Skip to content

Commit

Permalink
Fix @-moz-document parsing and add deprecation warnings
Browse files Browse the repository at this point in the history
Partially addresses #378
Closes #372
  • Loading branch information
nex3 committed Jun 23, 2018
1 parent 69e79d6 commit ccff2e2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 56 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 1.7.1

* Add a deprecation warning for `@-moz-document`, except for cases where only an
empty `url-prefix()` is used. Support is [being removed from Firefox][] and
will eventually be removed from Sass as well.

[being removed from Firefox]: https://www.fxsitecompat.com/en-CA/docs/2018/moz-document-support-has-been-dropped-except-for-empty-url-prefix/

* Fix a bug where `@-moz-document` functions with string arguments weren't being
parsed.

## 1.7.0

* Emit deprecation warnings for tokens such as `#abcd` that are ambiguous
Expand Down
4 changes: 2 additions & 2 deletions lib/src/parse/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ abstract class Parser {
/// Consumes a `url()` token if possible, and returns `null` otherwise.
@protected
String tryUrl() {
// NOTE: this logic is largely duplicated in ScssParser._urlContents and
// ScssParser._tryUrlContents. Most changes here should be mirrored there.
// NOTE: this logic is largely duplicated in ScssParser._tryUrlContents.
// Most changes here should be mirrored there.

var start = scanner.state;
if (!scanIdentifier("url", ignoreCase: true)) return null;
Expand Down
97 changes: 44 additions & 53 deletions lib/src/parse/stylesheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -907,18 +907,42 @@ abstract class StylesheetParser extends Parser {
AtRule _mozDocumentRule(LineScannerState start) {
var valueStart = scanner.state;
var buffer = new InterpolationBuffer();
var needsDeprecationWarning = false;
while (true) {
if (scanner.peekChar() == $hash) {
buffer.add(singleInterpolation());
needsDeprecationWarning = true;
} else {
var identifierStart = scanner.state;
var identifier = this.identifier();
switch (identifier) {
case "url":
case "url-prefix":
case "domain":
buffer.addInterpolation(
_urlContents(identifierStart, name: identifier));
var contents = _tryUrlContents(identifierStart, name: identifier);
if (contents != null) {
buffer.addInterpolation(contents);
} else {
scanner.expectChar($lparen);
whitespace();
var argument = interpolatedString();
scanner.expectChar($rparen);

buffer
..write(identifier)
..writeCharCode($lparen)
..addInterpolation(argument.asInterpolation())
..writeCharCode($rparen);
}

// A url-prefix with no argument, or with an empty string as an
// argument, is not (yet) deprecated.
var trailing = buffer.trailingString;
if (!trailing.endsWith("url-prefix()") &&
!trailing.endsWith("url-prefix('')") &&
!trailing.endsWith('url-prefix("")')) {
needsDeprecationWarning = true;
}
break;

case "regexp":
Expand All @@ -927,6 +951,7 @@ abstract class StylesheetParser extends Parser {
buffer.addInterpolation(interpolatedString().asInterpolation());
scanner.expectChar($rparen);
buffer.writeCharCode($rparen);
needsDeprecationWarning = true;
break;

default:
Expand All @@ -944,8 +969,16 @@ abstract class StylesheetParser extends Parser {

var value = buffer.interpolation(scanner.spanFrom(valueStart));
var children = this.children(_statement);
return new AtRule("-moz-document", scanner.spanFrom(start),
value: value, children: children);
var span = scanner.spanFrom(start);

if (needsDeprecationWarning) {
logger.warn("""
@-moz-document is deprecated and support will be removed from Sass in a future
relase. For details, see http://bit.ly/moz-document.
""", span: span, deprecation: true);
}

return new AtRule("-moz-document", span, value: value, children: children);
}

/// Consumes a `@return` rule.
Expand Down Expand Up @@ -2159,65 +2192,23 @@ To parse it as a color, use "${color.toStringAsRgb()}".
return new StringExpression(buffer.interpolation(scanner.spanFrom(start)));
}

/// Consumes the contents of a `url()` token (after the name).
/// Like [_urlContents], but returns `null` if the URL fails to parse.
///
/// [start] is the position before the beginning of the name. [name] is the
/// function's name; it defaults to `"url"`.
Interpolation _urlContents(LineScannerState start, {String name}) {
// NOTE: this logic is largely duplicated in [_tryUrlContents] and
// Parser.tryUrl. Most changes here should be mirrored there.

scanner.expectChar($lparen);
whitespaceWithoutComments();

// Match Ruby Sass's behavior: parse a raw URL() if possible, and if not
// backtrack and re-parse as a function expression.
var buffer = new InterpolationBuffer()..write("${name ?? 'url'}(");
while (true) {
var next = scanner.peekChar();
if (next == null) {
break;
} else if (next == $percent ||
next == $ampersand ||
(next >= $asterisk && next <= $tilde) ||
next >= 0x0080) {
buffer.writeCharCode(scanner.readChar());
} else if (next == $backslash) {
buffer.write(escape());
} else if (next == $hash) {
if (scanner.peekChar(1) == $lbrace) {
buffer.add(singleInterpolation());
} else {
buffer.writeCharCode(scanner.readChar());
}
} else if (isWhitespace(next)) {
whitespaceWithoutComments();
scanner.expectChar($rparen);
buffer.writeCharCode($rparen);
break;
} else if (next == $rparen) {
buffer.writeCharCode(scanner.readChar());
break;
} else {
scanner.expectChar($rparen);
}
}

return buffer.interpolation(scanner.spanFrom(start));
}

/// Like [_urlContents], but returns `null` if the URL fails to parse.
Interpolation _tryUrlContents(LineScannerState start) {
// NOTE: this logic is largely duplicated in [_urlContents] and
// Parser.tryUrl. Most changes here should be mirrored there.
Interpolation _tryUrlContents(LineScannerState start, {String name}) {
// NOTE: this logic is largely duplicated in Parser.tryUrl. Most changes
// here should be mirrored there.

var beginningOfContents = scanner.state;
if (!scanner.scanChar($lparen)) return null;
whitespaceWithoutComments();

// Match Ruby Sass's behavior: parse a raw URL() if possible, and if not
// backtrack and re-parse as a function expression.
var buffer = new InterpolationBuffer()..write("url(");
var buffer = new InterpolationBuffer()
..write(name ?? 'url')
..writeCharCode($lparen);
while (true) {
var next = scanner.peekChar();
if (next == null) {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: sass
version: 1.7.0
version: 1.7.1-dev
description: A Sass implementation in Dart.
author: Dart Team <[email protected]>
homepage: https://github.com/sass/dart-sass
Expand Down

0 comments on commit ccff2e2

Please sign in to comment.