mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-22 05:41:14 +01:00
Merge pull request #750 from sass/function-fixes
Fix a bunch of small spec incompatibilities in built-in functions
This commit is contained in:
commit
525958951d
45
CHANGELOG.md
45
CHANGELOG.md
@ -1,3 +1,48 @@
|
||||
## 1.22.3
|
||||
|
||||
* **Potentially breaking bug fix:** The argument name for the `saturate()`
|
||||
function is now `$amount`, to match the name in LibSass and originally in Ruby
|
||||
Sass.
|
||||
|
||||
* **Potentially breaking bug fix:** The `invert()` function now properly returns
|
||||
`#808080` when passed `$weight: 50%`. This matches the behavior in LibSass and
|
||||
originally in Ruby Sass, as well as being consistent with other nearby values
|
||||
of `$weight`.
|
||||
|
||||
* **Potentially breaking bug fix:** The `invert()` function now throws an error
|
||||
if it's used [as a plain CSS function][plain-CSS invert] *and* the Sass-only
|
||||
`$weight` parameter is passed. This never did anything useful, so it's
|
||||
considered a bug fix rather than a full breaking change.
|
||||
|
||||
[plain-CSS invert]: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/invert
|
||||
|
||||
* **Potentially breaking bug fix**: The `str-insert()` function now properly
|
||||
inserts at the end of the string if the `$index` is `-1`. This matches the
|
||||
behavior in LibSass and originally in Ruby Sass.
|
||||
|
||||
* **Potentially breaking bug fix**: An empty map returned by `map-remove()` is
|
||||
now treated as identical to the literal value `()`, rather than being treated
|
||||
as though it had a comma separator. This matches the original behavior in Ruby
|
||||
Sass.
|
||||
|
||||
* The `adjust-color()` function no longer throws an error when a large `$alpha`
|
||||
value is combined with HSL adjustments.
|
||||
|
||||
* The `alpha()` function now produces clearer error messages when the wrong
|
||||
number of arguments are passed.
|
||||
|
||||
* Fix a bug where the `str-slice()` function could produce invalid output when
|
||||
passed a string that contains characters that aren't represented as a single
|
||||
byte in UTF-16.
|
||||
|
||||
* Improve the error message for an unknown separator name passed to the `join()`
|
||||
or `append()` functions.
|
||||
|
||||
* The `zip()` function no longer deadlocks if passed no arguments.
|
||||
|
||||
* The `map-remove()` function can now take a `$key` named argument. This matches
|
||||
the signature in LibSass and originally in Ruby Sass.
|
||||
|
||||
## 1.22.2
|
||||
|
||||
### JavaScript API
|
||||
|
@ -47,16 +47,20 @@ final global = UnmodifiableListView([
|
||||
}
|
||||
}),
|
||||
|
||||
BuiltInCallable("invert", r"$color, $weight: 50%", (arguments) {
|
||||
BuiltInCallable("invert", r"$color, $weight: 100%", (arguments) {
|
||||
var weight = arguments[1].assertNumber("weight");
|
||||
if (arguments[0] is SassNumber) {
|
||||
if (weight.value != 100 || !weight.hasUnit("%")) {
|
||||
throw "Only one argument may be passed to the plain-CSS invert() "
|
||||
"function.";
|
||||
}
|
||||
|
||||
return _functionString("invert", arguments.take(1));
|
||||
}
|
||||
|
||||
var color = arguments[0].assertColor("color");
|
||||
var weight = arguments[1].assertNumber("weight");
|
||||
var inverse = color.changeRgb(
|
||||
red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue);
|
||||
if (weight.value == 50) return inverse;
|
||||
|
||||
return _mixColors(inverse, color, weight);
|
||||
}),
|
||||
@ -130,8 +134,8 @@ final global = UnmodifiableListView([
|
||||
}),
|
||||
|
||||
BuiltInCallable.overloaded("saturate", {
|
||||
r"$number": (arguments) {
|
||||
var number = arguments[0].assertNumber("number");
|
||||
r"$amount": (arguments) {
|
||||
var number = arguments[0].assertNumber("amount");
|
||||
return SassString("saturate(${number.toCssString()})", quotes: false);
|
||||
},
|
||||
r"$color, $amount": (arguments) {
|
||||
@ -171,17 +175,23 @@ final global = UnmodifiableListView([
|
||||
return SassNumber(color.alpha);
|
||||
},
|
||||
r"$args...": (arguments) {
|
||||
if (arguments[0].asList.every((argument) =>
|
||||
argument is SassString &&
|
||||
!argument.hasQuotes &&
|
||||
argument.text.contains(_microsoftFilterStart))) {
|
||||
var argList = arguments[0].asList;
|
||||
if (argList.isNotEmpty &&
|
||||
argList.every((argument) =>
|
||||
argument is SassString &&
|
||||
!argument.hasQuotes &&
|
||||
argument.text.contains(_microsoftFilterStart))) {
|
||||
// Suport the proprietary Microsoft alpha() function.
|
||||
return _functionString("alpha", arguments);
|
||||
}
|
||||
|
||||
assert(arguments.length != 1);
|
||||
throw SassScriptException(
|
||||
"Only 1 argument allowed, but ${arguments.length} were passed.");
|
||||
assert(argList.length != 1);
|
||||
if (argList.isEmpty) {
|
||||
throw SassScriptException("Missing argument \$color.");
|
||||
} else {
|
||||
throw SassScriptException(
|
||||
"Only 1 argument allowed, but ${argList.length} were passed.");
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
@ -206,8 +216,14 @@ final module = BuiltInModule("color", [
|
||||
// ### RGB
|
||||
_red, _green, _blue, _mix,
|
||||
|
||||
BuiltInCallable("invert", r"$color, $weight: 50%", (arguments) {
|
||||
BuiltInCallable("invert", r"$color, $weight: 100%", (arguments) {
|
||||
var weight = arguments[1].assertNumber("weight");
|
||||
if (arguments[0] is SassNumber) {
|
||||
if (weight.value != 100 || !weight.hasUnit("%")) {
|
||||
throw "Only one argument may be passed to the plain-CSS invert() "
|
||||
"function.";
|
||||
}
|
||||
|
||||
var result = _functionString("invert", arguments.take(1));
|
||||
warn("Passing a number to color.invert() is deprecated.\n"
|
||||
"\n"
|
||||
@ -216,10 +232,8 @@ final module = BuiltInModule("color", [
|
||||
}
|
||||
|
||||
var color = arguments[0].assertColor("color");
|
||||
var weight = arguments[1].assertNumber("weight");
|
||||
var inverse = color.changeRgb(
|
||||
red: 255 - color.red, green: 255 - color.green, blue: 255 - color.blue);
|
||||
if (weight.value == 50) return inverse;
|
||||
|
||||
return _mixColors(inverse, color, weight);
|
||||
}),
|
||||
@ -400,7 +414,7 @@ final _adjust = BuiltInCallable("adjust", r"$color, $kwargs...", (arguments) {
|
||||
hue: color.hue + (hue ?? 0),
|
||||
saturation: (color.saturation + (saturation ?? 0)).clamp(0, 100),
|
||||
lightness: (color.lightness + (lightness ?? 0)).clamp(0, 100),
|
||||
alpha: color.alpha + (alpha ?? 0));
|
||||
alpha: (color.alpha + (alpha ?? 0)).clamp(0, 1));
|
||||
} else if (alpha != null) {
|
||||
return color.changeAlpha((color.alpha + (alpha ?? 0)).clamp(0, 1));
|
||||
} else {
|
||||
|
@ -63,7 +63,7 @@ final _join = BuiltInCallable(
|
||||
separator = ListSeparator.comma;
|
||||
} else {
|
||||
throw SassScriptException(
|
||||
'\$$separator: Must be "space", "comma", or "auto".');
|
||||
'\$separator: Must be "space", "comma", or "auto".');
|
||||
}
|
||||
|
||||
var bracketed = bracketedParam is SassString && bracketedParam.text == 'auto'
|
||||
@ -91,7 +91,7 @@ final _append =
|
||||
separator = ListSeparator.comma;
|
||||
} else {
|
||||
throw SassScriptException(
|
||||
'\$$separator: Must be "space", "comma", or "auto".');
|
||||
'\$separator: Must be "space", "comma", or "auto".');
|
||||
}
|
||||
|
||||
var newList = [...list.asList, value];
|
||||
@ -100,6 +100,10 @@ final _append =
|
||||
|
||||
final _zip = BuiltInCallable("zip", r"$lists...", (arguments) {
|
||||
var lists = arguments[0].asList.map((list) => list.asList).toList();
|
||||
if (lists.isEmpty) {
|
||||
return const SassList.empty(separator: ListSeparator.comma);
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var results = <SassList>[];
|
||||
while (lists.every((list) => i != list.length)) {
|
||||
|
@ -36,14 +36,23 @@ final _merge = BuiltInCallable("merge", r"$map1, $map2", (arguments) {
|
||||
return SassMap({...map1.contents, ...map2.contents});
|
||||
});
|
||||
|
||||
final _remove = BuiltInCallable("remove", r"$map, $keys...", (arguments) {
|
||||
var map = arguments[0].assertMap("map");
|
||||
var keys = arguments[1];
|
||||
var mutableMap = Map.of(map.contents);
|
||||
for (var key in keys.asList) {
|
||||
mutableMap.remove(key);
|
||||
final _remove = BuiltInCallable.overloaded("remove", {
|
||||
// Because the signature below has an explicit `$key` argument, it doesn't
|
||||
// allow zero keys to be passed. We want to allow that case, so we add an
|
||||
// explicit overload for it.
|
||||
r"$map": (arguments) => arguments[0].assertMap("map"),
|
||||
|
||||
// The first argument has special handling so that the $key parameter can be
|
||||
// passed by name.
|
||||
r"$map, $key, $keys...": (arguments) {
|
||||
var map = arguments[0].assertMap("map");
|
||||
var keys = [arguments[1], ...arguments[2].asList];
|
||||
var mutableMap = Map.of(map.contents);
|
||||
for (var key in keys) {
|
||||
mutableMap.remove(key);
|
||||
}
|
||||
return SassMap(mutableMap);
|
||||
}
|
||||
return SassMap(mutableMap);
|
||||
});
|
||||
|
||||
final _keys = BuiltInCallable(
|
||||
|
@ -64,10 +64,13 @@ final _insert =
|
||||
// the `$insert` string is at `$index` in the result, which means that we
|
||||
// want to insert before `$index` if it's positive and after if it's
|
||||
// negative.
|
||||
if (indexInt < 0) indexInt++;
|
||||
if (indexInt < 0) {
|
||||
// +1 because negative indexes start counting from -1 rather than 0, and
|
||||
// another +1 because we want to insert *after* that index.
|
||||
indexInt = string.sassLength + indexInt + 2;
|
||||
}
|
||||
|
||||
var codepointIndex = _codepointForIndex(indexInt, string.sassLength);
|
||||
|
||||
var codeUnitIndex =
|
||||
codepointIndexToCodeUnitIndex(string.text, codepointIndex);
|
||||
return SassString(
|
||||
@ -113,7 +116,7 @@ final _slice =
|
||||
return SassString(
|
||||
string.text.substring(
|
||||
codepointIndexToCodeUnitIndex(string.text, startCodepoint),
|
||||
codepointIndexToCodeUnitIndex(string.text, endCodepoint) + 1),
|
||||
codepointIndexToCodeUnitIndex(string.text, endCodepoint + 1)),
|
||||
quotes: string.hasQuotes);
|
||||
});
|
||||
|
||||
|
@ -10,7 +10,8 @@ import 'external/value.dart' as ext;
|
||||
class SassMap extends Value implements ext.SassMap {
|
||||
final Map<Value, Value> contents;
|
||||
|
||||
ListSeparator get separator => ListSeparator.comma;
|
||||
ListSeparator get separator =>
|
||||
contents.isEmpty ? ListSeparator.undecided : ListSeparator.comma;
|
||||
|
||||
List<Value> get asList {
|
||||
var result = <Value>[];
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: sass
|
||||
version: 1.22.2
|
||||
version: 1.22.3
|
||||
description: A Sass implementation in Dart.
|
||||
author: Dart Team <misc@dartlang.org>
|
||||
homepage: https://github.com/sass/dart-sass
|
||||
|
@ -15,7 +15,7 @@ main() {
|
||||
SassMap value;
|
||||
setUp(() => value = parseValue("(a: b, c: d)") as SassMap);
|
||||
|
||||
test("is comma-separated", () {
|
||||
test("has an undecided separator", () {
|
||||
expect(value.separator, equals(ListSeparator.comma));
|
||||
});
|
||||
|
||||
@ -143,8 +143,8 @@ main() {
|
||||
SassMap value;
|
||||
setUp(() => value = parseValue("map-remove((a: b), a)") as SassMap);
|
||||
|
||||
test("is comma-separated", () {
|
||||
expect(value.separator, equals(ListSeparator.comma));
|
||||
test("has an undecided separator", () {
|
||||
expect(value.separator, equals(ListSeparator.undecided));
|
||||
});
|
||||
|
||||
test("returns its contents as a map", () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user