diff --git a/CHANGELOG.md b/CHANGELOG.md index f829f18e2..930ba70b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.17.1 + +* Properly quote attribute selector values that start with identifiers but end + with a non-identifier character. + ## 1.17.0 * Improve error output, particularly for errors that cover multiple lines. diff --git a/lib/src/parse/parser.dart b/lib/src/parse/parser.dart index e6fe5618c..baaabc771 100644 --- a/lib/src/parse/parser.dart +++ b/lib/src/parse/parser.dart @@ -31,6 +31,16 @@ class Parser { static String parseIdentifier(String text, {Logger logger}) => Parser(text, logger: logger)._parseIdentifier(); + /// Returns whether [text] is a valid CSS identifier. + static bool isIdentifier(String text, {Logger logger}) { + try { + parseIdentifier(text, logger: logger); + return true; + } on SassFormatException { + return false; + } + } + @protected Parser(String contents, {url, Logger logger}) : scanner = SpanScanner(contents, sourceUrl: url), diff --git a/lib/src/visitor/serialize.dart b/lib/src/visitor/serialize.dart index 96c6ac1a4..037582908 100644 --- a/lib/src/visitor/serialize.dart +++ b/lib/src/visitor/serialize.dart @@ -15,6 +15,7 @@ import '../ast/node.dart'; import '../ast/selector.dart'; import '../color_names.dart'; import '../exception.dart'; +import '../parse/parser.dart'; import '../utils.dart'; import '../util/character.dart'; import '../util/no_source_map_buffer.dart'; @@ -903,7 +904,10 @@ class _SerializeVisitor implements CssVisitor, ValueVisitor, SelectorVisitor { _buffer.write(attribute.name); if (attribute.op != null) { _buffer.write(attribute.op); - if (_isIdentifier(attribute.value)) { + if (Parser.isIdentifier(attribute.value) && + // Emit identifiers that start with `--` with quotes, because IE11 + // doesn't consider them to be valid identifiers. + !attribute.value.startsWith('--')) { _buffer.write(attribute.value); } else { _visitQuotedString(attribute.value); @@ -1133,64 +1137,6 @@ class _SerializeVisitor implements CssVisitor, ValueVisitor, SelectorVisitor { return false; } } - - /// Returns whether [text] is a valid identifier. - /// - /// This *doesn't* consider identifiers beginning with `--` to be valid, - /// because IE 11 doesn't. - bool _isIdentifier(String text) { - var scanner = StringScanner(text); - scanner.scanChar($dash); - - if (scanner.isDone) return false; - var first = scanner.readChar(); - - if (isNameStart(first)) { - if (scanner.isDone) return true; - scanner.readChar(); - } else if (first == $backslash) { - if (!_consumeEscape(scanner)) return false; - } else { - return false; - } - - while (true) { - var next = scanner.peekChar(); - if (next == null) return true; - - if (isName(next)) { - scanner.readChar(); - } else if (next == $backslash) { - if (!_consumeEscape(scanner)) return false; - } else { - return false; - } - } - } - - /// Consumes an escape sequence in [scanner]. - /// - /// Returns whether a valid escape was consumed. - bool _consumeEscape(StringScanner scanner) { - scanner.expectChar($backslash); - - var first = scanner.peekChar(); - if (first == null || isNewline(first)) return false; - - if (isHex(first)) { - for (var i = 0; i < 6; i++) { - var next = scanner.peekChar(); - if (next == null || !isHex(next)) break; - scanner.readChar(); - } - if (isWhitespace(scanner.peekChar())) scanner.readChar(); - } else { - if (scanner.isDone) return false; - scanner.readChar(); - } - - return true; - } } /// An enum of generated CSS styles. diff --git a/pubspec.yaml b/pubspec.yaml index 2bd3bcb6c..916d2db67 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.17.0 +version: 1.17.1 description: A Sass implementation in Dart. author: Dart Team homepage: https://github.com/sass/dart-sass