mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-22 13:51:31 +01:00
Properly handle escaped @else
(#1014)
Fixes #1011. This also fixes a bug where `@else` was parsed case-insensitively (unlike all other Sass at-rules, which must be lowercase).
This commit is contained in:
parent
f233bccadf
commit
fba0ea37a1
@ -1,5 +1,7 @@
|
||||
## 1.26.6
|
||||
|
||||
* Fix a bug where escape sequences were improperly recognized in `@else` rules.
|
||||
|
||||
### JavaScript API
|
||||
|
||||
* Add `sass.NULL`, `sass.TRUE`, and `sass.FALSE` constants to match Node Sass's
|
||||
|
@ -517,24 +517,37 @@ class Parser {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Consumes the next character if it's equal to [letter], ignoring ASCII
|
||||
/// case.
|
||||
/// Consumes the next character or escape sequence if it matches [expected].
|
||||
///
|
||||
/// Matching will be case-insensitive unless [caseSensitive] is true.
|
||||
@protected
|
||||
bool scanCharIgnoreCase(int letter) {
|
||||
if (!equalsLetterIgnoreCase(letter, scanner.peekChar())) return false;
|
||||
bool scanIdentChar(int char, {bool caseSensitive = false}) {
|
||||
bool matches(int actual) => caseSensitive
|
||||
? actual == char
|
||||
: characterEqualsIgnoreCase(char, actual);
|
||||
|
||||
var next = scanner.peekChar();
|
||||
if (matches(next)) {
|
||||
scanner.readChar();
|
||||
return true;
|
||||
} else if (next == $backslash) {
|
||||
var start = scanner.state;
|
||||
if (matches(escapeCharacter())) return true;
|
||||
scanner.state = start;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Consumes the next character and asserts that it's equal to [letter],
|
||||
/// ignoring ASCII case.
|
||||
/// Consumes the next character or escape sequence and asserts it matches
|
||||
/// [char].
|
||||
///
|
||||
/// Matching will be case-insensitive unless [caseSensitive] is true.
|
||||
@protected
|
||||
void expectCharIgnoreCase(int letter) {
|
||||
var actual = scanner.readChar();
|
||||
if (equalsLetterIgnoreCase(letter, actual)) return;
|
||||
void expectIdentChar(int letter, {bool caseSensitive = false}) {
|
||||
if (scanIdentChar(letter, caseSensitive: caseSensitive)) return;
|
||||
|
||||
scanner.error('Expected "${String.fromCharCode(letter)}".',
|
||||
position: actual == null ? scanner.position : scanner.position - 1);
|
||||
position: scanner.position);
|
||||
}
|
||||
|
||||
// ## Utilities
|
||||
@ -599,13 +612,12 @@ class Parser {
|
||||
|
||||
/// Consumes an identifier if its name exactly matches [text].
|
||||
@protected
|
||||
bool scanIdentifier(String text) {
|
||||
bool scanIdentifier(String text, {bool caseSensitive = false}) {
|
||||
if (!lookingAtIdentifier()) return false;
|
||||
|
||||
var start = scanner.state;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
var next = text.codeUnitAt(i);
|
||||
if (scanCharIgnoreCase(next)) continue;
|
||||
for (var letter in text.codeUnits) {
|
||||
if (scanIdentChar(letter, caseSensitive: caseSensitive)) continue;
|
||||
scanner.state = start;
|
||||
return false;
|
||||
}
|
||||
@ -617,13 +629,13 @@ class Parser {
|
||||
|
||||
/// Consumes an identifier and asserts that its name exactly matches [text].
|
||||
@protected
|
||||
void expectIdentifier(String text, {String name}) {
|
||||
void expectIdentifier(String text,
|
||||
{String name, bool caseSensitive = false}) {
|
||||
name ??= '"$text"';
|
||||
|
||||
var start = scanner.position;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
var next = text.codeUnitAt(i);
|
||||
if (scanCharIgnoreCase(next)) continue;
|
||||
for (var letter in text.codeUnits) {
|
||||
if (scanIdentChar(letter, caseSensitive: caseSensitive)) continue;
|
||||
scanner.error("Expected $name.", position: start);
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ class ScssParser extends StylesheetParser {
|
||||
whitespace();
|
||||
var beforeAt = scanner.state;
|
||||
if (scanner.scanChar($at)) {
|
||||
if (scanIdentifier('else')) return true;
|
||||
if (scanIdentifier('elseif')) {
|
||||
if (scanIdentifier('else', caseSensitive: true)) return true;
|
||||
if (scanIdentifier('elseif', caseSensitive: true)) {
|
||||
logger.warn(
|
||||
'@elseif is deprecated and will not be supported in future Sass '
|
||||
'versions.\n'
|
||||
|
@ -363,9 +363,9 @@ class SelectorParser extends Parser {
|
||||
buffer.writeCharCode(scanner.readChar());
|
||||
}
|
||||
whitespace();
|
||||
if (!scanCharIgnoreCase($n)) return buffer.toString();
|
||||
if (!scanIdentChar($n)) return buffer.toString();
|
||||
} else {
|
||||
expectCharIgnoreCase($n);
|
||||
expectIdentChar($n);
|
||||
}
|
||||
buffer.writeCharCode($n);
|
||||
whitespace();
|
||||
|
@ -2437,7 +2437,7 @@ relase. For details, see http://bit.ly/moz-document.
|
||||
/// Consumes a unicode range expression.
|
||||
StringExpression _unicodeRange() {
|
||||
var start = scanner.state;
|
||||
expectCharIgnoreCase($u);
|
||||
expectIdentChar($u);
|
||||
scanner.expectChar($plus);
|
||||
|
||||
var i = 0;
|
||||
@ -2749,11 +2749,11 @@ relase. For details, see http://bit.ly/moz-document.
|
||||
case $m:
|
||||
case $M:
|
||||
scanner.readChar();
|
||||
if (scanCharIgnoreCase($i)) {
|
||||
if (!scanCharIgnoreCase($n)) return false;
|
||||
if (scanIdentChar($i)) {
|
||||
if (!scanIdentChar($n)) return false;
|
||||
buffer.write("min(");
|
||||
} else if (scanCharIgnoreCase($a)) {
|
||||
if (!scanCharIgnoreCase($x)) return false;
|
||||
} else if (scanIdentChar($a)) {
|
||||
if (!scanIdentChar($x)) return false;
|
||||
buffer.write("max(");
|
||||
} else {
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user