Skip to content

Support empty custom properties #2572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## 1.88.0-dev
## 1.88.0

* Allow custom properties with empty values (such as `--var:;`).

* Fix a bug when calculating source spans for interpolations.

Expand Down
4 changes: 3 additions & 1 deletion lib/src/parse/stylesheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,9 @@ abstract class StylesheetParser extends Parser {
var name = nameBuffer.interpolation(scanner.spanFrom(start, beforeColon));
if (name.initialPlain.startsWith('--')) {
var value = StringExpression(
_interpolatedDeclarationValue(silentComments: false),
atEndOfStatement()
? Interpolation(const [], const [], scanner.emptySpan)
: _interpolatedDeclarationValue(silentComments: false),
);
expectStatementSeparator("custom property");
return Declaration(name, value, scanner.spanFrom(start));
Expand Down
14 changes: 6 additions & 8 deletions lib/src/visitor/async_evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1381,9 +1381,12 @@ final class _EvaluateVisitor

if (node.value case var expression?) {
var value = await expression.accept(this);
// If the value is an empty list, preserve it, because converting it to CSS
// will throw an error that we want the user to see.
if (!value.isBlank || _isEmptyList(value)) {
if (!value.isBlank ||
// If the value is an empty list, preserve it, because converting it
// to CSS will throw an error that we want the user to see.
_isEmptyList(value) ||
// Custom properties are allowed to have empty values, per spec.
name.value.startsWith('--')) {
_parent.addChild(
ModifiableCssDeclaration(
name,
Expand All @@ -1396,11 +1399,6 @@ final class _EvaluateVisitor
_sourceMap ? node.value.andThen(_expressionNode)?.span : null,
),
);
} else if (name.value.startsWith('--')) {
throw _exception(
"Custom property values may not be empty.",
expression.span,
);
}
}

Expand Down
16 changes: 7 additions & 9 deletions lib/src/visitor/evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_evaluate.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: 6e5710daa106ed0b9b684af8bc61ce9cc233a10b
// Checksum: a3068d04660dd2bed34b884aa6e1a21d423dc4e5
//
// ignore_for_file: unused_import

Expand Down Expand Up @@ -1389,9 +1389,12 @@ final class _EvaluateVisitor

if (node.value case var expression?) {
var value = expression.accept(this);
// If the value is an empty list, preserve it, because converting it to CSS
// will throw an error that we want the user to see.
if (!value.isBlank || _isEmptyList(value)) {
if (!value.isBlank ||
// If the value is an empty list, preserve it, because converting it
// to CSS will throw an error that we want the user to see.
_isEmptyList(value) ||
// Custom properties are allowed to have empty values, per spec.
name.value.startsWith('--')) {
_parent.addChild(
ModifiableCssDeclaration(
name,
Expand All @@ -1404,11 +1407,6 @@ final class _EvaluateVisitor
_sourceMap ? node.value.andThen(_expressionNode)?.span : null,
),
);
} else if (name.value.startsWith('--')) {
throw _exception(
"Custom property values may not be empty.",
expression.span,
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/sass-parser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 0.4.21-dev
## 0.4.21

* No user-visible changes.

Expand Down
2 changes: 1 addition & 1 deletion pkg/sass-parser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sass-parser",
"version": "0.4.21-dev",
"version": "0.4.21",
"description": "A PostCSS-compatible wrapper of the official Sass parser",
"repository": "sass/sass",
"author": "Google Inc.",
Expand Down
2 changes: 1 addition & 1 deletion pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 15.5.0-dev
## 15.5.0

* No user-visible changes.

Expand Down
2 changes: 1 addition & 1 deletion pkg/sass_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: sass_api
# Note: Every time we add a new Sass AST node, we need to bump the *major*
# version because it's a breaking change for anyone who's implementing the
# visitor interface(s).
version: 15.5.0-dev
version: 15.5.0
description: Additional APIs for Dart Sass.
homepage: https://github.com/sass/dart-sass

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.88.0-dev
version: 1.88.0
description: A Sass implementation in Dart.
homepage: https://github.com/sass/dart-sass

Expand Down
7 changes: 5 additions & 2 deletions tool/grind/bump_version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ final _pubspecVersionRegExp = RegExp(r'^version: (.*)$', multiLine: true);
/// A regular expression that matches a Sass dependency version in a pubspec.
final _sassVersionRegExp = RegExp(r'^( +)sass: (\d.*)$', multiLine: true);

/// A regular expression that matches a CHANGELOG header for a dev version
final _changelogDevHeaderRegExp = RegExp(r'^## .*-dev$', multiLine: true);

/// Adds grinder tasks for bumping package versions.
void addBumpVersionTasks() {
for (var patch in [false, true]) {
Expand Down Expand Up @@ -65,9 +68,9 @@ void _bumpVersion(bool patch, bool dev) {
void addChangelogEntry(String dir, Version version) {
var path = p.join(dir, "CHANGELOG.md");
var text = File(path).readAsStringSync();
if (!dev && text.startsWith("## $version-dev\n")) {
if (!dev && text.startsWith(_changelogDevHeaderRegExp)) {
File(path).writeAsStringSync(
text.replaceFirst("## $version-dev\n", "## $version\n"),
text.replaceFirst(_changelogDevHeaderRegExp, "## $version"),
);
} else if (text.startsWith("## $version\n")) {
return;
Expand Down