Skip to content

Commit 0f5b99e

Browse files
committed
Update new color space code to Dart 3 style
1 parent f9280e4 commit 0f5b99e

17 files changed

+388
-590
lines changed

Diff for: lib/src/functions/color.dart

+115-129
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '../deprecation.dart';
1111
import '../evaluation_context.dart';
1212
import '../exception.dart';
1313
import '../module/built_in.dart';
14+
import '../util/map.dart';
1415
import '../util/nullable.dart';
1516
import '../util/number.dart';
1617
import '../utils.dart';
@@ -589,40 +590,30 @@ Value _invert(List<Value> arguments, {bool global = false}) {
589590
if (fuzzyEquals(weight, 0)) return color;
590591

591592
var inSpace = color.toSpace(space);
592-
SassColor inverted;
593-
switch (space) {
594-
case ColorSpace.hwb:
595-
inverted = SassColor.hwb((inSpace.channel0 + 180) % 360, inSpace.channel2,
596-
inSpace.channel1, inSpace.alpha);
597-
break;
598-
599-
case ColorSpace.hsl:
600-
inverted = SassColor.hsl((inSpace.channel0 + 180) % 360, inSpace.channel1,
601-
100 - inSpace.channel2, inSpace.alpha);
602-
break;
603-
604-
case ColorSpace.lch:
605-
inverted = SassColor.lch(100 - inSpace.channel0, inSpace.channel1,
606-
(inSpace.channel2 + 180) % 360, inSpace.alpha);
607-
break;
608-
609-
case ColorSpace.oklch:
610-
inverted = SassColor.oklch(1 - inSpace.channel0, inSpace.channel1,
611-
(inSpace.channel2 + 180) % 360, inSpace.alpha);
612-
break;
613-
614-
default:
615-
var channel0 = space.channels[0] as LinearChannel;
616-
var channel1 = space.channels[1] as LinearChannel;
617-
var channel2 = space.channels[2] as LinearChannel;
618-
inverted = SassColor.forSpaceInternal(
593+
var inverted = switch (space) {
594+
ColorSpace.hwb => SassColor.hwb((inSpace.channel0 + 180) % 360,
595+
inSpace.channel2, inSpace.channel1, inSpace.alpha),
596+
ColorSpace.hsl => SassColor.hsl((inSpace.channel0 + 180) % 360,
597+
inSpace.channel1, 100 - inSpace.channel2, inSpace.alpha),
598+
ColorSpace.lch => SassColor.lch(100 - inSpace.channel0, inSpace.channel1,
599+
(inSpace.channel2 + 180) % 360, inSpace.alpha),
600+
ColorSpace.oklch => SassColor.oklch(1 - inSpace.channel0, inSpace.channel1,
601+
(inSpace.channel2 + 180) % 360, inSpace.alpha),
602+
ColorSpace(
603+
channels: [
604+
LinearChannel channel0,
605+
LinearChannel channel1,
606+
LinearChannel channel2
607+
]
608+
) =>
609+
SassColor.forSpaceInternal(
619610
space,
620611
_invertChannel(channel0, inSpace.channel0),
621612
_invertChannel(channel1, inSpace.channel1),
622613
_invertChannel(channel2, inSpace.channel2),
623-
inSpace.alpha);
624-
break;
625-
}
614+
inSpace.alpha),
615+
_ => throw UnsupportedError("Unknown color space $space.")
616+
};
626617

627618
if (fuzzyEquals(weight, 1)) return inverted;
628619
return color.interpolate(inverted, InterpolationMethod(space),
@@ -704,15 +695,15 @@ SassColor _updateComponents(List<Value> arguments,
704695
var oldChannels = color.channels;
705696
var channelArgs = List<SassNumber?>.filled(oldChannels.length, null);
706697
var channelInfo = color.space.channels;
707-
for (var entry in keywords.entries) {
708-
var channelIndex = channelInfo.indexWhere((info) => entry.key == info.name);
698+
for (var (name, value) in keywords.pairs) {
699+
var channelIndex = channelInfo.indexWhere((info) => name == info.name);
709700
if (channelIndex == -1) {
710701
throw SassScriptException(
711702
"Color space ${color.space} doesn't have a channel with this name.",
712-
entry.key);
703+
name);
713704
}
714705

715-
channelArgs[channelIndex] = entry.value.assertNumber(entry.key);
706+
channelArgs[channelIndex] = value.assertNumber(name);
716707
}
717708

718709
var result = change
@@ -765,17 +756,15 @@ double _scaleChannel(
765756
var factor = (factorArg..assertUnit('%', channel.name))
766757
.valueInRangeWithUnit(-100, 100, channel.name, '%') /
767758
100;
768-
if (factor == 0) {
769-
return oldValue;
770-
} else if (factor > 0) {
771-
return oldValue >= channel.max
759+
return switch (factor) {
760+
0 => oldValue,
761+
> 0 => oldValue >= channel.max
772762
? oldValue
773-
: oldValue + (channel.max - oldValue) * factor;
774-
} else {
775-
return oldValue <= channel.min
763+
: oldValue + (channel.max - oldValue) * factor,
764+
_ => oldValue <= channel.min
776765
? oldValue
777-
: oldValue + (oldValue - channel.min) * factor;
778-
}
766+
: oldValue + (oldValue - channel.min) * factor
767+
};
779768
}
780769

781770
/// Returns a copy of [color] with its channel values adjusted by the values in
@@ -804,32 +793,34 @@ double _adjustChannel(ColorSpace space, ColorChannel channel, double oldValue,
804793
SassNumber? adjustmentArg) {
805794
if (adjustmentArg == null) return oldValue;
806795

807-
if ((space == ColorSpace.hsl || space == ColorSpace.hwb) &&
808-
channel is! LinearChannel) {
809-
// `_channelFromValue` expects all hue values to be compatible with `deg`,
810-
// but we're still in the deprecation period where we allow non-`deg` values
811-
// for HSL and HWB so we have to handle that ahead-of-time.
812-
adjustmentArg = SassNumber(_angleValue(adjustmentArg, 'hue'));
813-
} else if (space == ColorSpace.hsl && channel is LinearChannel) {
814-
// `_channelFromValue` expects lightness/saturation to be `%`, but we're
815-
// still in the deprecation period where we allow non-`%` values so we have
816-
// to handle that ahead-of-time.
817-
_checkPercent(adjustmentArg, channel.name);
818-
adjustmentArg = SassNumber(adjustmentArg.value, '%');
819-
} else if (channel == ColorChannel.alpha && adjustmentArg.hasUnits) {
820-
// `_channelFromValue` expects alpha to be unitless or `%`, but we're still
821-
// in the deprecation period where we allow other values (and interpret `%`
822-
// as unitless) so we have to handle that ahead-of-time.
823-
warnForDeprecation(
824-
"\$alpha: Passing a number with unit ${adjustmentArg.unitString} is "
825-
"deprecated.\n"
826-
"\n"
827-
"To preserve current behavior: "
828-
"${adjustmentArg.unitSuggestion('alpha')}\n"
829-
"\n"
830-
"More info: https://sass-lang.com/d/function-units",
831-
Deprecation.functionUnits);
832-
adjustmentArg = SassNumber(adjustmentArg.value);
796+
switch ((space, channel)) {
797+
case (ColorSpace.hsl || ColorSpace.hwb, _) when channel is! LinearChannel:
798+
// `_channelFromValue` expects all hue values to be compatible with `deg`,
799+
// but we're still in the deprecation period where we allow non-`deg`
800+
// values for HSL and HWB so we have to handle that ahead-of-time.
801+
adjustmentArg = SassNumber(_angleValue(adjustmentArg, 'hue'));
802+
803+
case (ColorSpace.hsl, LinearChannel()):
804+
// `_channelFromValue` expects lightness/saturation to be `%`, but we're
805+
// still in the deprecation period where we allow non-`%` values so we
806+
// have to handle that ahead-of-time.
807+
_checkPercent(adjustmentArg, channel.name);
808+
adjustmentArg = SassNumber(adjustmentArg.value, '%');
809+
810+
case (_, ColorChannel.alpha) when adjustmentArg.hasUnits:
811+
// `_channelFromValue` expects alpha to be unitless or `%`, but we're
812+
// still in the deprecation period where we allow other values (and
813+
// interpret `%` as unitless) so we have to handle that ahead-of-time.
814+
warnForDeprecation(
815+
"\$alpha: Passing a number with unit ${adjustmentArg.unitString} is "
816+
"deprecated.\n"
817+
"\n"
818+
"To preserve current behavior: "
819+
"${adjustmentArg.unitSuggestion('alpha')}\n"
820+
"\n"
821+
"More info: https://sass-lang.com/d/function-units",
822+
Deprecation.functionUnits);
823+
adjustmentArg = SassNumber(adjustmentArg.value);
833824
}
834825

835826
var result = oldValue + _channelFromValue(channel, adjustmentArg)!;
@@ -846,17 +837,13 @@ double _adjustChannel(ColorSpace space, ColorChannel channel, double oldValue,
846837
ColorSpace? _sniffLegacyColorSpace(Map<String, Value> keywords) {
847838
for (var key in keywords.keys) {
848839
switch (key) {
849-
case "red":
850-
case "green":
851-
case "blue":
840+
case "red" || "green" || "blue":
852841
return ColorSpace.rgb;
853842

854-
case "saturation":
855-
case "lightness":
843+
case "saturation" || "lightness":
856844
return ColorSpace.hsl;
857845

858-
case "whiteness":
859-
case "blackness":
846+
case "whiteness" || "blackness":
860847
return ColorSpace.hwb;
861848
}
862849
}
@@ -1138,24 +1125,20 @@ ColorSpace _spaceOrDefault(SassColor color, Value space, [String? name]) =>
11381125
Value _parseChannels(String functionName, Value input,
11391126
{ColorSpace? space, String? name}) {
11401127
if (input.isVar) return _functionString(functionName, [input]);
1141-
var inputList = input.assertCommonListStyle(name, allowSlash: true);
11421128

11431129
Value components;
11441130
Value? alphaValue;
1145-
switch (inputList) {
1131+
switch (input.assertCommonListStyle(name, allowSlash: true)) {
11461132
case [var components_, var alphaValue_]
11471133
when input.separator == ListSeparator.slash:
11481134
components = components_;
11491135
alphaValue = alphaValue_;
11501136

1151-
case _ when input.separator == ListSeparator.slash:
1137+
case var inputList when input.separator == ListSeparator.slash:
11521138
throw SassScriptException(
11531139
"Only 2 slash-separated elements allowed, but ${inputList.length} "
11541140
"${pluralize('was', inputList.length, plural: 'were')} passed.");
11551141

1156-
case []:
1157-
components = input;
1158-
11591142
case [..., SassString(hasQuotes: false, :var text)] when text.contains('/'):
11601143
return _functionString(functionName, [input]);
11611144

@@ -1169,46 +1152,51 @@ Value _parseChannels(String functionName, Value input,
11691152

11701153
List<Value> channels;
11711154
SassString? spaceName;
1172-
var componentList = components.assertCommonListStyle(name, allowSlash: false);
1173-
if (componentList.isEmpty) {
1174-
throw SassScriptException('Color component list may not be empty.', name);
1175-
} else if (components.isVar) {
1176-
channels = [components];
1177-
} else {
1178-
if (space == null) {
1179-
spaceName = componentList.first.assertString(name)..assertUnquoted(name);
1180-
space =
1181-
spaceName.isVar ? null : ColorSpace.fromName(spaceName.text, name);
1182-
channels = [...componentList.skip(1)];
1183-
1184-
if (const {
1185-
ColorSpace.rgb,
1186-
ColorSpace.hsl,
1187-
ColorSpace.hwb,
1188-
ColorSpace.lab,
1189-
ColorSpace.lch,
1190-
ColorSpace.oklab,
1191-
ColorSpace.oklch
1192-
}.contains(space)) {
1193-
throw SassScriptException(
1194-
"The color() function doesn't support the color space $space. Use "
1195-
"the $space() function instead.",
1196-
name);
1155+
switch (components.assertCommonListStyle(name, allowSlash: false)) {
1156+
case []:
1157+
throw SassScriptException('Color component list may not be empty.', name);
1158+
1159+
case _ when components.isVar:
1160+
channels = [components];
1161+
1162+
case [var first, ...var rest] && var componentList:
1163+
if (space == null) {
1164+
spaceName = first.assertString(name)..assertUnquoted(name);
1165+
space =
1166+
spaceName.isVar ? null : ColorSpace.fromName(spaceName.text, name);
1167+
channels = rest;
1168+
1169+
if (space
1170+
case ColorSpace.rgb ||
1171+
ColorSpace.hsl ||
1172+
ColorSpace.hwb ||
1173+
ColorSpace.lab ||
1174+
ColorSpace.lch ||
1175+
ColorSpace.oklab ||
1176+
ColorSpace.oklch) {
1177+
throw SassScriptException(
1178+
"The color() function doesn't support the color space $space. Use "
1179+
"the $space() function instead.",
1180+
name);
1181+
}
1182+
} else {
1183+
channels = componentList;
11971184
}
1198-
} else {
1199-
channels = componentList;
1200-
}
12011185

1202-
for (var channel in channels) {
1203-
if (!channel.isSpecialNumber &&
1204-
channel is! SassNumber &&
1205-
!_isNone(channel)) {
1206-
var channelName =
1207-
space?.channels[channels.indexOf(channel)].name ?? 'channel';
1208-
throw SassScriptException(
1209-
'Expected $channelName $channel to be a number.', name);
1186+
for (var channel in channels) {
1187+
if (!channel.isSpecialNumber &&
1188+
channel is! SassNumber &&
1189+
!_isNone(channel)) {
1190+
var channelName =
1191+
space?.channels[channels.indexOf(channel)].name ?? 'channel';
1192+
throw SassScriptException(
1193+
'Expected $channelName $channel to be a number.', name);
1194+
}
12101195
}
1211-
}
1196+
1197+
// dart-lang/sdk#51926
1198+
case _:
1199+
throw "unreachable";
12121200
}
12131201

12141202
if (alphaValue?.isSpecialNumber ?? false) {
@@ -1319,16 +1307,14 @@ SassColor _colorFromChannels(ColorSpace space, SassNumber? channel0,
13191307
/// Converts a channel value from a [SassNumber] into a [double] according to
13201308
/// [channel].
13211309
double? _channelFromValue(ColorChannel channel, SassNumber? value) =>
1322-
value.andThen((value) {
1323-
if (channel is! LinearChannel) {
1324-
return value.coerceValueToUnit('deg', channel.name);
1325-
} else if (channel.requiresPercent && !value.hasUnit('%')) {
1326-
throw SassScriptException(
1327-
'Expected $value to have unit "%".', channel.name);
1328-
} else {
1329-
return _percentageOrUnitless(value, channel.max, channel.name);
1330-
}
1331-
});
1310+
value.andThen((value) => switch (channel) {
1311+
LinearChannel(requiresPercent: true) when !value.hasUnit('%') =>
1312+
throw SassScriptException(
1313+
'Expected $value to have unit "%".', channel.name),
1314+
LinearChannel() =>
1315+
_percentageOrUnitless(value, channel.max, channel.name),
1316+
_ => value.coerceValueToUnit('deg', channel.name)
1317+
});
13321318

13331319
/// Returns whether [value] is an unquoted string case-insensitively equal to
13341320
/// "none".

Diff for: lib/src/js/value/color.dart

+4-8
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,11 @@ final JSClass colorClass = () {
3939
} else if (options.red != null ||
4040
options.green != null ||
4141
options.blue != null) {
42-
var red = options.red;
43-
var green = options.green;
44-
var blue = options.blue;
45-
var alpha = options.alpha;
4642
return self.changeChannels({
47-
if (red != null) "red": red,
48-
if (green != null) "green": green,
49-
if (blue != null) "blue": blue,
50-
if (alpha != null) "alpha": alpha
43+
if (options.red case var red?) "red": red,
44+
if (options.green case var green?) "green": green,
45+
if (options.blue case var blue?) "blue": blue,
46+
if (options.alpha case var alpha?) "alpha": alpha
5147
});
5248
} else {
5349
return self.changeAlpha(options.alpha ?? self.alpha);

0 commit comments

Comments
 (0)