Skip to content

Commit 04b6251

Browse files
authored
Parse silent comments in _interpolatedDeclarationValue() (#2266)
Closes #2263
1 parent 860eb5a commit 04b6251

File tree

4 files changed

+76
-22
lines changed

4 files changed

+76
-22
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.77.7
2+
3+
* **Potentially breaking bug fix:** `//` in certain places such as unknown
4+
at-rule values was being preserved in the CSS output, leading to potentially
5+
invalid CSS. It's now properly parsed as a silent comment and omitted from the
6+
CSS output.
7+
18
## 1.77.6
29

310
* Fix a few cases where comments and occasionally even whitespace wasn't allowed

lib/src/parse/parser.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ class Parser {
133133
whitespace();
134134
}
135135

136-
/// Consumes and ignores a silent (Sass-style) comment.
136+
/// Consumes and ignores a single silent (Sass-style) comment, not including
137+
/// the trailing newline.
137138
///
138139
/// Returns whether the comment was consumed.
139140
@protected

lib/src/parse/stylesheet.dart

+66-20
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,8 @@ abstract class StylesheetParser extends Parser {
380380
// Parse custom properties as declarations no matter what.
381381
var name = nameBuffer.interpolation(scanner.spanFrom(start, beforeColon));
382382
if (name.initialPlain.startsWith('--')) {
383-
var value = StringExpression(_interpolatedDeclarationValue());
383+
var value = StringExpression(
384+
_interpolatedDeclarationValue(silentComments: false));
384385
expectStatementSeparator("custom property");
385386
return Declaration(name, value, scanner.spanFrom(start));
386387
}
@@ -532,7 +533,8 @@ abstract class StylesheetParser extends Parser {
532533
scanner.expectChar($colon);
533534

534535
if (parseCustomProperties && name.initialPlain.startsWith('--')) {
535-
var value = StringExpression(_interpolatedDeclarationValue());
536+
var value = StringExpression(
537+
_interpolatedDeclarationValue(silentComments: false));
536538
expectStatementSeparator("custom property");
537539
return Declaration(name, value, scanner.spanFrom(start));
538540
}
@@ -1550,7 +1552,7 @@ abstract class StylesheetParser extends Parser {
15501552

15511553
Interpolation? value;
15521554
if (scanner.peekChar() != $exclamation && !atEndOfStatement()) {
1553-
value = almostAnyValue();
1555+
value = _interpolatedDeclarationValue(allowOpenBrace: false);
15541556
}
15551557

15561558
AtRule rule;
@@ -1575,7 +1577,7 @@ abstract class StylesheetParser extends Parser {
15751577
/// This declares a return type of [Statement] so that it can be returned
15761578
/// within case statements.
15771579
Statement _disallowedAtRule(LineScannerState start) {
1578-
almostAnyValue();
1580+
_interpolatedDeclarationValue(allowEmpty: true, allowOpenBrace: false);
15791581
error("This at-rule is not allowed here.", scanner.spanFrom(start));
15801582
}
15811583

@@ -2748,13 +2750,11 @@ abstract class StylesheetParser extends Parser {
27482750
///
27492751
/// Differences from [_interpolatedDeclarationValue] include:
27502752
///
2751-
/// * This does not balance brackets.
2753+
/// * This always stops at curly braces.
27522754
///
27532755
/// * This does not interpret backslashes, since the text is expected to be
27542756
/// re-parsed.
27552757
///
2756-
/// * This supports Sass-style single-line comments.
2757-
///
27582758
/// * This does not compress adjacent whitespace characters.
27592759
@protected
27602760
Interpolation almostAnyValue({bool omitComments = false}) {
@@ -2773,11 +2773,21 @@ abstract class StylesheetParser extends Parser {
27732773
buffer.addInterpolation(interpolatedString().asInterpolation());
27742774

27752775
case $slash:
2776-
var commentStart = scanner.position;
2777-
if (scanComment()) {
2778-
if (!omitComments) buffer.write(scanner.substring(commentStart));
2779-
} else {
2780-
buffer.writeCharCode(scanner.readChar());
2776+
switch (scanner.peekChar(1)) {
2777+
case $asterisk when !omitComments:
2778+
buffer.write(rawText(loudComment));
2779+
2780+
case $asterisk:
2781+
loudComment();
2782+
2783+
case $slash when !omitComments:
2784+
buffer.write(rawText(silentComment));
2785+
2786+
case $slash:
2787+
silentComment();
2788+
2789+
case _:
2790+
buffer.writeCharCode(scanner.readChar());
27812791
}
27822792

27832793
case $hash when scanner.peekChar(1) == $lbrace:
@@ -2794,12 +2804,17 @@ abstract class StylesheetParser extends Parser {
27942804

27952805
case $u || $U:
27962806
var beforeUrl = scanner.state;
2797-
if (!scanIdentifier("url")) {
2798-
buffer.writeCharCode(scanner.readChar());
2807+
var identifier = this.identifier();
2808+
if (identifier != "url" &&
2809+
// This isn't actually a standard CSS feature, but it was
2810+
// supported by the old `@document` rule so we continue to support
2811+
// it for backwards-compatibility.
2812+
identifier != "url-prefix") {
2813+
buffer.write(identifier);
27992814
continue loop;
28002815
}
28012816

2802-
if (_tryUrlContents(beforeUrl) case var contents?) {
2817+
if (_tryUrlContents(beforeUrl, name: identifier) case var contents?) {
28032818
buffer.addInterpolation(contents);
28042819
} else {
28052820
scanner.state = beforeUrl;
@@ -2830,11 +2845,19 @@ abstract class StylesheetParser extends Parser {
28302845
///
28312846
/// If [allowColon] is `false`, this stops at top-level colons.
28322847
///
2848+
/// If [allowOpenBrace] is `false`, this stops at top-level colons.
2849+
///
2850+
/// If [silentComments] is `true`, this will parse silent comments as
2851+
/// comments. Otherwise, it will preserve two adjacent slashes and emit them
2852+
/// to CSS.
2853+
///
28332854
/// Unlike [declarationValue], this allows interpolation.
28342855
Interpolation _interpolatedDeclarationValue(
28352856
{bool allowEmpty = false,
28362857
bool allowSemicolon = false,
2837-
bool allowColon = true}) {
2858+
bool allowColon = true,
2859+
bool allowOpenBrace = true,
2860+
bool silentComments = true}) {
28382861
// NOTE: this logic is largely duplicated in Parser.declarationValue. Most
28392862
// changes here should be mirrored there.
28402863

@@ -2854,7 +2877,22 @@ abstract class StylesheetParser extends Parser {
28542877
buffer.addInterpolation(interpolatedString().asInterpolation());
28552878
wroteNewline = false;
28562879

2857-
case $slash when scanner.peekChar(1) == $asterisk:
2880+
case $slash:
2881+
switch (scanner.peekChar(1)) {
2882+
case $asterisk:
2883+
buffer.write(rawText(loudComment));
2884+
wroteNewline = false;
2885+
2886+
case $slash when silentComments:
2887+
silentComment();
2888+
wroteNewline = false;
2889+
2890+
case _:
2891+
buffer.writeCharCode(scanner.readChar());
2892+
wroteNewline = false;
2893+
}
2894+
2895+
case $slash when silentComments && scanner.peekChar(1) == $slash:
28582896
buffer.write(rawText(loudComment));
28592897
wroteNewline = false;
28602898

@@ -2882,6 +2920,9 @@ abstract class StylesheetParser extends Parser {
28822920
scanner.readChar();
28832921
wroteNewline = true;
28842922

2923+
case $lbrace when !allowOpenBrace:
2924+
break loop;
2925+
28852926
case $lparen || $lbrace || $lbracket:
28862927
var bracket = scanner.readChar();
28872928
buffer.writeCharCode(bracket);
@@ -2907,13 +2948,18 @@ abstract class StylesheetParser extends Parser {
29072948

29082949
case $u || $U:
29092950
var beforeUrl = scanner.state;
2910-
if (!scanIdentifier("url")) {
2911-
buffer.writeCharCode(scanner.readChar());
2951+
var identifier = this.identifier();
2952+
if (identifier != "url" &&
2953+
// This isn't actually a standard CSS feature, but it was
2954+
// supported by the old `@document` rule so we continue to support
2955+
// it for backwards-compatibility.
2956+
identifier != "url-prefix") {
2957+
buffer.write(identifier);
29122958
wroteNewline = false;
29132959
continue loop;
29142960
}
29152961

2916-
if (_tryUrlContents(beforeUrl) case var contents?) {
2962+
if (_tryUrlContents(beforeUrl, name: identifier) case var contents?) {
29172963
buffer.addInterpolation(contents);
29182964
} else {
29192965
scanner.state = beforeUrl;

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: sass
2-
version: 1.77.6
2+
version: 1.77.7-dev
33
description: A Sass implementation in Dart.
44
homepage: https://github.com/sass/dart-sass
55

0 commit comments

Comments
 (0)