From e905840c447df1d4b0ce62c84638d9c753997029 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 18 Jun 2024 19:49:42 -0700 Subject: [PATCH 1/4] Deprecated mixed declarations and implement `@nest` See sass/sass#3885 --- lib/src/ast/sass.dart | 1 + lib/src/ast/sass/statement/nest_rule.dart | 28 ++++++++ lib/src/deprecation.dart | 7 +- lib/src/parse/css.dart | 7 +- lib/src/parse/stylesheet.dart | 11 +++ lib/src/visitor/async_evaluate.dart | 81 +++++++++++++++++++--- lib/src/visitor/evaluate.dart | 82 ++++++++++++++++++++--- lib/src/visitor/interface/statement.dart | 1 + lib/src/visitor/recursive_statement.dart | 2 + lib/src/visitor/statement_search.dart | 2 + 10 files changed, 201 insertions(+), 21 deletions(-) create mode 100644 lib/src/ast/sass/statement/nest_rule.dart diff --git a/lib/src/ast/sass.dart b/lib/src/ast/sass.dart index 149641670..8a8f24246 100644 --- a/lib/src/ast/sass.dart +++ b/lib/src/ast/sass.dart @@ -54,6 +54,7 @@ export 'sass/statement/include_rule.dart'; export 'sass/statement/loud_comment.dart'; export 'sass/statement/media_rule.dart'; export 'sass/statement/mixin_rule.dart'; +export 'sass/statement/nest_rule.dart'; export 'sass/statement/parent.dart'; export 'sass/statement/return_rule.dart'; export 'sass/statement/silent_comment.dart'; diff --git a/lib/src/ast/sass/statement/nest_rule.dart b/lib/src/ast/sass/statement/nest_rule.dart new file mode 100644 index 000000000..9ee815264 --- /dev/null +++ b/lib/src/ast/sass/statement/nest_rule.dart @@ -0,0 +1,28 @@ +// Copyright 2024 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:source_span/source_span.dart'; + +import '../../../visitor/interface/statement.dart'; +import '../statement.dart'; +import 'parent.dart'; + +/// A `@nest` rule. +/// +/// This ensures that the nesting and ordering of its contents match that +/// [specified by CSS]. +/// +/// [specified by CSS]: https://drafts.csswg.org/css-nesting/#mixing +/// +/// {@category AST} +final class NestRule extends ParentStatement> { + final FileSpan span; + + NestRule(Iterable children, this.span) + : super(List.unmodifiable(children)); + + T accept(StatementVisitor visitor) => visitor.visitNestRule(this); + + String toString() => "@nest {${children.join(' ')}}"; +} diff --git a/lib/src/deprecation.dart b/lib/src/deprecation.dart index cec976714..b71960c47 100644 --- a/lib/src/deprecation.dart +++ b/lib/src/deprecation.dart @@ -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', @@ -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.'), diff --git a/lib/src/parse/css.dart b/lib/src/parse/css.dart index 747d22c49..45f326b55 100644 --- a/lib/src/parse/css.dart +++ b/lib/src/parse/css.dart @@ -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; @@ -65,17 +65,18 @@ class CssParser extends ScssParser { "return" || "warn" || "while" => - _forbiddenAtRoot(start), + _forbiddenAtRule(start), "import" => _cssImportRule(start), "media" => mediaRule(start), "-moz-document" => mozDocumentRule(start, name), "supports" => supportsRule(start), + var name? when name.toLowerCase() == "nest" => nestRule(start), _ => unknownAtRule(start, name) }; } /// 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)); } diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index 046c56e6f..006645251 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -647,6 +647,8 @@ abstract class StylesheetParser extends Parser { return _warnRule(start); case "while": return _whileRule(start, child); + case var name? when name.toLowerCase() == "nest": + return nestRule(start); default: return unknownAtRule(start, name); } @@ -1398,6 +1400,15 @@ abstract class StylesheetParser extends Parser { }); } + /// Consumes a `@return` rule. + /// + /// [start] should point before the `@`. + NestRule nestRule(LineScannerState start) { + whitespace(); + return _withChildren( + _statement, start, (children, span) => NestRule(children, span)); + } + /// Consumes a `@return` rule. /// /// [start] should point before the `@`. diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index b8434ff47..79e5b565e 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -1189,6 +1189,19 @@ 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 `& {}`.", + 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); @@ -1884,6 +1897,53 @@ final class _EvaluateVisitor return null; } + Future visitNestRule(NestRule node) async { + if (_declarationName != null) { + throw _exception( + "At-rules may not be used within nested declarations.", node.span); + } else if (_inKeyframes) { + throw _exception( + "@nest may not be used within a keyframe block.", node.span); + } + + var wasInUnknownAtRule = _inUnknownAtRule; + var oldAtRootExcludingStyleRule = _atRootExcludingStyleRule; + _inUnknownAtRule = true; + _atRootExcludingStyleRule = false; + if (_styleRule case var styleRule?) { + if (_stylesheet.plainCss) { + for (var child in node.children) { + await child.accept(this); + } + } else { + var newStyleRule = styleRule.copyWithoutChildren(); + await _withParent(newStyleRule, () async { + await _withStyleRule(newStyleRule, () async { + for (var child in node.children) { + await child.accept(this); + } + }); + }, + through: (node) => node is CssStyleRule, + scopeWhen: node.hasDeclarations); + + _warnForBogusCombinators(newStyleRule); + } + } else { + await _withParent( + ModifiableCssAtRule(CssValue("nest", node.span), node.span), + () async { + for (var child in node.children) { + await child.accept(this); + } + }, scopeWhen: node.hasDeclarations); + } + _inUnknownAtRule = wasInUnknownAtRule; + _atRootExcludingStyleRule = oldAtRootExcludingStyleRule; + + return null; + } + Future visitLoudComment(LoudComment node) async { // NOTE: this logic is largely duplicated in [visitCssComment]. Most changes // here should be mirrored there. @@ -2065,8 +2125,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) { @@ -2110,13 +2182,6 @@ final class _EvaluateVisitor } } } - - if (_styleRule == null && _parent.children.isNotEmpty) { - var lastChild = _parent.children.last; - lastChild.isGroupEnd = true; - } - - return null; } Future visitSupportsRule(SupportsRule node) async { diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 1680be88e..67b4ad793 100644 --- a/lib/src/visitor/evaluate.dart +++ b/lib/src/visitor/evaluate.dart @@ -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: 779c244329c3373db98017fefa2dd997cff05904 // // ignore_for_file: unused_import @@ -1187,6 +1187,19 @@ 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 `& {}`.", + 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); @@ -1876,6 +1889,52 @@ final class _EvaluateVisitor return null; } + Value? visitNestRule(NestRule node) { + if (_declarationName != null) { + throw _exception( + "At-rules may not be used within nested declarations.", node.span); + } else if (_inKeyframes) { + throw _exception( + "@nest may not be used within a keyframe block.", node.span); + } + + var wasInUnknownAtRule = _inUnknownAtRule; + var oldAtRootExcludingStyleRule = _atRootExcludingStyleRule; + _inUnknownAtRule = true; + _atRootExcludingStyleRule = false; + if (_styleRule case var styleRule?) { + if (_stylesheet.plainCss) { + for (var child in node.children) { + child.accept(this); + } + } else { + var newStyleRule = styleRule.copyWithoutChildren(); + _withParent(newStyleRule, () { + _withStyleRule(newStyleRule, () { + for (var child in node.children) { + child.accept(this); + } + }); + }, + through: (node) => node is CssStyleRule, + scopeWhen: node.hasDeclarations); + + _warnForBogusCombinators(newStyleRule); + } + } else { + _withParent(ModifiableCssAtRule(CssValue("nest", node.span), node.span), + () { + for (var child in node.children) { + child.accept(this); + } + }, scopeWhen: node.hasDeclarations); + } + _inUnknownAtRule = wasInUnknownAtRule; + _atRootExcludingStyleRule = oldAtRootExcludingStyleRule; + + return null; + } + Value? visitLoudComment(LoudComment node) { // NOTE: this logic is largely duplicated in [visitCssComment]. Most changes // here should be mirrored there. @@ -2055,8 +2114,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) { @@ -2100,13 +2171,6 @@ final class _EvaluateVisitor } } } - - if (_styleRule == null && _parent.children.isNotEmpty) { - var lastChild = _parent.children.last; - lastChild.isGroupEnd = true; - } - - return null; } Value? visitSupportsRule(SupportsRule node) { diff --git a/lib/src/visitor/interface/statement.dart b/lib/src/visitor/interface/statement.dart index 610c488bf..61b0da933 100644 --- a/lib/src/visitor/interface/statement.dart +++ b/lib/src/visitor/interface/statement.dart @@ -28,6 +28,7 @@ abstract interface class StatementVisitor { T visitLoudComment(LoudComment node); T visitMediaRule(MediaRule node); T visitMixinRule(MixinRule node); + T visitNestRule(NestRule node); T visitReturnRule(ReturnRule node); T visitSilentComment(SilentComment node); T visitStyleRule(StyleRule node); diff --git a/lib/src/visitor/recursive_statement.dart b/lib/src/visitor/recursive_statement.dart index 3d89a84d9..bfcbdbfd4 100644 --- a/lib/src/visitor/recursive_statement.dart +++ b/lib/src/visitor/recursive_statement.dart @@ -71,6 +71,8 @@ mixin RecursiveStatementVisitor implements StatementVisitor { void visitMixinRule(MixinRule node) => visitCallableDeclaration(node); + void visitNestRule(NestRule node) => visitChildren(node.children); + void visitReturnRule(ReturnRule node) {} void visitSilentComment(SilentComment node) {} diff --git a/lib/src/visitor/statement_search.dart b/lib/src/visitor/statement_search.dart index 6abd7fe9f..3fd31863d 100644 --- a/lib/src/visitor/statement_search.dart +++ b/lib/src/visitor/statement_search.dart @@ -61,6 +61,8 @@ mixin StatementSearchVisitor implements StatementVisitor { T? visitMixinRule(MixinRule node) => visitCallableDeclaration(node); + T? visitNestRule(NestRule node) => visitChildren(node.children); + T? visitReturnRule(ReturnRule node) => null; T? visitSilentComment(SilentComment node) => null; From 855fcb2e16c27604e5b77b8ac4862b1613d40a30 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 20 Jun 2024 14:27:54 -0700 Subject: [PATCH 2/4] Fixes for tests --- lib/src/parse/stylesheet.dart | 11 +++++++++-- lib/src/visitor/async_evaluate.dart | 3 ++- lib/src/visitor/evaluate.dart | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index 921c86ce8..8101e2d76 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -1405,10 +1405,17 @@ abstract class StylesheetParser extends Parser { /// Consumes a `@return` rule. /// /// [start] should point before the `@`. + @protected NestRule nestRule(LineScannerState start) { whitespace(); - return _withChildren( - _statement, start, (children, span) => NestRule(children, span)); + var wasInUnknownAtRule = _inUnknownAtRule; + _inUnknownAtRule = true; + try { + return _withChildren( + _statement, start, (children, span) => NestRule(children, span)); + } finally { + _inUnknownAtRule = wasInUnknownAtRule; + } } /// Consumes a `@return` rule. diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index 79e5b565e..244fde80f 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -1197,7 +1197,8 @@ final class _EvaluateVisitor "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 `& {}`.", + "rule. To opt into the new behavior, wrap the declaration in `@nest " + "{}`.", MultiSpan(node.span, 'declaration', {sibling.span: 'nested rule'}), Deprecation.mixedDecls); } diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 67b4ad793..83b32243e 100644 --- a/lib/src/visitor/evaluate.dart +++ b/lib/src/visitor/evaluate.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_evaluate.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: 779c244329c3373db98017fefa2dd997cff05904 +// Checksum: e1e8310eb9afa8042569f8a706341ae983fd78ee // // ignore_for_file: unused_import @@ -1195,7 +1195,8 @@ final class _EvaluateVisitor "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 `& {}`.", + "rule. To opt into the new behavior, wrap the declaration in `@nest " + "{}`.", MultiSpan(node.span, 'declaration', {sibling.span: 'nested rule'}), Deprecation.mixedDecls); } From 9b996e7b4096f1f8944427c9a53062696dfbaee6 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 3 Jul 2024 18:07:50 -0700 Subject: [PATCH 3/4] Drop support for `@nest` --- CHANGELOG.md | 6 +++ lib/src/ast/sass.dart | 1 - lib/src/ast/sass/statement/nest_rule.dart | 28 ------------ lib/src/parse/css.dart | 1 - lib/src/parse/stylesheet.dart | 18 -------- lib/src/visitor/async_evaluate.dart | 53 ++-------------------- lib/src/visitor/evaluate.dart | 54 +++-------------------- lib/src/visitor/interface/statement.dart | 1 - lib/src/visitor/recursive_statement.dart | 2 - lib/src/visitor/statement_search.dart | 2 - pkg/sass_api/CHANGELOG.md | 4 ++ pkg/sass_api/pubspec.yaml | 2 +- pubspec.yaml | 2 +- 13 files changed, 21 insertions(+), 153 deletions(-) delete mode 100644 lib/src/ast/sass/statement/nest_rule.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index edce7c487..3cd1720e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/lib/src/ast/sass.dart b/lib/src/ast/sass.dart index 8a8f24246..149641670 100644 --- a/lib/src/ast/sass.dart +++ b/lib/src/ast/sass.dart @@ -54,7 +54,6 @@ export 'sass/statement/include_rule.dart'; export 'sass/statement/loud_comment.dart'; export 'sass/statement/media_rule.dart'; export 'sass/statement/mixin_rule.dart'; -export 'sass/statement/nest_rule.dart'; export 'sass/statement/parent.dart'; export 'sass/statement/return_rule.dart'; export 'sass/statement/silent_comment.dart'; diff --git a/lib/src/ast/sass/statement/nest_rule.dart b/lib/src/ast/sass/statement/nest_rule.dart deleted file mode 100644 index 9ee815264..000000000 --- a/lib/src/ast/sass/statement/nest_rule.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2024 Google Inc. Use of this source code is governed by an -// MIT-style license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -import 'package:source_span/source_span.dart'; - -import '../../../visitor/interface/statement.dart'; -import '../statement.dart'; -import 'parent.dart'; - -/// A `@nest` rule. -/// -/// This ensures that the nesting and ordering of its contents match that -/// [specified by CSS]. -/// -/// [specified by CSS]: https://drafts.csswg.org/css-nesting/#mixing -/// -/// {@category AST} -final class NestRule extends ParentStatement> { - final FileSpan span; - - NestRule(Iterable children, this.span) - : super(List.unmodifiable(children)); - - T accept(StatementVisitor visitor) => visitor.visitNestRule(this); - - String toString() => "@nest {${children.join(' ')}}"; -} diff --git a/lib/src/parse/css.dart b/lib/src/parse/css.dart index 45f326b55..22d380edb 100644 --- a/lib/src/parse/css.dart +++ b/lib/src/parse/css.dart @@ -70,7 +70,6 @@ class CssParser extends ScssParser { "media" => mediaRule(start), "-moz-document" => mozDocumentRule(start, name), "supports" => supportsRule(start), - var name? when name.toLowerCase() == "nest" => nestRule(start), _ => unknownAtRule(start, name) }; } diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index 8101e2d76..eace75790 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -649,8 +649,6 @@ abstract class StylesheetParser extends Parser { return _warnRule(start); case "while": return _whileRule(start, child); - case var name? when name.toLowerCase() == "nest": - return nestRule(start); default: return unknownAtRule(start, name); } @@ -1402,22 +1400,6 @@ abstract class StylesheetParser extends Parser { }); } - /// Consumes a `@return` rule. - /// - /// [start] should point before the `@`. - @protected - NestRule nestRule(LineScannerState start) { - whitespace(); - var wasInUnknownAtRule = _inUnknownAtRule; - _inUnknownAtRule = true; - try { - return _withChildren( - _statement, start, (children, span) => NestRule(children, span)); - } finally { - _inUnknownAtRule = wasInUnknownAtRule; - } - } - /// Consumes a `@return` rule. /// /// [start] should point before the `@`. diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index 244fde80f..e4a65d12e 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -1197,8 +1197,10 @@ final class _EvaluateVisitor "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 `@nest " - "{}`.", + "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); } @@ -1898,53 +1900,6 @@ final class _EvaluateVisitor return null; } - Future visitNestRule(NestRule node) async { - if (_declarationName != null) { - throw _exception( - "At-rules may not be used within nested declarations.", node.span); - } else if (_inKeyframes) { - throw _exception( - "@nest may not be used within a keyframe block.", node.span); - } - - var wasInUnknownAtRule = _inUnknownAtRule; - var oldAtRootExcludingStyleRule = _atRootExcludingStyleRule; - _inUnknownAtRule = true; - _atRootExcludingStyleRule = false; - if (_styleRule case var styleRule?) { - if (_stylesheet.plainCss) { - for (var child in node.children) { - await child.accept(this); - } - } else { - var newStyleRule = styleRule.copyWithoutChildren(); - await _withParent(newStyleRule, () async { - await _withStyleRule(newStyleRule, () async { - for (var child in node.children) { - await child.accept(this); - } - }); - }, - through: (node) => node is CssStyleRule, - scopeWhen: node.hasDeclarations); - - _warnForBogusCombinators(newStyleRule); - } - } else { - await _withParent( - ModifiableCssAtRule(CssValue("nest", node.span), node.span), - () async { - for (var child in node.children) { - await child.accept(this); - } - }, scopeWhen: node.hasDeclarations); - } - _inUnknownAtRule = wasInUnknownAtRule; - _atRootExcludingStyleRule = oldAtRootExcludingStyleRule; - - return null; - } - Future visitLoudComment(LoudComment node) async { // NOTE: this logic is largely duplicated in [visitCssComment]. Most changes // here should be mirrored there. diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 83b32243e..cc2458bab 100644 --- a/lib/src/visitor/evaluate.dart +++ b/lib/src/visitor/evaluate.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_evaluate.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: e1e8310eb9afa8042569f8a706341ae983fd78ee +// Checksum: ebf292c26dcfdd7f61fd70ce3dc9e0be2b6708b3 // // ignore_for_file: unused_import @@ -1195,8 +1195,10 @@ final class _EvaluateVisitor "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 `@nest " - "{}`.", + "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); } @@ -1890,52 +1892,6 @@ final class _EvaluateVisitor return null; } - Value? visitNestRule(NestRule node) { - if (_declarationName != null) { - throw _exception( - "At-rules may not be used within nested declarations.", node.span); - } else if (_inKeyframes) { - throw _exception( - "@nest may not be used within a keyframe block.", node.span); - } - - var wasInUnknownAtRule = _inUnknownAtRule; - var oldAtRootExcludingStyleRule = _atRootExcludingStyleRule; - _inUnknownAtRule = true; - _atRootExcludingStyleRule = false; - if (_styleRule case var styleRule?) { - if (_stylesheet.plainCss) { - for (var child in node.children) { - child.accept(this); - } - } else { - var newStyleRule = styleRule.copyWithoutChildren(); - _withParent(newStyleRule, () { - _withStyleRule(newStyleRule, () { - for (var child in node.children) { - child.accept(this); - } - }); - }, - through: (node) => node is CssStyleRule, - scopeWhen: node.hasDeclarations); - - _warnForBogusCombinators(newStyleRule); - } - } else { - _withParent(ModifiableCssAtRule(CssValue("nest", node.span), node.span), - () { - for (var child in node.children) { - child.accept(this); - } - }, scopeWhen: node.hasDeclarations); - } - _inUnknownAtRule = wasInUnknownAtRule; - _atRootExcludingStyleRule = oldAtRootExcludingStyleRule; - - return null; - } - Value? visitLoudComment(LoudComment node) { // NOTE: this logic is largely duplicated in [visitCssComment]. Most changes // here should be mirrored there. diff --git a/lib/src/visitor/interface/statement.dart b/lib/src/visitor/interface/statement.dart index 61b0da933..610c488bf 100644 --- a/lib/src/visitor/interface/statement.dart +++ b/lib/src/visitor/interface/statement.dart @@ -28,7 +28,6 @@ abstract interface class StatementVisitor { T visitLoudComment(LoudComment node); T visitMediaRule(MediaRule node); T visitMixinRule(MixinRule node); - T visitNestRule(NestRule node); T visitReturnRule(ReturnRule node); T visitSilentComment(SilentComment node); T visitStyleRule(StyleRule node); diff --git a/lib/src/visitor/recursive_statement.dart b/lib/src/visitor/recursive_statement.dart index bfcbdbfd4..3d89a84d9 100644 --- a/lib/src/visitor/recursive_statement.dart +++ b/lib/src/visitor/recursive_statement.dart @@ -71,8 +71,6 @@ mixin RecursiveStatementVisitor implements StatementVisitor { void visitMixinRule(MixinRule node) => visitCallableDeclaration(node); - void visitNestRule(NestRule node) => visitChildren(node.children); - void visitReturnRule(ReturnRule node) {} void visitSilentComment(SilentComment node) {} diff --git a/lib/src/visitor/statement_search.dart b/lib/src/visitor/statement_search.dart index 3fd31863d..6abd7fe9f 100644 --- a/lib/src/visitor/statement_search.dart +++ b/lib/src/visitor/statement_search.dart @@ -61,8 +61,6 @@ mixin StatementSearchVisitor implements StatementVisitor { T? visitMixinRule(MixinRule node) => visitCallableDeclaration(node); - T? visitNestRule(NestRule node) => visitChildren(node.children); - T? visitReturnRule(ReturnRule node) => null; T? visitSilentComment(SilentComment node) => null; diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 3ea002075..006fbe277 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.4.7 + +* No user-visible changes. + ## 10.4.6 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index bcd120d20..a2a260141 100644 --- a/pkg/sass_api/pubspec.yaml +++ b/pkg/sass_api/pubspec.yaml @@ -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: 10.4.6 +version: 10.4.7 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass diff --git a/pubspec.yaml b/pubspec.yaml index fd753e22b..ad62bb19b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 From 5b36c15c32ab71b91089d92d521c73fa61db34cf Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 8 Jul 2024 18:38:07 -0700 Subject: [PATCH 4/4] Bump sass_api --- pkg/sass_api/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index a2a260141..cba35a261 100644 --- a/pkg/sass_api/pubspec.yaml +++ b/pkg/sass_api/pubspec.yaml @@ -10,7 +10,7 @@ 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"