Skip to content

Commit

Permalink
Fix str-slice(). (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 authored Dec 19, 2016
1 parent ade384b commit 41772a1
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
* Fix conversions between numbers with `dpi`, `dpcm`, and `dppx` units.
Previously these conversions were inverted.

* Don't crash when calling `str-slice()` with an `$end-at` index lower than the
`$start-at` index.

* `str-slice()` now correctly returns `""` when `$end-at` is negative and points
before the beginning of the string.

## 1.0.0-alpha.5

* Fix bounds-checking for `opacify()`, `fade-in()`, `transparentize()`, and
Expand Down
20 changes: 17 additions & 3 deletions lib/src/functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ void defineCoreFunctions(Environment environment) {

var codeUnitIndex = codepointIndexToCodeUnitIndex(string.text,
_codepointForIndex(index.assertInt("index"), string.text.runes.length));

return new SassString(
string.text.replaceRange(codeUnitIndex, codeUnitIndex, insert.text),
quotes: string.hasQuotes);
Expand Down Expand Up @@ -514,7 +515,13 @@ void defineCoreFunctions(Environment environment) {
var lengthInCodepoints = string.text.runes.length;
var startCodepoint =
_codepointForIndex(start.assertInt(), lengthInCodepoints);
var endCodepoint = _codepointForIndex(end.assertInt(), lengthInCodepoints);
var endCodepoint = _codepointForIndex(end.assertInt(), lengthInCodepoints,
allowNegative: true);
if (endCodepoint == lengthInCodepoints) endCodepoint -= 1;
if (endCodepoint < startCodepoint) {
return new SassString.empty(quotes: string.hasQuotes);
}

return new SassString(
string.text.substring(
codepointIndexToCodeUnitIndex(string.text, startCodepoint),
Expand Down Expand Up @@ -1018,10 +1025,17 @@ SassColor _transparentize(List<Value> arguments) {
/// A Sass string index is one-based, and uses negative numbers to count
/// backwards from the end of the string. A codepoint index is an index into
/// [String.runes].
int _codepointForIndex(int index, int lengthInCodepoints) {
///
/// If [index] is negative and it points before the beginning of
/// [lengthInCodepoints], this will return `0` if [allowNegative] is `false` and
/// the index if it's `true`.
int _codepointForIndex(int index, int lengthInCodepoints,
{bool allowNegative: false}) {
if (index == 0) return 0;
if (index > 0) return math.min(index - 1, lengthInCodepoints);
return math.max(lengthInCodepoints + index, 0);
var result = lengthInCodepoints + index;
if (result < 0 && !allowNegative) return 0;
return result;
}

/// Returns a [BuiltInCallable] named [name] that transforms a number's value
Expand Down
9 changes: 9 additions & 0 deletions lib/src/value/string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import '../util/character.dart';
import '../visitor/interface/value.dart';
import '../value.dart';

/// A quoted empty string, returned by [SassString.empty].
final _emptyQuoted = new SassString("", quotes: true);

/// An unquoted empty string, returned by [SassString.empty].
final _emptyUnquoted = new SassString("", quotes: true);

/// A SassScript string.
///
/// Strings can either be quoted or unquoted. Unquoted strings are usually CSS
Expand Down Expand Up @@ -51,6 +57,9 @@ class SassString extends Value {

bool get isBlank => !hasQuotes && text.isEmpty;

factory SassString.empty({bool quotes: false}) =>
quotes ? _emptyQuoted : _emptyUnquoted;

SassString(this.text, {bool quotes: false}) : hasQuotes = quotes;

/*=T*/ accept/*<T>*/(ValueVisitor/*<T>*/ visitor) =>
Expand Down

0 comments on commit 41772a1

Please sign in to comment.