Skip to content

Commit

Permalink
Deprecate /-as-division and add replacements
Browse files Browse the repository at this point in the history
Partially addresses #663
  • Loading branch information
nex3 committed Jun 12, 2019
1 parent 4d374c4 commit 1ec90e8
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 89 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,12 @@
## 1.21.0

* Deprecate the use of `/` for division. The new `divide()` function should be
used instead. See [this page][] for details.

[this page]: https://sass-lang.com/documentation/breaking-changes/slash-div

* Add a `slash-list()` function that returns a slash-separated list.

* Add a top-level `warn()` function for custom functions and importers to print
warning messages.

Expand Down
73 changes: 62 additions & 11 deletions lib/src/functions.dart
Expand Up @@ -15,6 +15,7 @@ import 'util/character.dart';
import 'util/number.dart';
import 'utils.dart';
import 'value.dart';
import 'warn.dart';

/// A regular expression matching the beginning of a proprietary Microsoft
/// filter declaration.
Expand Down Expand Up @@ -577,6 +578,18 @@ final List<BuiltInCallable> coreFunctions = UnmodifiableListView([
return SassNumber(_random.nextInt(limit) + 1);
}),

BuiltInCallable("divide", r"$numerator, $denominator", (arguments) {
var numerator = arguments[0];
var denominator = arguments[1];

if (numerator is! SassNumber || denominator is! SassNumber) {
warn("divide() will only support number arguments in a future release.\n"
"Use slash-list() instead for a slash separator.");
}

return numerator.dividedBy(denominator);
}),

// ## Lists

BuiltInCallable("length", r"$list",
Expand Down Expand Up @@ -617,9 +630,11 @@ final List<BuiltInCallable> coreFunctions = UnmodifiableListView([
separator = ListSeparator.space;
} else if (separatorParam.text == "comma") {
separator = ListSeparator.comma;
} else if (separatorParam.text == "slash") {
separator = ListSeparator.slash;
} else {
throw SassScriptException(
'\$$separator: Must be "space", "comma", or "auto".');
'\$$separator: Must be "space", "comma", "slash", or "auto".');
}

var bracketed =
Expand All @@ -645,9 +660,11 @@ final List<BuiltInCallable> coreFunctions = UnmodifiableListView([
separator = ListSeparator.space;
} else if (separatorParam.text == "comma") {
separator = ListSeparator.comma;
} else if (separatorParam.text == "slash") {
separator = ListSeparator.slash;
} else {
throw SassScriptException(
'\$$separator: Must be "space", "comma", or "auto".');
'\$$separator: Must be "space", "comma", "slash", or "auto".');
}

var newList = [...list.asList, value];
Expand All @@ -673,16 +690,29 @@ final List<BuiltInCallable> coreFunctions = UnmodifiableListView([
return index == -1 ? sassNull : SassNumber(index + 1);
}),

BuiltInCallable(
"list-separator",
r"$list",
(arguments) => arguments[0].separator == ListSeparator.comma
? SassString("comma", quotes: false)
: SassString("space", quotes: false)),
BuiltInCallable("list-separator", r"$list", (arguments) {
switch (arguments[0].separator) {
case ListSeparator.comma:
return SassString("comma", quotes: false);
case ListSeparator.slash:
return SassString("slash", quotes: false);
default:
return SassString("space", quotes: false);
}
}),

BuiltInCallable("is-bracketed", r"$list",
(arguments) => SassBoolean(arguments[0].hasBrackets)),

BuiltInCallable("slash-list", r"$elements...", (arguments) {
var list = arguments[0].asList;
if (list.length < 2) {
throw SassScriptException("At least two elements are required.");
}

return SassList(list, ListSeparator.slash);
}),

// ## Maps

BuiltInCallable("map-get", r"$map, $key", (arguments) {
Expand Down Expand Up @@ -968,6 +998,25 @@ Value _hsl(String name, List<Value> arguments) {
String name, List<String> argumentNames, Value channels) {
if (channels.isVar) return _functionString(name, [channels]);

var originalChannels = channels;
Value alphaFromSlashList;
if (channels.separator == ListSeparator.slash) {
var list = channels.asList;
if (list.length != 2) {
throw SassScriptException(
"Only 2 slash-separated elements allowed, but ${list.length} "
"${pluralize('was', list.length, plural: 'were')} passed.");
}

channels = list[0];

alphaFromSlashList = list[1];
if (!alphaFromSlashList.isSpecialNumber) {
alphaFromSlashList.assertNumber("alpha");
}
if (list[0].isVar) return _functionString(name, [originalChannels]);
}

var isCommaSeparated = channels.separator == ListSeparator.comma;
var isBracketed = channels.hasBrackets;
if (isCommaSeparated || isBracketed) {
Expand All @@ -983,18 +1032,20 @@ Value _hsl(String name, List<Value> arguments) {

var list = channels.asList;
if (list.length > 3) {
throw SassScriptException(
"Only 3 elements allowed, but ${list.length} were passed.");
throw SassScriptException("Only 3 elements allowed, but ${list.length} "
"${pluralize('was', list.length, plural: 'were')} passed.");
} else if (list.length < 3) {
if (list.any((value) => value.isVar) ||
(list.isNotEmpty && _isVarSlash(list.last))) {
return _functionString(name, [channels]);
return _functionString(name, [originalChannels]);
} else {
var argument = argumentNames[list.length];
throw SassScriptException("Missing element $argument.");
}
}

if (alphaFromSlashList != null) return [...list, alphaFromSlashList];

var maybeSlashSeparated = list[2];
if (maybeSlashSeparated is SassNumber &&
maybeSlashSeparated.asSlash != null) {
Expand Down
43 changes: 24 additions & 19 deletions lib/src/value.dart
Expand Up @@ -188,27 +188,32 @@ abstract class Value implements ext.Value {
if (list.asList.isEmpty) return null;

var result = <String>[];
if (list.separator == ListSeparator.comma) {
for (var complex in list.asList) {
if (complex is SassString) {
result.add(complex.text);
} else if (complex is SassList &&
complex.separator == ListSeparator.space) {
var string = complex._selectorString();
if (string == null) return null;
result.add(string);
} else {
return null;
switch (list.separator) {
case ListSeparator.comma:
for (var complex in list.asList) {
if (complex is SassString) {
result.add(complex.text);
} else if (complex is SassList &&
complex.separator == ListSeparator.space) {
var string = complex._selectorString();
if (string == null) return null;
result.add(string);
} else {
return null;
}
}
}
} else {
for (var compound in list.asList) {
if (compound is SassString) {
result.add(compound.text);
} else {
return null;
break;
case ListSeparator.slash:
return null;
default:
for (var compound in list.asList) {
if (compound is SassString) {
result.add(compound.text);
} else {
return null;
}
}
}
break;
}
return result.join(list.separator == ListSeparator.comma ? ', ' : ' ');
}
Expand Down
3 changes: 3 additions & 0 deletions lib/src/value/list.dart
Expand Up @@ -65,6 +65,9 @@ class ListSeparator {
/// A comma-separated list.
static const comma = ListSeparator._("comma", ",");

/// A slash-separated list.
static const slash = ListSeparator._("slash", "/");

/// A separator that hasn't yet been determined.
///
/// Singleton lists and empty lists don't have separators defiend. This means
Expand Down

0 comments on commit 1ec90e8

Please sign in to comment.