From 79742402b462c6aa9cb8ab3bcb76ce3afdc0d4ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Israel=20Ortiz=20Garc=C3=ADa?= Date: Wed, 2 Jul 2025 13:37:37 -0700 Subject: [PATCH 1/5] Fix crash when mixin @import with @use Fixes https://github.com/sass/dart-sass/issues/2588 --- lib/src/visitor/async_evaluate.dart | 27 ++++++++++++++++++++------- lib/src/visitor/evaluate.dart | 26 ++++++++++++++++++-------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index c1db0e72e..dff65ad26 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -208,6 +208,12 @@ final class _EvaluateVisitor ModifiableCssParentNode? __parent; + /// The original parent node for a stylesheet that was loaded with @import. + /// + /// This value is only set when a file uses `@import` in combination with + /// non-built-in Sass modules. + ModifiableCssParentNode? _importParent; + /// The name of the current declaration parent. String? _declarationName; @@ -1321,7 +1327,12 @@ final class _EvaluateVisitor } Future visitDeclaration(Declaration node) async { - if (_styleRule == null && !_inUnknownAtRule && !_inKeyframes) { + // If a stylesheet is @imported inside a style rule, declarations from that + // imported sheet are parented by the outer style rule. + var parent = _parent.parent == null ? _importParent : _parent; + + if ((_styleRule == null && !_inUnknownAtRule && !_inKeyframes) || + parent == null) { throw _exception( "Declarations may only be used within style rules.", node.span, @@ -1334,14 +1345,14 @@ final class _EvaluateVisitor ); } - var siblings = _parent.parent!.children; + var siblings = parent.parent?.children ?? []; var interleavedRules = []; - if (siblings.last != _parent && - // Reproduce this condition from [_warn] so that we don't add anything to - // [interleavedRules] for declarations in dependencies. + if (siblings.last != parent && + // Reproduce this condition from [_warn] so that we don't add anything + // to [interleavedRules] for declarations in dependencies. !(_quietDeps && _inDependency)) { loop: - for (var sibling in siblings.skip(siblings.indexOf(_parent) + 1)) { + for (var sibling in siblings.skip(siblings.indexOf(parent) + 1)) { switch (sibling) { case CssComment(): continue loop; @@ -1387,7 +1398,7 @@ final class _EvaluateVisitor _isEmptyList(value) || // Custom properties are allowed to have empty values, per spec. name.value.startsWith('--')) { - _parent.addChild( + parent.addChild( ModifiableCssDeclaration( name, CssValue(value, expression.span), @@ -1895,6 +1906,7 @@ final class _EvaluateVisitor _stylesheet = stylesheet; if (loadsUserDefinedModules) { _root = ModifiableCssStylesheet(stylesheet.span); + _importParent = _parent; _parent = _root; _endOfImports = 0; _outOfOrderImports = null; @@ -1915,6 +1927,7 @@ final class _EvaluateVisitor if (loadsUserDefinedModules) { _root = oldRoot; _parent = oldParent; + _importParent = null; _endOfImports = oldEndOfImports; _outOfOrderImports = oldOutOfOrderImports; } diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 5727e56aa..cff19b686 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: a3068d04660dd2bed34b884aa6e1a21d423dc4e5 +// Checksum: 25e98f7f4a04108e924c63b63b1db844637a66e0 // // ignore_for_file: unused_import @@ -216,6 +216,9 @@ final class _EvaluateVisitor ModifiableCssParentNode? __parent; + /// The original parent node for a stylesheet that was loaded with @import. + ModifiableCssParentNode? _importParent; + /// The name of the current declaration parent. String? _declarationName; @@ -1329,7 +1332,12 @@ final class _EvaluateVisitor } Value? visitDeclaration(Declaration node) { - if (_styleRule == null && !_inUnknownAtRule && !_inKeyframes) { + // If a stylesheet is @imported inside a style rule, declarations from that + // imported sheet are parented by the outer style rule. + var parent = _parent.parent == null ? _importParent : _parent; + + if ((_styleRule == null && !_inUnknownAtRule && !_inKeyframes) || + parent == null) { throw _exception( "Declarations may only be used within style rules.", node.span, @@ -1342,14 +1350,14 @@ final class _EvaluateVisitor ); } - var siblings = _parent.parent!.children; + var siblings = parent.parent?.children ?? []; var interleavedRules = []; - if (siblings.last != _parent && - // Reproduce this condition from [_warn] so that we don't add anything to - // [interleavedRules] for declarations in dependencies. + if (siblings.last != parent && + // Reproduce this condition from [_warn] so that we don't add anything + // to [interleavedRules] for declarations in dependencies. !(_quietDeps && _inDependency)) { loop: - for (var sibling in siblings.skip(siblings.indexOf(_parent) + 1)) { + for (var sibling in siblings.skip(siblings.indexOf(parent) + 1)) { switch (sibling) { case CssComment(): continue loop; @@ -1395,7 +1403,7 @@ final class _EvaluateVisitor _isEmptyList(value) || // Custom properties are allowed to have empty values, per spec. name.value.startsWith('--')) { - _parent.addChild( + parent.addChild( ModifiableCssDeclaration( name, CssValue(value, expression.span), @@ -1903,6 +1911,7 @@ final class _EvaluateVisitor _stylesheet = stylesheet; if (loadsUserDefinedModules) { _root = ModifiableCssStylesheet(stylesheet.span); + _importParent = _parent; _parent = _root; _endOfImports = 0; _outOfOrderImports = null; @@ -1923,6 +1932,7 @@ final class _EvaluateVisitor if (loadsUserDefinedModules) { _root = oldRoot; _parent = oldParent; + _importParent = null; _endOfImports = oldEndOfImports; _outOfOrderImports = oldOutOfOrderImports; } From 4b9205a975963170bf5e246cc62b6667f3f75b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Israel=20Ortiz=20Garc=C3=ADa?= Date: Wed, 2 Jul 2025 14:08:21 -0700 Subject: [PATCH 2/5] dart run grind --- lib/src/visitor/evaluate.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index cff19b686..6e3e54718 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: 25e98f7f4a04108e924c63b63b1db844637a66e0 +// Checksum: d02e86d11c5ca310e2402c60935ccf301d3cfbc2 // // ignore_for_file: unused_import @@ -217,6 +217,9 @@ final class _EvaluateVisitor ModifiableCssParentNode? __parent; /// The original parent node for a stylesheet that was loaded with @import. + /// + /// This value is only set when a file uses `@import` in combination with + /// non-built-in Sass modules. ModifiableCssParentNode? _importParent; /// The name of the current declaration parent. From 9952e2922a2fa941c9befa7186aa8c1c8cd00c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Israel=20Ortiz=20Garc=C3=ADa?= Date: Wed, 2 Jul 2025 14:22:51 -0700 Subject: [PATCH 3/5] From af92d9368981a68cc99a4e4855957d3159f4c11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Israel=20Ortiz=20Garc=C3=ADa?= Date: Wed, 9 Jul 2025 11:09:18 -0700 Subject: [PATCH 4/5] add changelog and bump version --- CHANGELOG.md | 6 ++++++ pkg/sass-parser/CHANGELOG.md | 4 ++++ pkg/sass-parser/package.json | 2 +- pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 2 +- 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b2ccc65f..68ae2fe45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.89.3 + +* Fixed a crash when `@import` was nested in a style rule and loaded a Sass file + that `@use`s a non-built-in module and a top-level `@include` that emits + declarations. + ## 1.89.2 ### Embedded Host diff --git a/pkg/sass-parser/CHANGELOG.md b/pkg/sass-parser/CHANGELOG.md index ef9e27284..1c1862ee3 100644 --- a/pkg/sass-parser/CHANGELOG.md +++ b/pkg/sass-parser/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.25 + +* No user-visible changes. + ## 0.4.24 * No user-visible changes. diff --git a/pkg/sass-parser/package.json b/pkg/sass-parser/package.json index f3d816655..128c4b1e2 100644 --- a/pkg/sass-parser/package.json +++ b/pkg/sass-parser/package.json @@ -1,6 +1,6 @@ { "name": "sass-parser", - "version": "0.4.24", + "version": "0.4.25", "description": "A PostCSS-compatible wrapper of the official Sass parser", "repository": "sass/sass", "author": "Google Inc.", diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index e034f36f9..cb5bdf3c5 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 15.7.2 + +* No user-visible changes. + ## 15.7.1 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index a0ad29aca..787bb1575 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: 15.7.1 +version: 15.7.2 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.6.0 <4.0.0" dependencies: - sass: 1.89.2 + sass: 1.89.3 dev_dependencies: dartdoc: ^8.0.14 diff --git a/pubspec.yaml b/pubspec.yaml index 039be9860..aada25374 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.89.2 +version: 1.89.3 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 7cdf182721ce3b76ba2dd8044c80507465780cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Israel=20Ortiz=20Garc=C3=ADa?= Date: Wed, 16 Jul 2025 18:57:30 -0700 Subject: [PATCH 5/5] add backticks to @import --- lib/src/visitor/async_evaluate.dart | 2 +- lib/src/visitor/evaluate.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index dff65ad26..3938734b4 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -208,7 +208,7 @@ final class _EvaluateVisitor ModifiableCssParentNode? __parent; - /// The original parent node for a stylesheet that was loaded with @import. + /// The original parent node for a stylesheet that was loaded with `@import`. /// /// This value is only set when a file uses `@import` in combination with /// non-built-in Sass modules. diff --git a/lib/src/visitor/evaluate.dart b/lib/src/visitor/evaluate.dart index 6e3e54718..040f4d94c 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: d02e86d11c5ca310e2402c60935ccf301d3cfbc2 +// Checksum: 0db2da7b7facb3c5c79cfba1d6829d18a5de5cdd // // ignore_for_file: unused_import @@ -216,7 +216,7 @@ final class _EvaluateVisitor ModifiableCssParentNode? __parent; - /// The original parent node for a stylesheet that was loaded with @import. + /// The original parent node for a stylesheet that was loaded with `@import`. /// /// This value is only set when a file uses `@import` in combination with /// non-built-in Sass modules.