Skip to content

Commit

Permalink
Deprecated mixed declarations (#2267)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Jul 9, 2024
1 parent 1edc247 commit 7203d65
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 24 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 1,11 @@
## 1.77.7

* Declarations that appear after nested rules are deprecated, because the
semantics Sass has historically used are different from the semantics
specified by CSS. In the future, Sass will adopt the standard CSS semantics.

See [the Sass website](https://sass-lang.com/d/mixed-decls) for details.

* **Potentially breaking bug fix:** `//` in certain places such as unknown
at-rule values was being preserved in the CSS output, leading to potentially
invalid CSS. It's now properly parsed as a silent comment and omitted from the
Expand Down
7 changes: 6 additions & 1 deletion lib/src/deprecation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 15,7 @@ enum Deprecation {
// DO NOT EDIT. This section was generated from the language repo.
// See tool/grind/generate_deprecations.dart for details.
//
// Checksum: 22d9bdbe92eb39b3c0d6d64ebe1879a431c0037e
// Checksum: 309e4f1f008f08379b824ab6094e13df2e18e187

/// Deprecation for passing a string directly to meta.call().
callString('call-string',
Expand Down Expand Up @@ -90,6 90,11 @@ enum Deprecation {
deprecatedIn: '1.76.0',
description: 'Function and mixin names beginning with --.'),

/// Deprecation for declarations after or between nested rules.
mixedDecls('mixed-decls',
deprecatedIn: '1.77.7',
description: 'Declarations after or between nested rules.'),

/// Deprecation for @import rules.
import.future('import', description: '@import rules.'),

Expand Down
6 changes: 3 additions & 3 deletions lib/src/parse/css.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 42,7 @@ class CssParser extends ScssParser {
}

Statement atRule(Statement child(), {bool root = false}) {
// NOTE: this logic is largely duplicated in CssParser.atRule. Most changes
// NOTE: this logic is largely duplicated in StylesheetParser.atRule. Most changes
// here should be mirrored there.

var start = scanner.state;
Expand All @@ -65,7 65,7 @@ class CssParser extends ScssParser {
"return" ||
"warn" ||
"while" =>
_forbiddenAtRoot(start),
_forbiddenAtRule(start),
"import" => _cssImportRule(start),
"media" => mediaRule(start),
"-moz-document" => mozDocumentRule(start, name),
Expand All @@ -75,7 75,7 @@ class CssParser extends ScssParser {
}

/// Throws an error for a forbidden at-rule.
Never _forbiddenAtRoot(LineScannerState start) {
Never _forbiddenAtRule(LineScannerState start) {
almostAnyValue();
error("This at-rule isn't allowed in plain CSS.", scanner.spanFrom(start));
}
Expand Down
37 changes: 29 additions & 8 deletions lib/src/visitor/async_evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 1189,22 @@ final class _EvaluateVisitor
node.span);
}

if (_parent.parent!.children.last case var sibling
when _parent != sibling) {
_warn(
"Sass's behavior for declarations that appear after nested\n"
"rules will be changing to match the behavior specified by CSS in an "
"upcoming\n"
"version. To keep the existing behavior, move the declaration above "
"the nested\n"
"rule. To opt into the new behavior, wrap the declaration in `& "
"{}`.\n"
"\n"
"More info: https://sass-lang.com/d/mixed-decls",
MultiSpan(node.span, 'declaration', {sibling.span: 'nested rule'}),
Deprecation.mixedDecls);
}

var name = await _interpolationToValue(node.name, warnForColor: true);
if (_declarationName case var declarationName?) {
name = CssValue("$declarationName-${name.value}", name.span);
Expand Down Expand Up @@ -2065,8 2081,20 @@ final class _EvaluateVisitor
scopeWhen: node.hasDeclarations);
_atRootExcludingStyleRule = oldAtRootExcludingStyleRule;

_warnForBogusCombinators(rule);

if (_styleRule == null && _parent.children.isNotEmpty) {
var lastChild = _parent.children.last;
lastChild.isGroupEnd = true;
}

return null;
}

/// Emits deprecation warnings for any bogus combinators in [rule].
void _warnForBogusCombinators(CssStyleRule rule) {
if (!rule.isInvisibleOtherThanBogusCombinators) {
for (var complex in parsedSelector.components) {
for (var complex in rule.selector.components) {
if (!complex.isBogus) continue;

if (complex.isUseless) {
Expand Down Expand Up @@ -2110,13 2138,6 @@ final class _EvaluateVisitor
}
}
}

if (_styleRule == null && _parent.children.isNotEmpty) {
var lastChild = _parent.children.last;
lastChild.isGroupEnd = true;
}

return null;
}

Future<Value?> visitSupportsRule(SupportsRule node) async {
Expand Down
39 changes: 30 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: 116b8079719577ac6e4dad4aebe403282136e611
// Checksum: ebf292c26dcfdd7f61fd70ce3dc9e0be2b6708b3
//
// ignore_for_file: unused_import

Expand Down Expand Up @@ -1187,6 1187,22 @@ final class _EvaluateVisitor
node.span);
}

if (_parent.parent!.children.last case var sibling
when _parent != sibling) {
_warn(
"Sass's behavior for declarations that appear after nested\n"
"rules will be changing to match the behavior specified by CSS in an "
"upcoming\n"
"version. To keep the existing behavior, move the declaration above "
"the nested\n"
"rule. To opt into the new behavior, wrap the declaration in `& "
"{}`.\n"
"\n"
"More info: https://sass-lang.com/d/mixed-decls",
MultiSpan(node.span, 'declaration', {sibling.span: 'nested rule'}),
Deprecation.mixedDecls);
}

var name = _interpolationToValue(node.name, warnForColor: true);
if (_declarationName case var declarationName?) {
name = CssValue("$declarationName-${name.value}", name.span);
Expand Down Expand Up @@ -2055,8 2071,20 @@ final class _EvaluateVisitor
scopeWhen: node.hasDeclarations);
_atRootExcludingStyleRule = oldAtRootExcludingStyleRule;

_warnForBogusCombinators(rule);

if (_styleRule == null && _parent.children.isNotEmpty) {
var lastChild = _parent.children.last;
lastChild.isGroupEnd = true;
}

return null;
}

/// Emits deprecation warnings for any bogus combinators in [rule].
void _warnForBogusCombinators(CssStyleRule rule) {
if (!rule.isInvisibleOtherThanBogusCombinators) {
for (var complex in parsedSelector.components) {
for (var complex in rule.selector.components) {
if (!complex.isBogus) continue;

if (complex.isUseless) {
Expand Down Expand Up @@ -2100,13 2128,6 @@ final class _EvaluateVisitor
}
}
}

if (_styleRule == null && _parent.children.isNotEmpty) {
var lastChild = _parent.children.last;
lastChild.isGroupEnd = true;
}

return null;
}

Value? visitSupportsRule(SupportsRule node) {
Expand Down
4 changes: 4 additions & 0 deletions pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 1,7 @@
## 10.4.7

* No user-visible changes.

## 10.4.6

* No user-visible changes.
Expand Down
4 changes: 2 additions & 2 deletions pkg/sass_api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 2,15 @@ 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: 10.4.6
version: 10.4.7
description: Additional APIs for Dart Sass.
homepage: https://github.com/sass/dart-sass

environment:
sdk: ">=3.0.0 <4.0.0"

dependencies:
sass: 1.77.6
sass: 1.77.7

dev_dependencies:
dartdoc: ">=6.0.0 <9.0.0"
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.77.7-dev
version: 1.77.7
description: A Sass implementation in Dart.
homepage: https://github.com/sass/dart-sass

Expand Down

0 comments on commit 7203d65

Please sign in to comment.