From 21eeb4d9428d1808487223a379c036a019f98487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 30 May 2024 16:25:17 -0700 Subject: [PATCH 01/25] Parse Deprecation.forVersion on compiler side (#2248) --- CHANGELOG.md | 10 ++++++ lib/src/embedded/compilation_dispatcher.dart | 38 +++++++++++++------- pkg/sass_api/CHANGELOG.md | 4 +++ pkg/sass_api/pubspec.yaml | 4 +-- pubspec.yaml | 2 +- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d06b712fd..41b6c0862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 1.77.4 + +### Embedded Sass + +* Support passing `Version` input for `fatalDeprecations` as string over + embedded protocol. + +* Fix a bug in the JS Embedded Host where `Version` could be incorrectly accepted + as input for `silenceDeprecations` and `futureDeprecations` in pure JS. + ## 1.77.3 ### Dart API diff --git a/lib/src/embedded/compilation_dispatcher.dart b/lib/src/embedded/compilation_dispatcher.dart index 675216022..e8c3764b5 100644 --- a/lib/src/embedded/compilation_dispatcher.dart +++ b/lib/src/embedded/compilation_dispatcher.dart @@ -7,10 +7,10 @@ import 'dart:io'; import 'dart:isolate'; import 'dart:typed_data'; -import 'package:collection/collection.dart'; import 'package:native_synchronization/mailbox.dart'; import 'package:path/path.dart' as p; import 'package:protobuf/protobuf.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'package:sass/sass.dart' as sass; import 'package:sass/src/importer/node_package.dart' as npi; @@ -125,20 +125,34 @@ final class CompilationDispatcher { : EmbeddedLogger(this, color: request.alertColor, ascii: request.alertAscii); - sass.Deprecation? deprecationOrWarn(String id) { - var deprecation = sass.Deprecation.fromId(id); - if (deprecation == null) { - logger.warn('Invalid deprecation "$id".'); - } - return deprecation; + Iterable? parseDeprecationsOrWarn( + Iterable deprecations, + {bool supportVersions = false}) { + return () sync* { + for (var item in deprecations) { + var deprecation = sass.Deprecation.fromId(item); + if (deprecation == null) { + if (supportVersions) { + try { + yield* sass.Deprecation.forVersion(Version.parse(item)); + } on FormatException { + logger.warn('Invalid deprecation id or version "$item".'); + } + } else { + logger.warn('Invalid deprecation id "$item".'); + } + } else { + yield deprecation; + } + } + }(); } - var fatalDeprecations = - request.fatalDeprecation.map(deprecationOrWarn).whereNotNull(); + var fatalDeprecations = parseDeprecationsOrWarn(request.fatalDeprecation, + supportVersions: true); var silenceDeprecations = - request.silenceDeprecation.map(deprecationOrWarn).whereNotNull(); - var futureDeprecations = - request.futureDeprecation.map(deprecationOrWarn).whereNotNull(); + parseDeprecationsOrWarn(request.silenceDeprecation); + var futureDeprecations = parseDeprecationsOrWarn(request.futureDeprecation); try { var importers = request.importers.map((importer) => diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index e82b07c57..0006705c9 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.4.4 + +* No user-visible changes. + ## 10.4.3 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 0943de732..c184e5f24 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.3 +version: 10.4.4 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - sass: 1.77.3 + sass: 1.77.4 dev_dependencies: dartdoc: ">=6.0.0 <9.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5260eba17..c8656f802 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.77.3 +version: 1.77.4 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 53b9ead5aaf8eb83223bc918eac6e2bb68c41d1c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 31 May 2024 14:38:56 -0700 Subject: [PATCH 02/25] Regenerate protobuf as part of default task (#2257) --- tool/grind.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/grind.dart b/tool/grind.dart index 7af45b438..5f71995f5 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -130,7 +130,7 @@ void main(List args) { } @DefaultTask('Compile async code and reformat.') -@Depends(format, synchronize, deprecations) +@Depends(format, synchronize, deprecations, protobuf) void all() {} @Task('Run the Dart formatter.') From 5ddd7fc723d5be220a38882010469bbd7390a3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 6 Jun 2024 13:15:23 -0700 Subject: [PATCH 03/25] Enable AOT build for linux-riscv64-musl (#2258) --- .github/workflows/build-linux-musl.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-linux-musl.yml b/.github/workflows/build-linux-musl.yml index 5f4ba2639..024820e34 100644 --- a/.github/workflows/build-linux-musl.yml +++ b/.github/workflows/build-linux-musl.yml @@ -26,9 +26,8 @@ jobs: # https://gitlab.com/qemu-project/qemu/-/issues/1729 - arch: arm platform: linux/amd64 # linux/arm/v7 - # There is no docker image for riscv64 dart-sdk, build kernel snapshot instead. - arch: riscv64 - platform: linux/amd64 # linux/riscv64 + platform: linux/riscv64 steps: - uses: actions/checkout@v4 From ecff05dfefc2da3f7e462c2a173ac12beeb51100 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 11 Jun 2024 16:05:41 -0700 Subject: [PATCH 04/25] Remove the heuristic where long selector lists wouldn't be trimmed (#2255) Testing this against the `@extend`-heavy stylesheets in vinceliuice/Colloid-gtk-theme, trimming everywhere actually *improves* performance rather than reducing it. --- CHANGELOG.md | 4 ++++ lib/src/ast/selector/compound.dart | 12 ++++++++++ lib/src/ast/selector/pseudo.dart | 4 ++++ lib/src/ast/selector/simple.dart | 10 ++++++++ lib/src/extend/extension_store.dart | 7 ------ lib/src/extend/functions.dart | 36 ++++++++++++++++++----------- pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 2 +- 9 files changed, 59 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41b6c0862..5f299e042 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.77.5 + +* Fully trim redundant selectors generated by `@extend`. + ## 1.77.4 ### Embedded Sass diff --git a/lib/src/ast/selector/compound.dart b/lib/src/ast/selector/compound.dart index bcc2beb33..9fbc8d397 100644 --- a/lib/src/ast/selector/compound.dart +++ b/lib/src/ast/selector/compound.dart @@ -42,6 +42,18 @@ final class CompoundSelector extends Selector { SimpleSelector? get singleSimple => components.length == 1 ? components.first : null; + /// Whether any simple selector in this contains a selector that requires + /// complex non-local reasoning to determine whether it's a super- or + /// sub-selector. + /// + /// This includes both pseudo-elements and pseudo-selectors that take + /// selectors as arguments. + /// + /// #nodoc + @internal + late final bool hasComplicatedSuperselectorSemantics = components + .any((component) => component.hasComplicatedSuperselectorSemantics); + CompoundSelector(Iterable components, super.span) : components = List.unmodifiable(components) { if (this.components.isEmpty) { diff --git a/lib/src/ast/selector/pseudo.dart b/lib/src/ast/selector/pseudo.dart index 44a263d15..e632c651e 100644 --- a/lib/src/ast/selector/pseudo.dart +++ b/lib/src/ast/selector/pseudo.dart @@ -67,6 +67,10 @@ final class PseudoSelector extends SimpleSelector { bool get isHostContext => isClass && name == 'host-context' && selector != null; + @internal + bool get hasComplicatedSuperselectorSemantics => + isElement || selector != null; + /// The non-selector argument passed to this selector. /// /// This is `null` if there's no argument. If [argument] and [selector] are diff --git a/lib/src/ast/selector/simple.dart b/lib/src/ast/selector/simple.dart index d8ae7864d..5ac2f0e53 100644 --- a/lib/src/ast/selector/simple.dart +++ b/lib/src/ast/selector/simple.dart @@ -34,6 +34,16 @@ abstract base class SimpleSelector extends Selector { /// sequence will contain 1000 simple selectors. int get specificity => 1000; + /// Whether this requires complex non-local reasoning to determine whether + /// it's a super- or sub-selector. + /// + /// This includes both pseudo-elements and pseudo-selectors that take + /// selectors as arguments. + /// + /// #nodoc + @internal + bool get hasComplicatedSuperselectorSemantics => false; + SimpleSelector(super.span); /// Parses a simple selector from [contents]. diff --git a/lib/src/extend/extension_store.dart b/lib/src/extend/extension_store.dart index 3637b5aac..2bbc2a9cb 100644 --- a/lib/src/extend/extension_store.dart +++ b/lib/src/extend/extension_store.dart @@ -901,13 +901,6 @@ class ExtensionStore { // document, and thus should never be trimmed. List _trim(List selectors, bool isOriginal(ComplexSelector complex)) { - // Avoid truly horrific quadratic behavior. - // - // TODO(nweiz): I think there may be a way to get perfect trimming without - // going quadratic by building some sort of trie-like data structure that - // can be used to look up superselectors. - if (selectors.length > 100) return selectors; - // This is n² on the sequences, but only comparing between separate // sequences should limit the quadratic behavior. We iterate from last to // first and reverse the result so that, if two selectors are identical, we diff --git a/lib/src/extend/functions.dart b/lib/src/extend/functions.dart index 01d70d248..2fb1f2555 100644 --- a/lib/src/extend/functions.dart +++ b/lib/src/extend/functions.dart @@ -646,24 +646,28 @@ bool complexIsSuperselector(List complex1, var component1 = complex1[i1]; if (component1.combinators.length > 1) return false; if (remaining1 == 1) { - var parents = complex2.sublist(i2, complex2.length - 1); - if (parents.any((parent) => parent.combinators.length > 1)) return false; - - return compoundIsSuperselector( - component1.selector, complex2.last.selector, - parents: parents); + if (complex2.any((parent) => parent.combinators.length > 1)) { + return false; + } else { + return compoundIsSuperselector( + component1.selector, complex2.last.selector, + parents: component1.selector.hasComplicatedSuperselectorSemantics + ? complex2.sublist(i2, complex2.length - 1) + : null); + } } // Find the first index [endOfSubselector] in [complex2] such that // `complex2.sublist(i2, endOfSubselector + 1)` is a subselector of // [component1.selector]. var endOfSubselector = i2; - List? parents; while (true) { var component2 = complex2[endOfSubselector]; if (component2.combinators.length > 1) return false; if (compoundIsSuperselector(component1.selector, component2.selector, - parents: parents)) { + parents: component1.selector.hasComplicatedSuperselectorSemantics + ? complex2.sublist(i2, endOfSubselector) + : null)) { break; } @@ -675,13 +679,10 @@ bool complexIsSuperselector(List complex1, // to match. return false; } - - parents ??= []; - parents.add(component2); } if (!_compatibleWithPreviousCombinator( - previousCombinator, parents ?? const [])) { + previousCombinator, complex2.take(endOfSubselector).skip(i2))) { return false; } @@ -717,8 +718,8 @@ bool complexIsSuperselector(List complex1, /// Returns whether [parents] are valid intersitial components between one /// complex superselector and another, given that the earlier complex /// superselector had the combinator [previous]. -bool _compatibleWithPreviousCombinator( - CssValue? previous, List parents) { +bool _compatibleWithPreviousCombinator(CssValue? previous, + Iterable parents) { if (parents.isEmpty) return true; if (previous == null) return true; @@ -754,6 +755,13 @@ bool _isSupercombinator( bool compoundIsSuperselector( CompoundSelector compound1, CompoundSelector compound2, {Iterable? parents}) { + if (!compound1.hasComplicatedSuperselectorSemantics && + !compound2.hasComplicatedSuperselectorSemantics) { + if (compound1.components.length > compound2.components.length) return false; + return compound1.components + .every((simple1) => compound2.components.any(simple1.isSuperselector)); + } + // Pseudo elements effectively change the target of a compound selector rather // than narrowing the set of elements to which it applies like other // selectors. As such, if either selector has a pseudo element, they both must diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 0006705c9..373024d43 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.4.5 + +* No user-visible changes. + ## 10.4.4 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index c184e5f24..69c311a02 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.4 +version: 10.4.5 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - sass: 1.77.4 + sass: 1.77.5 dev_dependencies: dartdoc: ">=6.0.0 <9.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c8656f802..668acf389 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.77.4 +version: 1.77.5 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From a1b372eaf1188e34e1bda2628db45ca17fd621c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Tue, 11 Jun 2024 16:39:13 -0700 Subject: [PATCH 05/25] Enable AOT build for linux-riscv64 (#2260) --- .github/workflows/build-linux.yml | 34 ++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index c8f5ddd41..308c5ec58 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -22,10 +22,8 @@ jobs: platform: linux/arm/v7 - arch: arm64 platform: linux/arm64 - # There is no docker image for riscv64 dart-sdk, build kernel snapshot instead. - # https://github.com/dart-lang/dart-docker/issues/96#issuecomment-1669860829 - arch: riscv64 - platform: linux/amd64 # linux/riscv64 + platform: linux/riscv64 steps: - uses: actions/checkout@v4 @@ -46,6 +44,7 @@ jobs: EOF - name: Build + if: matrix.arch != 'riscv64' run: | docker run --rm -i \ --platform ${{ matrix.platform }} \ @@ -57,6 +56,35 @@ jobs: dart run grinder pkg-standalone-linux-${{ matrix.arch }} EOF + # https://github.com/dart-lang/dart-docker/issues/96#issuecomment-1669860829 + # There is no official riscv64 dart container image yet, build on debian:unstable instead. + # The setup is adopted from: https://github.com/dart-lang/dart-docker/blob/main/Dockerfile-debian.template + - name: Build riscv64 + if: matrix.arch == 'riscv64' + run: | + DART_CHANNEL=stable + DART_VERSION=$(curl -fsSL https://storage.googleapis.com/dart-archive/channels/$DART_CHANNEL/release/latest/VERSION | yq .version) + curl -fsSLO https://storage.googleapis.com/dart-archive/channels/$DART_CHANNEL/release/$DART_VERSION/sdk/dartsdk-linux-${{ matrix.arch }}-release.zip + + docker run --rm -i \ + --platform ${{ matrix.platform }} \ + --volume "$PWD:$PWD" \ + --workdir "$PWD" \ + docker.io/library/debian:unstable-slim <<'EOF' + set -e + apt-get update + apt-get install -y --no-install-recommends ca-certificates curl dnsutils git openssh-client unzip + + export DART_SDK=/usr/lib/dart + export PATH=$DART_SDK/bin:/root/.pub-cache/bin:$PATH + + SDK="dartsdk-linux-${{ matrix.arch }}-release.zip" + unzip "$SDK" && mv dart-sdk "$DART_SDK" && rm "$SDK" + + dart pub get + dart run grinder pkg-standalone-linux-${{ matrix.arch }} + EOF + - name: Upload Artifact uses: actions/upload-artifact@v4 with: From cf6f9d0842fbbc786d8b2908f5948c6d282e1b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 12 Jun 2024 13:49:16 -0700 Subject: [PATCH 06/25] Build AOT releases with native arm64 runners (#2262) --- .github/workflows/build-android.yml | 7 ++++++- .github/workflows/build-linux-musl.yml | 13 +++++++------ .github/workflows/build-linux.yml | 13 +++++++++---- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index e8ccdd7dc..90405bbd0 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -8,7 +8,7 @@ jobs: build: name: Build - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} strategy: fail-fast: false @@ -16,19 +16,24 @@ jobs: include: - arch: x64 lib: lib64 + runner: ubuntu-latest platform: linux/amd64 - arch: ia32 lib: lib + runner: ubuntu-latest platform: linux/amd64 - arch: arm64 lib: lib64 + runner: linux-arm64 platform: linux/arm64 - arch: arm lib: lib + runner: linux-arm64 platform: linux/arm64 # There is no docker image for riscv64 dart-sdk, build kernel snapshot instead. - arch: riscv64 lib: lib64 + runner: ubuntu-latest platform: linux/amd64 # linux/riscv64 steps: diff --git a/.github/workflows/build-linux-musl.yml b/.github/workflows/build-linux-musl.yml index 024820e34..aa33b4eff 100644 --- a/.github/workflows/build-linux-musl.yml +++ b/.github/workflows/build-linux-musl.yml @@ -8,25 +8,26 @@ jobs: build: name: Build - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: include: - arch: x64 + runner: ubuntu-latest platform: linux/amd64 - arch: ia32 + runner: ubuntu-latest platform: linux/386 - arch: arm64 + runner: linux-arm64 platform: linux/arm64 - # There is a bug in qemu's mremap causing pthread_getattr_np in musl to stuck in a loop on arm. - # Unless qemu fixes the bug or we get a real linux-arm runner, we cannot build aot-snapshot - # for arm on CI. So, we create a kernel snapshot for arm build in amd64 container instead. - # https://gitlab.com/qemu-project/qemu/-/issues/1729 - arch: arm - platform: linux/amd64 # linux/arm/v7 + runner: linux-arm64 + platform: linux/arm/v7 - arch: riscv64 + runner: ubuntu-latest platform: linux/riscv64 steps: diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 308c5ec58..bf28d809f 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -8,21 +8,26 @@ jobs: build: name: Build - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: include: - arch: x64 + runner: ubuntu-latest platform: linux/amd64 - arch: ia32 - platform: linux/amd64 - - arch: arm - platform: linux/arm/v7 + runner: ubuntu-latest + platform: linux/386 - arch: arm64 + runner: linux-arm64 platform: linux/arm64 + - arch: arm + runner: linux-arm64 + platform: linux/arm/v7 - arch: riscv64 + runner: ubuntu-latest platform: linux/riscv64 steps: diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 3dff23d3b..660ceadfa 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -17,7 +17,7 @@ jobs: - arch: x64 runner: macos-13 - arch: arm64 - runner: macos-14 + runner: macos-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index ba9ff8bb1..86ea17c22 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,7 +19,7 @@ jobs: - arch: ia32 runner: windows-latest - arch: arm64 - runner: windows-latest + runner: windows-arm64 steps: - uses: actions/checkout@v4 From 7aae1e67ed3322c1caab1c8ebb2f5c28ff0b2e0b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 17 Jun 2024 13:41:49 -0700 Subject: [PATCH 07/25] Fix a bug where comments were incorrectly forbidden in some cases (#2264) --- CHANGELOG.md | 5 +++++ lib/src/parse/stylesheet.dart | 20 ++++++++++++++------ pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 2 +- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f299e042..5229a0b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.77.6 + +* Fix a few cases where comments and occasionally even whitespace wasn't allowed + between the end of Sass statements and the following semicolon. + ## 1.77.5 * Fully trim redundant selectors generated by `@extend`. diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index e372e3912..046c56e6f 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -770,10 +770,15 @@ abstract class StylesheetParser extends Parser { scanner.spanFrom(start)); } + var beforeWhitespace = scanner.location; whitespace(); - var arguments = scanner.peekChar() == $lparen - ? _argumentInvocation(mixin: true) - : ArgumentInvocation.empty(scanner.emptySpan); + ArgumentInvocation arguments; + if (scanner.peekChar() == $lparen) { + arguments = _argumentInvocation(mixin: true); + whitespace(); + } else { + arguments = ArgumentInvocation.empty(beforeWhitespace.pointSpan()); + } expectStatementSeparator("@content rule"); return ContentRule(arguments, scanner.spanFrom(start)); @@ -835,7 +840,10 @@ abstract class StylesheetParser extends Parser { var value = almostAnyValue(); var optional = scanner.scanChar($exclamation); - if (optional) expectIdentifier("optional"); + if (optional) { + expectIdentifier("optional"); + whitespace(); + } expectStatementSeparator("@extend rule"); return ExtendRule(value, scanner.spanFrom(start), optional: optional); } @@ -954,6 +962,7 @@ abstract class StylesheetParser extends Parser { } var configuration = _configuration(allowGuarded: true); + whitespace(); expectStatementSeparator("@forward rule"); var span = scanner.spanFrom(start); @@ -1419,8 +1428,7 @@ abstract class StylesheetParser extends Parser { var namespace = _useNamespace(url, start); whitespace(); var configuration = _configuration(); - - expectStatementSeparator("@use rule"); + whitespace(); var span = scanner.spanFrom(start); if (!_isUseAllowed) { diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 373024d43..3ea002075 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.4.6 + +* No user-visible changes. + ## 10.4.5 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 69c311a02..bcd120d20 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.5 +version: 10.4.6 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - sass: 1.77.5 + sass: 1.77.6 dev_dependencies: dartdoc: ">=6.0.0 <9.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 668acf389..936b32092 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.77.5 +version: 1.77.6 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 860eb5ae2b4701226cb098632205d94d6cb41c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Mon, 17 Jun 2024 16:26:29 -0700 Subject: [PATCH 08/25] Fix linux-ia32, linux-arm-musl, and windows-arm64 releases (#2265) --- .github/workflows/build-linux-musl.yml | 4 ++-- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-windows.yml | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-linux-musl.yml b/.github/workflows/build-linux-musl.yml index aa33b4eff..27bc592a7 100644 --- a/.github/workflows/build-linux-musl.yml +++ b/.github/workflows/build-linux-musl.yml @@ -19,7 +19,7 @@ jobs: platform: linux/amd64 - arch: ia32 runner: ubuntu-latest - platform: linux/386 + platform: linux/amd64 - arch: arm64 runner: linux-arm64 platform: linux/arm64 @@ -51,7 +51,7 @@ jobs: - name: Build run: | docker run --rm -i \ - --platform ${{ matrix.arch == 'arm' && 'linux/amd64' || matrix.platform }} \ + --platform ${{ matrix.platform }} \ --volume "$PWD:$PWD" \ --workdir "$PWD" \ ghcr.io/dart-musl/dart <<'EOF' diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index bf28d809f..4f0d3450c 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -19,7 +19,7 @@ jobs: platform: linux/amd64 - arch: ia32 runner: ubuntu-latest - platform: linux/386 + platform: linux/amd64 - arch: arm64 runner: linux-arm64 platform: linux/arm64 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 86ea17c22..b2011ce2f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,7 +19,8 @@ jobs: - arch: ia32 runner: windows-latest - arch: arm64 - runner: windows-arm64 + # TODO: switch the following to windows-arm64, blocked by https://github.com/dart-lang/setup-dart/issues/118 + runner: windows-latest # windows-arm64 steps: - uses: actions/checkout@v4 From 04b6251cedca92323095d8b8f9e13fbc5a651502 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 20 Jun 2024 13:17:32 -0700 Subject: [PATCH 09/25] Parse silent comments in `_interpolatedDeclarationValue()` (#2266) Closes #2263 --- CHANGELOG.md | 7 +++ lib/src/parse/parser.dart | 3 +- lib/src/parse/stylesheet.dart | 86 +++++++++++++++++++++++++++-------- pubspec.yaml | 2 +- 4 files changed, 76 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5229a0b08..edce7c487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.77.7 + +* **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 + CSS output. + ## 1.77.6 * Fix a few cases where comments and occasionally even whitespace wasn't allowed diff --git a/lib/src/parse/parser.dart b/lib/src/parse/parser.dart index a16b871e7..49dd72fe4 100644 --- a/lib/src/parse/parser.dart +++ b/lib/src/parse/parser.dart @@ -133,7 +133,8 @@ class Parser { whitespace(); } - /// Consumes and ignores a silent (Sass-style) comment. + /// Consumes and ignores a single silent (Sass-style) comment, not including + /// the trailing newline. /// /// Returns whether the comment was consumed. @protected diff --git a/lib/src/parse/stylesheet.dart b/lib/src/parse/stylesheet.dart index 046c56e6f..eace75790 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -380,7 +380,8 @@ abstract class StylesheetParser extends Parser { // Parse custom properties as declarations no matter what. var name = nameBuffer.interpolation(scanner.spanFrom(start, beforeColon)); if (name.initialPlain.startsWith('--')) { - var value = StringExpression(_interpolatedDeclarationValue()); + var value = StringExpression( + _interpolatedDeclarationValue(silentComments: false)); expectStatementSeparator("custom property"); return Declaration(name, value, scanner.spanFrom(start)); } @@ -532,7 +533,8 @@ abstract class StylesheetParser extends Parser { scanner.expectChar($colon); if (parseCustomProperties && name.initialPlain.startsWith('--')) { - var value = StringExpression(_interpolatedDeclarationValue()); + var value = StringExpression( + _interpolatedDeclarationValue(silentComments: false)); expectStatementSeparator("custom property"); return Declaration(name, value, scanner.spanFrom(start)); } @@ -1550,7 +1552,7 @@ abstract class StylesheetParser extends Parser { Interpolation? value; if (scanner.peekChar() != $exclamation && !atEndOfStatement()) { - value = almostAnyValue(); + value = _interpolatedDeclarationValue(allowOpenBrace: false); } AtRule rule; @@ -1575,7 +1577,7 @@ abstract class StylesheetParser extends Parser { /// This declares a return type of [Statement] so that it can be returned /// within case statements. Statement _disallowedAtRule(LineScannerState start) { - almostAnyValue(); + _interpolatedDeclarationValue(allowEmpty: true, allowOpenBrace: false); error("This at-rule is not allowed here.", scanner.spanFrom(start)); } @@ -2748,13 +2750,11 @@ abstract class StylesheetParser extends Parser { /// /// Differences from [_interpolatedDeclarationValue] include: /// - /// * This does not balance brackets. + /// * This always stops at curly braces. /// /// * This does not interpret backslashes, since the text is expected to be /// re-parsed. /// - /// * This supports Sass-style single-line comments. - /// /// * This does not compress adjacent whitespace characters. @protected Interpolation almostAnyValue({bool omitComments = false}) { @@ -2773,11 +2773,21 @@ abstract class StylesheetParser extends Parser { buffer.addInterpolation(interpolatedString().asInterpolation()); case $slash: - var commentStart = scanner.position; - if (scanComment()) { - if (!omitComments) buffer.write(scanner.substring(commentStart)); - } else { - buffer.writeCharCode(scanner.readChar()); + switch (scanner.peekChar(1)) { + case $asterisk when !omitComments: + buffer.write(rawText(loudComment)); + + case $asterisk: + loudComment(); + + case $slash when !omitComments: + buffer.write(rawText(silentComment)); + + case $slash: + silentComment(); + + case _: + buffer.writeCharCode(scanner.readChar()); } case $hash when scanner.peekChar(1) == $lbrace: @@ -2794,12 +2804,17 @@ abstract class StylesheetParser extends Parser { case $u || $U: var beforeUrl = scanner.state; - if (!scanIdentifier("url")) { - buffer.writeCharCode(scanner.readChar()); + var identifier = this.identifier(); + if (identifier != "url" && + // This isn't actually a standard CSS feature, but it was + // supported by the old `@document` rule so we continue to support + // it for backwards-compatibility. + identifier != "url-prefix") { + buffer.write(identifier); continue loop; } - if (_tryUrlContents(beforeUrl) case var contents?) { + if (_tryUrlContents(beforeUrl, name: identifier) case var contents?) { buffer.addInterpolation(contents); } else { scanner.state = beforeUrl; @@ -2830,11 +2845,19 @@ abstract class StylesheetParser extends Parser { /// /// If [allowColon] is `false`, this stops at top-level colons. /// + /// If [allowOpenBrace] is `false`, this stops at top-level colons. + /// + /// If [silentComments] is `true`, this will parse silent comments as + /// comments. Otherwise, it will preserve two adjacent slashes and emit them + /// to CSS. + /// /// Unlike [declarationValue], this allows interpolation. Interpolation _interpolatedDeclarationValue( {bool allowEmpty = false, bool allowSemicolon = false, - bool allowColon = true}) { + bool allowColon = true, + bool allowOpenBrace = true, + bool silentComments = true}) { // NOTE: this logic is largely duplicated in Parser.declarationValue. Most // changes here should be mirrored there. @@ -2854,7 +2877,22 @@ abstract class StylesheetParser extends Parser { buffer.addInterpolation(interpolatedString().asInterpolation()); wroteNewline = false; - case $slash when scanner.peekChar(1) == $asterisk: + case $slash: + switch (scanner.peekChar(1)) { + case $asterisk: + buffer.write(rawText(loudComment)); + wroteNewline = false; + + case $slash when silentComments: + silentComment(); + wroteNewline = false; + + case _: + buffer.writeCharCode(scanner.readChar()); + wroteNewline = false; + } + + case $slash when silentComments && scanner.peekChar(1) == $slash: buffer.write(rawText(loudComment)); wroteNewline = false; @@ -2882,6 +2920,9 @@ abstract class StylesheetParser extends Parser { scanner.readChar(); wroteNewline = true; + case $lbrace when !allowOpenBrace: + break loop; + case $lparen || $lbrace || $lbracket: var bracket = scanner.readChar(); buffer.writeCharCode(bracket); @@ -2907,13 +2948,18 @@ abstract class StylesheetParser extends Parser { case $u || $U: var beforeUrl = scanner.state; - if (!scanIdentifier("url")) { - buffer.writeCharCode(scanner.readChar()); + var identifier = this.identifier(); + if (identifier != "url" && + // This isn't actually a standard CSS feature, but it was + // supported by the old `@document` rule so we continue to support + // it for backwards-compatibility. + identifier != "url-prefix") { + buffer.write(identifier); wroteNewline = false; continue loop; } - if (_tryUrlContents(beforeUrl) case var contents?) { + if (_tryUrlContents(beforeUrl, name: identifier) case var contents?) { buffer.addInterpolation(contents); } else { scanner.state = beforeUrl; diff --git a/pubspec.yaml b/pubspec.yaml index 936b32092..fd753e22b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.77.6 +version: 1.77.7-dev description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From a16488992517cb30d907d3982a12517e5f13d334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Mon, 1 Jul 2024 17:09:27 -0700 Subject: [PATCH 10/25] Enable AOT build for windows-arm64 (#2270) --- .github/workflows/build-windows.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index b2011ce2f..86ea17c22 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,8 +19,7 @@ jobs: - arch: ia32 runner: windows-latest - arch: arm64 - # TODO: switch the following to windows-arm64, blocked by https://github.com/dart-lang/setup-dart/issues/118 - runner: windows-latest # windows-arm64 + runner: windows-arm64 steps: - uses: actions/checkout@v4 From 1edc247425c0d6731e750f13e2d5386c076f9b33 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 9 Jul 2024 14:13:55 -0700 Subject: [PATCH 11/25] Avoid `[this]` in Dartdoc comments (#2273) Dartdoc broke this in dart-lang/dartdoc#3765. --- lib/src/ast/css/modifiable/node.dart | 8 ++-- lib/src/ast/sass/at_root_query.dart | 4 +- .../ast/sass/expression/binary_operation.dart | 6 +-- lib/src/ast/sass/expression/list.dart | 2 +- lib/src/ast/sass/expression/string.dart | 2 +- .../ast/sass/expression/unary_operation.dart | 4 +- lib/src/ast/selector.dart | 2 +- lib/src/ast/selector/list.dart | 4 +- lib/src/ast/selector/pseudo.dart | 2 +- lib/src/ast/selector/simple.dart | 2 +- lib/src/async_environment.dart | 4 +- lib/src/environment.dart | 6 +-- lib/src/extend/extension_store.dart | 10 ++--- lib/src/stylesheet_graph.dart | 2 +- lib/src/util/map.dart | 2 +- lib/src/util/multi_span.dart | 2 +- lib/src/util/nullable.dart | 2 +- lib/src/util/span.dart | 4 +- lib/src/value.dart | 42 +++++++++---------- lib/src/value/calculation.dart | 6 +-- lib/src/value/number.dart | 32 +++++++------- 21 files changed, 74 insertions(+), 74 deletions(-) diff --git a/lib/src/ast/css/modifiable/node.dart b/lib/src/ast/css/modifiable/node.dart index bef0be821..1b27f8258 100644 --- a/lib/src/ast/css/modifiable/node.dart +++ b/lib/src/ast/css/modifiable/node.dart @@ -17,7 +17,7 @@ abstract base class ModifiableCssNode extends CssNode { ModifiableCssParentNode? get parent => _parent; ModifiableCssParentNode? _parent; - /// The index of [this] in `parent.children`. + /// The index of `this` in `parent.children`. /// /// This makes [remove] more efficient. int? _indexInParent; @@ -33,7 +33,7 @@ abstract base class ModifiableCssNode extends CssNode { T accept(ModifiableCssVisitor visitor); - /// Removes [this] from [parent]'s child list. + /// Removes `this` from [parent]'s child list. /// /// Throws a [StateError] if [parent] is `null`. void remove() { @@ -65,10 +65,10 @@ abstract base class ModifiableCssParentNode extends ModifiableCssNode : _children = children, children = UnmodifiableListView(children); - /// Returns whether [this] is equal to [other], ignoring their child nodes. + /// Returns whether `this` is equal to [other], ignoring their child nodes. bool equalsIgnoringChildren(ModifiableCssNode other); - /// Returns a copy of [this] with an empty [children] list. + /// Returns a copy of `this` with an empty [children] list. /// /// This is *not* a deep copy. If other parts of this node are modifiable, /// they are shared between the new and old nodes. diff --git a/lib/src/ast/sass/at_root_query.dart b/lib/src/ast/sass/at_root_query.dart index 3bad9cf20..58b2e2f94 100644 --- a/lib/src/ast/sass/at_root_query.dart +++ b/lib/src/ast/sass/at_root_query.dart @@ -61,7 +61,7 @@ final class AtRootQuery { {Object? url, Logger? logger, InterpolationMap? interpolationMap}) => AtRootQueryParser(contents, url: url, logger: logger).parse(); - /// Returns whether [this] excludes [node]. + /// Returns whether `this` excludes [node]. /// /// @nodoc @internal @@ -76,6 +76,6 @@ final class AtRootQuery { }; } - /// Returns whether [this] excludes an at-rule with the given [name]. + /// Returns whether `this` excludes an at-rule with the given [name]. bool excludesName(String name) => (_all || names.contains(name)) != include; } diff --git a/lib/src/ast/sass/expression/binary_operation.dart b/lib/src/ast/sass/expression/binary_operation.dart index dc750900a..15ab22bba 100644 --- a/lib/src/ast/sass/expression/binary_operation.dart +++ b/lib/src/ast/sass/expression/binary_operation.dart @@ -153,13 +153,13 @@ enum BinaryOperator { /// The modulo operator, `%`. modulo('modulo', '%', 6); - /// The English name of [this]. + /// The English name of `this`. final String name; - /// The Sass syntax for [this]. + /// The Sass syntax for `this`. final String operator; - /// The precedence of [this]. + /// The precedence of `this`. /// /// An operator with higher precedence binds tighter. final int precedence; diff --git a/lib/src/ast/sass/expression/list.dart b/lib/src/ast/sass/expression/list.dart index 01416afa4..5bf768cac 100644 --- a/lib/src/ast/sass/expression/list.dart +++ b/lib/src/ast/sass/expression/list.dart @@ -58,7 +58,7 @@ final class ListExpression implements Expression { return buffer.toString(); } - /// Returns whether [expression], contained in [this], needs parentheses when + /// Returns whether [expression], contained in `this`, needs parentheses when /// printed as Sass source. bool _elementNeedsParens(Expression expression) => switch (expression) { ListExpression( diff --git a/lib/src/ast/sass/expression/string.dart b/lib/src/ast/sass/expression/string.dart index 2e7824345..a8539146a 100644 --- a/lib/src/ast/sass/expression/string.dart +++ b/lib/src/ast/sass/expression/string.dart @@ -23,7 +23,7 @@ final class StringExpression implements Expression { /// included. final Interpolation text; - /// Whether [this] has quotes. + /// Whether `this` has quotes. final bool hasQuotes; FileSpan get span => text.span; diff --git a/lib/src/ast/sass/expression/unary_operation.dart b/lib/src/ast/sass/expression/unary_operation.dart index d437fafc2..18e5f0c27 100644 --- a/lib/src/ast/sass/expression/unary_operation.dart +++ b/lib/src/ast/sass/expression/unary_operation.dart @@ -63,10 +63,10 @@ enum UnaryOperator { /// The boolean negation operator, `not`. not('not', 'not'); - /// The English name of [this]. + /// The English name of `this`. final String name; - /// The Sass syntax for [this]. + /// The Sass syntax for `this`. final String operator; const UnaryOperator(this.name, this.operator); diff --git a/lib/src/ast/selector.dart b/lib/src/ast/selector.dart index 953ccf7aa..fcabcdc25 100644 --- a/lib/src/ast/selector.dart +++ b/lib/src/ast/selector.dart @@ -83,7 +83,7 @@ abstract base class Selector implements AstNode { Selector(this.span); - /// Prints a warning if [this] is a bogus selector. + /// Prints a warning if `this` is a bogus selector. /// /// This may only be called from within a custom Sass function. This will /// throw a [SassException] in Dart Sass 2.0.0. diff --git a/lib/src/ast/selector/list.dart b/lib/src/ast/selector/list.dart index 8da4598f6..b45fa2a2d 100644 --- a/lib/src/ast/selector/list.dart +++ b/lib/src/ast/selector/list.dart @@ -96,9 +96,9 @@ final class SelectorList extends Selector { return contents.isEmpty ? null : SelectorList(contents, span); } - /// Returns a new selector list that represents [this] nested within [parent]. + /// Returns a new selector list that represents `this` nested within [parent]. /// - /// By default, this replaces [ParentSelector]s in [this] with [parent]. If + /// By default, this replaces [ParentSelector]s in `this` with [parent]. If /// [preserveParentSelectors] is true, this instead preserves those selectors /// as parent selectors. /// diff --git a/lib/src/ast/selector/pseudo.dart b/lib/src/ast/selector/pseudo.dart index e632c651e..930d49e08 100644 --- a/lib/src/ast/selector/pseudo.dart +++ b/lib/src/ast/selector/pseudo.dart @@ -174,7 +174,7 @@ final class PseudoSelector extends SimpleSelector { for (var simple in compound) { if (simple case PseudoSelector(isElement: true)) { // A given compound selector may only contain one pseudo element. If - // [compound] has a different one than [this], unification fails. + // [compound] has a different one than `this`, unification fails. if (isElement) return null; // Otherwise, this is a pseudo selector and should come before pseudo diff --git a/lib/src/ast/selector/simple.dart b/lib/src/ast/selector/simple.dart index 5ac2f0e53..acc86949e 100644 --- a/lib/src/ast/selector/simple.dart +++ b/lib/src/ast/selector/simple.dart @@ -59,7 +59,7 @@ abstract base class SimpleSelector extends Selector { url: url, logger: logger, allowParent: allowParent) .parseSimpleSelector(); - /// Returns a new [SimpleSelector] based on [this], as though it had been + /// Returns a new [SimpleSelector] based on `this`, as though it had been /// written with [suffix] at the end. /// /// Assumes [suffix] is a valid identifier suffix. If this wouldn't produce a diff --git a/lib/src/async_environment.dart b/lib/src/async_environment.dart index 96cbecc18..5313d8c45 100644 --- a/lib/src/async_environment.dart +++ b/lib/src/async_environment.dart @@ -790,7 +790,7 @@ final class AsyncEnvironment { return Configuration.implicit(configuration); } - /// Returns a module that represents the top-level members defined in [this], + /// Returns a module that represents the top-level members defined in `this`, /// that contains [css] and [preModuleComments] as its CSS, which can be /// extended using [extensionStore]. Module toModule( @@ -802,7 +802,7 @@ final class AsyncEnvironment { forwarded: _forwardedModules.andThen((modules) => MapKeySet(modules))); } - /// Returns a module with the same members and upstream modules as [this], but + /// Returns a module with the same members and upstream modules as `this`, but /// an empty stylesheet and extension store. /// /// This is used when resolving imports, since they need to inject forwarded diff --git a/lib/src/environment.dart b/lib/src/environment.dart index 623f67828..3aa0fa45d 100644 --- a/lib/src/environment.dart +++ b/lib/src/environment.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_environment.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: f7172be68e0a19c4dc2d2ad04fc32a843a98a6bd +// Checksum: e1beeae58a4d5b97cd7d4f01c7d46b0586b508b9 // // ignore_for_file: unused_import @@ -796,7 +796,7 @@ final class Environment { return Configuration.implicit(configuration); } - /// Returns a module that represents the top-level members defined in [this], + /// Returns a module that represents the top-level members defined in `this`, /// that contains [css] and [preModuleComments] as its CSS, which can be /// extended using [extensionStore]. Module toModule( @@ -808,7 +808,7 @@ final class Environment { forwarded: _forwardedModules.andThen((modules) => MapKeySet(modules))); } - /// Returns a module with the same members and upstream modules as [this], but + /// Returns a module with the same members and upstream modules as `this`, but /// an empty stylesheet and extension store. /// /// This is used when resolving imports, since they need to inject forwarded diff --git a/lib/src/extend/extension_store.dart b/lib/src/extend/extension_store.dart index 2bbc2a9cb..c450bb7e8 100644 --- a/lib/src/extend/extension_store.dart +++ b/lib/src/extend/extension_store.dart @@ -386,12 +386,12 @@ class ExtensionStore { } } - /// Extends [this] with all the extensions in [extensions]. + /// Extends `this` with all the extensions in [extensions]. /// - /// These extensions will extend all selectors already in [this], but they + /// These extensions will extend all selectors already in `this`, but they /// will *not* extend other extensions from [extensionStores]. void addExtensions(Iterable extensionStores) { - // Extensions already in [this] whose extenders are extended by + // Extensions already in `this` whose extenders are extended by // [extensions], and thus which need to be updated. List? extensionsToExtend; @@ -966,8 +966,8 @@ class ExtensionStore { return specificity; } - /// Returns a copy of [this] that extends new selectors, as well as a map - /// (with reference equality) from the selectors extended by [this] to the + /// Returns a copy of `this` that extends new selectors, as well as a map + /// (with reference equality) from the selectors extended by `this` to the /// selectors extended by the new [ExtensionStore]. (ExtensionStore, Map>) clone() { var newSelectors = >>{}; diff --git a/lib/src/stylesheet_graph.dart b/lib/src/stylesheet_graph.dart index 3109fc5f0..245d8b146 100644 --- a/lib/src/stylesheet_graph.dart +++ b/lib/src/stylesheet_graph.dart @@ -385,7 +385,7 @@ class StylesheetNode { _upstreamImports = newUpstreamImports; } - /// Removes [this] as an upstream and downstream node from all the nodes that + /// Removes `this` as an upstream and downstream node from all the nodes that /// import it and that it imports. void _remove() { for (var node in {...upstream.values, ...upstreamImports.values}) { diff --git a/lib/src/util/map.dart b/lib/src/util/map.dart index a61c151df..865b213bc 100644 --- a/lib/src/util/map.dart +++ b/lib/src/util/map.dart @@ -5,7 +5,7 @@ import 'option.dart'; extension MapExtensions on Map { - /// If [this] doesn't contain the given [key], sets that key to [value] and + /// If `this` doesn't contain the given [key], sets that key to [value] and /// returns it. /// /// Otherwise, calls [merge] with the existing value and [value] and sets diff --git a/lib/src/util/multi_span.dart b/lib/src/util/multi_span.dart index 24ca42b48..41121042a 100644 --- a/lib/src/util/multi_span.dart +++ b/lib/src/util/multi_span.dart @@ -70,7 +70,7 @@ class MultiSpan implements FileSpan { primaryColor: primaryColor, secondaryColor: secondaryColor); - /// Returns a copy of [this] with [newPrimary] as its primary span. + /// Returns a copy of `this` with [newPrimary] as its primary span. MultiSpan _withPrimary(FileSpan newPrimary) => MultiSpan._(newPrimary, primaryLabel, secondarySpans); } diff --git a/lib/src/util/nullable.dart b/lib/src/util/nullable.dart index ad4a8ba2f..cf24c880e 100644 --- a/lib/src/util/nullable.dart +++ b/lib/src/util/nullable.dart @@ -3,7 +3,7 @@ // https://opensource.org/licenses/MIT. extension NullableExtension on T? { - /// If [this] is `null`, returns `null`. Otherwise, runs [fn] and returns its + /// If `this` is `null`, returns `null`. Otherwise, runs [fn] and returns its /// result. /// /// Based on Rust's `Option.and_then`. diff --git a/lib/src/util/span.dart b/lib/src/util/span.dart index bcb9b6165..6328f4aed 100644 --- a/lib/src/util/span.dart +++ b/lib/src/util/span.dart @@ -84,10 +84,10 @@ extension SpanExtensions on FileSpan { return subspan(scanner.position).trimLeft(); } - /// Whether [this] FileSpan contains the [target] FileSpan. + /// Whether this [FileSpan] contains the [target] FileSpan. /// /// Validates the FileSpans to be in the same file and for the [target] to be - /// within [this] FileSpan inclusive range [start,end]. + /// within this [FileSpan]'s inclusive range `[start,end]`. bool contains(FileSpan target) => file.url == target.file.url && start.offset <= target.start.offset && diff --git a/lib/src/value.dart b/lib/src/value.dart index 3149435a0..1161ebbbe 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -100,7 +100,7 @@ abstract class Value { @internal bool get isVar => false; - /// Returns Dart's `null` value if this is [sassNull], and returns [this] + /// Returns Dart's `null` value if this is [sassNull], and returns `this` /// otherwise. Value? get realNull => this; @@ -148,7 +148,7 @@ abstract class Value { return index < 0 ? lengthAsList + index : index - 1; } - /// Throws a [SassScriptException] if [this] isn't a boolean. + /// Throws a [SassScriptException] if `this` isn't a boolean. /// /// Note that generally, functions should use [isTruthy] rather than requiring /// a literal boolean. @@ -158,53 +158,53 @@ abstract class Value { SassBoolean assertBoolean([String? name]) => throw SassScriptException("$this is not a boolean.", name); - /// Throws a [SassScriptException] if [this] isn't a calculation. + /// Throws a [SassScriptException] if `this` isn't a calculation. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. SassCalculation assertCalculation([String? name]) => throw SassScriptException("$this is not a calculation.", name); - /// Throws a [SassScriptException] if [this] isn't a color. + /// Throws a [SassScriptException] if `this` isn't a color. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. SassColor assertColor([String? name]) => throw SassScriptException("$this is not a color.", name); - /// Throws a [SassScriptException] if [this] isn't a function reference. + /// Throws a [SassScriptException] if `this` isn't a function reference. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. SassFunction assertFunction([String? name]) => throw SassScriptException("$this is not a function reference.", name); - /// Throws a [SassScriptException] if [this] isn't a mixin reference. + /// Throws a [SassScriptException] if `this` isn't a mixin reference. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. SassMixin assertMixin([String? name]) => throw SassScriptException("$this is not a mixin reference.", name); - /// Throws a [SassScriptException] if [this] isn't a map. + /// Throws a [SassScriptException] if `this` isn't a map. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. SassMap assertMap([String? name]) => throw SassScriptException("$this is not a map.", name); - /// Returns [this] as a [SassMap] if it is one (including empty lists, which + /// Returns `this` as a [SassMap] if it is one (including empty lists, which /// count as empty maps) or returns `null` if it's not. SassMap? tryMap() => null; - /// Throws a [SassScriptException] if [this] isn't a number. + /// Throws a [SassScriptException] if `this` isn't a number. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. SassNumber assertNumber([String? name]) => throw SassScriptException("$this is not a number.", name); - /// Throws a [SassScriptException] if [this] isn't a string. + /// Throws a [SassScriptException] if `this` isn't a string. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. @@ -214,7 +214,7 @@ abstract class Value { /// Converts a `selector-parse()`-style input into a string that can be /// parsed. /// - /// Throws a [SassScriptException] if [this] isn't a type or a structure that + /// Throws a [SassScriptException] if `this` isn't a type or a structure that /// can be parsed as a selector. String _selectorString([String? name]) { if (_selectorStringOrNull() case var string?) return string; @@ -228,7 +228,7 @@ abstract class Value { /// Converts a `selector-parse()`-style input into a string that can be /// parsed. /// - /// Returns `null` if [this] isn't a type or a structure that can be parsed as + /// Returns `null` if `this` isn't a type or a structure that can be parsed as /// a selector. String? _selectorStringOrNull() { var self = this; @@ -370,7 +370,7 @@ abstract class Value { @internal Value unaryNot() => sassFalse; - /// Returns a copy of [this] without [SassNumber.asSlash] set. + /// Returns a copy of `this` without [SassNumber.asSlash] set. /// /// If this isn't a [SassNumber], returns it as-is. /// @@ -378,9 +378,9 @@ abstract class Value { @internal Value withoutSlash() => this; - /// Returns a valid CSS representation of [this]. + /// Returns a valid CSS representation of `this`. /// - /// Throws a [SassScriptException] if [this] can't be represented in plain + /// Throws a [SassScriptException] if `this` can't be represented in plain /// CSS. Use [toString] instead to get a string representation even if this /// isn't valid CSS. // @@ -389,11 +389,11 @@ abstract class Value { String toCssString({@internal bool quote = true}) => serializeValue(this, quote: quote); - /// Returns a string representation of [this]. + /// Returns a string representation of `this`. /// /// Note that this is equivalent to calling `inspect()` on the value, and thus /// won't reflect the user's output settings. [toCssString] should be used - /// instead to convert [this] to CSS. + /// instead to convert `this` to CSS. String toString() => serializeValue(this, inspect: true); } @@ -404,7 +404,7 @@ abstract class Value { /// /// {@category Value} extension SassApiValue on Value { - /// Parses [this] as a selector list, in the same manner as the + /// Parses `this` as a selector list, in the same manner as the /// `selector-parse()` function. /// /// Throws a [SassScriptException] if this isn't a type that can be parsed as a @@ -428,7 +428,7 @@ extension SassApiValue on Value { } } - /// Parses [this] as a simple selector, in the same manner as the + /// Parses `this` as a simple selector, in the same manner as the /// `selector-parse()` function. /// /// Throws a [SassScriptException] if this isn't a type that can be parsed as a @@ -453,7 +453,7 @@ extension SassApiValue on Value { } } - /// Parses [this] as a compound selector, in the same manner as the + /// Parses `this` as a compound selector, in the same manner as the /// `selector-parse()` function. /// /// Throws a [SassScriptException] if this isn't a type that can be parsed as a @@ -478,7 +478,7 @@ extension SassApiValue on Value { } } - /// Parses [this] as a complex selector, in the same manner as the + /// Parses `this` as a complex selector, in the same manner as the /// `selector-parse()` function. /// /// Throws a [SassScriptException] if this isn't a type that can be parsed as a diff --git a/lib/src/value/calculation.dart b/lib/src/value/calculation.dart index cbb8b92e6..261400dc2 100644 --- a/lib/src/value/calculation.dart +++ b/lib/src/value/calculation.dart @@ -906,13 +906,13 @@ enum CalculationOperator { /// The division operator. dividedBy('divided by', '/', 2); - /// The English name of [this]. + /// The English name of `this`. final String name; - /// The CSS syntax for [this]. + /// The CSS syntax for `this`. final String operator; - /// The precedence of [this]. + /// The precedence of `this`. /// /// An operator with higher precedence binds tighter. /// diff --git a/lib/src/value/number.dart b/lib/src/value/number.dart index a5c90a501..29f144ad7 100644 --- a/lib/src/value/number.dart +++ b/lib/src/value/number.dart @@ -190,7 +190,7 @@ abstract class SassNumber extends Value { /// The value of this number. /// - /// Note that Sass stores all numbers as [double]s even if if [this] + /// Note that Sass stores all numbers as [double]s even if if `this` /// represents an integer from Sass's perspective. Use [isInt] to determine /// whether this is an integer, [asInt] to get its integer value, or /// [assertInt] to do both at once. @@ -209,14 +209,14 @@ abstract class SassNumber extends Value { /// This number's denominator units. List get denominatorUnits; - /// Whether [this] has any units. + /// Whether `this` has any units. /// /// If a function expects a number to have no units, it should use /// [assertNoUnits]. If it expects the number to have a particular unit, it /// should use [assertUnit]. bool get hasUnits; - /// Whether [this] has more than one numerator unit, or any denominator units. + /// Whether `this` has more than one numerator unit, or any denominator units. /// /// This is `true` for numbers whose units make them unrepresentable as CSS /// lengths. @@ -229,7 +229,7 @@ abstract class SassNumber extends Value { @internal final (SassNumber, SassNumber)? asSlash; - /// Whether [this] is an integer, according to [fuzzyEquals]. + /// Whether `this` is an integer, according to [fuzzyEquals]. /// /// The [int] value can be accessed using [asInt] or [assertInt]. Note that /// this may return `false` for very large doubles even though they may be @@ -237,7 +237,7 @@ abstract class SassNumber extends Value { /// representation for integers that large. bool get isInt => fuzzyIsInt(value); - /// If [this] is an integer according to [isInt], returns [value] as an [int]. + /// If `this` is an integer according to [isInt], returns [value] as an [int]. /// /// Otherwise, returns `null`. int? get asInt => fuzzyAsInt(value); @@ -304,20 +304,20 @@ abstract class SassNumber extends Value { T accept(ValueVisitor visitor) => visitor.visitNumber(this); - /// Returns a number with the same units as [this] but with [value] as its + /// Returns a number with the same units as `this` but with [value] as its /// value. /// /// @nodoc @protected SassNumber withValue(num value); - /// Returns a copy of [this] without [asSlash] set. + /// Returns a copy of `this` without [asSlash] set. /// /// @nodoc @internal SassNumber withoutSlash() => asSlash == null ? this : withValue(value); - /// Returns a copy of [this] with [asSlash] set to a pair containing + /// Returns a copy of `this` with [asSlash] set to a pair containing /// [numerator] and [denominator]. /// /// @nodoc @@ -365,10 +365,10 @@ abstract class SassNumber extends Value { "Expected $this to be within $min$unit and $max$unit.", name); } - /// Returns whether [this] has [unit] as its only unit (and as a numerator). + /// Returns whether `this` has [unit] as its only unit (and as a numerator). bool hasUnit(String unit); - /// Returns whether [this] has units that are compatible with [other]. + /// Returns whether `this` has units that are compatible with [other]. /// /// Unlike [isComparableTo], unitless numbers are only considered compatible /// with other unitless numbers. @@ -378,17 +378,17 @@ abstract class SassNumber extends Value { return isComparableTo(other); } - /// Returns whether [this] has units that are possibly-compatible with + /// Returns whether `this` has units that are possibly-compatible with /// [other], as defined by the Sass spec. @internal bool hasPossiblyCompatibleUnits(SassNumber other); - /// Returns whether [this] can be coerced to the given [unit]. + /// Returns whether `this` can be coerced to the given [unit]. /// /// This always returns `true` for a unitless number. bool compatibleWithUnit(String unit); - /// Throws a [SassScriptException] unless [this] has [unit] as its only unit + /// Throws a [SassScriptException] unless `this` has [unit] as its only unit /// (and as a numerator). /// /// If this came from a function argument, [name] is the argument name @@ -398,7 +398,7 @@ abstract class SassNumber extends Value { throw SassScriptException('Expected $this to have unit "$unit".', name); } - /// Throws a [SassScriptException] unless [this] has no units. + /// Throws a [SassScriptException] unless `this` has no units. /// /// If this came from a function argument, [name] is the argument name /// (without the `$`). It's used for error reporting. @@ -571,7 +571,7 @@ abstract class SassNumber extends Value { /// /// If [other] is passed, it should be the number from which [newNumerators] /// and [newDenominators] are derived. The [name] and [otherName] are the Sass - /// function parameter names of [this] and [other], respectively, used for + /// function parameter names of `this` and [other], respectively, used for /// error reporting. double _coerceOrConvertValue( List newNumerators, List newDenominators, @@ -775,7 +775,7 @@ abstract class SassNumber extends Value { return operation(value, other.coerceValueToMatch(this)); } on SassScriptException { // If the conversion fails, re-run it in the other direction. This will - // generate an error message that prints [this] before [other], which is + // generate an error message that prints `this` before [other], which is // more readable. coerceValueToMatch(other); rethrow; // This should be unreachable. From 7203d6538981df6422c686198da2497909fa11b5 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 9 Jul 2024 14:31:20 -0700 Subject: [PATCH 12/25] Deprecated mixed declarations (#2267) See sass/sass#3885 --- CHANGELOG.md | 6 +++++ lib/src/deprecation.dart | 7 +++++- lib/src/parse/css.dart | 6 ++--- lib/src/visitor/async_evaluate.dart | 37 +++++++++++++++++++++------ lib/src/visitor/evaluate.dart | 39 ++++++++++++++++++++++------- pkg/sass_api/CHANGELOG.md | 4 +++ pkg/sass_api/pubspec.yaml | 4 +-- pubspec.yaml | 2 +- 8 files changed, 81 insertions(+), 24 deletions(-) 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/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..22d380edb 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,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), @@ -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)); } diff --git a/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index b8434ff47..e4a65d12e 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -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); @@ -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) { @@ -2110,13 +2138,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..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: 116b8079719577ac6e4dad4aebe403282136e611 +// Checksum: ebf292c26dcfdd7f61fd70ce3dc9e0be2b6708b3 // // ignore_for_file: unused_import @@ -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); @@ -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) { @@ -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) { 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..cba35a261 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 @@ -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" 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 c96b5e2d4d14aee9e053700896537b4be0550c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 10 Jul 2024 16:44:04 -0700 Subject: [PATCH 13/25] Fix windows-arm64 release (#2274) --- .github/workflows/build-windows.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 86ea17c22..2d027a8d7 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -24,8 +24,21 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: ./.github/util/initialize - with: {github-token: "${{ github.token }}"} + # See: https://github.com/orgs/community/discussions/131594 + # The composite action requires bash which is not available on windows-arm64 runner. + # - uses: ./.github/util/initialize + # with: {github-token: "${{ github.token }}"} + + - uses: dart-lang/setup-dart@v1 + + - uses: bufbuild/buf-setup-action@v1.30.0 + with: {github_token: "${{ github.token }}"} + + - name: Install Dependencies + run: dart pub get + + - name: Compile Protobuf + run: dart run grinder protobuf - name: Build run: dart run grinder pkg-standalone-windows-${{ matrix.arch }} From d4b19397c493adb6e518ed5344913aa2615c11f6 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 10 Jul 2024 17:36:28 -0700 Subject: [PATCH 14/25] Run pub in verbose mode on windows-arm64 This is just intended to debug a GitHub Actions build failure. --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 2d027a8d7..a568a124f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -35,7 +35,7 @@ jobs: with: {github_token: "${{ github.token }}"} - name: Install Dependencies - run: dart pub get + run: dart pub get --verbose - name: Compile Protobuf run: dart run grinder protobuf From be9c3ac6fa547c3f2711f445b8b15932ddb5e7e4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 11 Jul 2024 12:44:37 -0700 Subject: [PATCH 15/25] Run Windows ARM64 releases on windows-latest instead (#2275) See https://github.com/orgs/community/discussions/131594 --- .github/workflows/build-windows.yml | 5 ++++- CHANGELOG.md | 4 ++++ pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index a568a124f..bb97bc1a9 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,7 +19,10 @@ jobs: - arch: ia32 runner: windows-latest - arch: arm64 - runner: windows-arm64 + # This should be windows-arm64, but it's broken by several issues: + # https://github.com/orgs/community/discussions/131594 + # https://github.com/orgs/community/discussions/131754 + runner: windows-latest steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cd1720e1..8533ae1c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.77.8 + +* No user-visible changes. + ## 1.77.7 * Declarations that appear after nested rules are deprecated, because the diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 006fbe277..7753afacf 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.4.8 + +* No user-visible changes. + ## 10.4.7 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index cba35a261..565bb7d8d 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.7 +version: 10.4.8 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - sass: 1.77.7 + sass: 1.77.8 dev_dependencies: dartdoc: ">=6.0.0 <9.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index ad62bb19b..1c78769ae 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.77.7 +version: 1.77.8 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 0cf476813974663fa3c6a297500a0c187b2392d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:29:12 -0700 Subject: [PATCH 16/25] Bump dartdoc from 8.0.7 to 8.0.8 (#2284) Bumps [dartdoc](https://github.com/dart-lang/dartdoc) from 8.0.7 to 8.0.8. - [Release notes](https://github.com/dart-lang/dartdoc/releases) - [Changelog](https://github.com/dart-lang/dartdoc/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/dartdoc/commits) --- updated-dependencies: - dependency-name: dartdoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From e03547f1dbb87fcd2cf06b0a3f25374c1d00ab31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Tue, 23 Jul 2024 18:26:41 -0700 Subject: [PATCH 17/25] Enable AOT build for windows-arm64 (#2286) --- .github/util/initialize/action.yml | 35 +++++++++++++++++++++++++++++ .github/workflows/build-windows.yml | 22 +++--------------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/.github/util/initialize/action.yml b/.github/util/initialize/action.yml index acfa759c2..ba37f9376 100644 --- a/.github/util/initialize/action.yml +++ b/.github/util/initialize/action.yml @@ -17,20 +17,55 @@ runs: with: node-version: "${{ inputs.node-version }}" + # See: https://github.com/dart-lang/sdk/issues/52266 + - run: Invoke-WebRequest https://pub.dev + if: runner.os == 'Windows' + shell: powershell + + # See: https://github.com/orgs/community/discussions/131594 + # The composite action requires an explict shell, but bash is not available on windows-arm64 runner. + # For the following commands conditionally use bash or powershell based on the runner.os: - run: dart pub get + if: runner.os != 'Windows' shell: bash + - run: dart pub get + if: runner.os == 'Windows' + shell: powershell + - run: npm install + if: runner.os != 'Windows' shell: bash + - run: npm install + if: runner.os == 'Windows' + shell: powershell + - uses: bufbuild/buf-setup-action@v1.30.0 with: {github_token: "${{ inputs.github-token }}"} + # This composite action requires bash, but bash is not available on windows-arm64 runner. + # Avoid running this composite action on non-PR, so that we can release on windows-arm64. - name: Check out the language repo + if: github.event_name == 'pull_request' uses: sass/clone-linked-repo@v1 with: {repo: sass/sass, path: build/language} + # Git is not pre-installed on windows-arm64 runner, however actions/checkout support + # downloading repo via GitHub API. + - name: Check out the language repo + if: github.event_name != 'pull_request' + uses: actions/checkout@v4 + with: {repository: sass/sass, path: build/language} + - name: Generate Dart from protobuf + if: runner.os != 'Windows' run: dart run grinder protobuf env: {UPDATE_SASS_SASS_REPO: false} shell: bash + + - name: Generate Dart from protobuf + if: runner.os == 'Windows' + run: dart run grinder protobuf + env: {UPDATE_SASS_SASS_REPO: false} + shell: powershell diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index bb97bc1a9..86ea17c22 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,29 +19,13 @@ jobs: - arch: ia32 runner: windows-latest - arch: arm64 - # This should be windows-arm64, but it's broken by several issues: - # https://github.com/orgs/community/discussions/131594 - # https://github.com/orgs/community/discussions/131754 - runner: windows-latest + runner: windows-arm64 steps: - uses: actions/checkout@v4 - # See: https://github.com/orgs/community/discussions/131594 - # The composite action requires bash which is not available on windows-arm64 runner. - # - uses: ./.github/util/initialize - # with: {github-token: "${{ github.token }}"} - - - uses: dart-lang/setup-dart@v1 - - - uses: bufbuild/buf-setup-action@v1.30.0 - with: {github_token: "${{ github.token }}"} - - - name: Install Dependencies - run: dart pub get --verbose - - - name: Compile Protobuf - run: dart run grinder protobuf + - uses: ./.github/util/initialize + with: {github-token: "${{ github.token }}"} - name: Build run: dart run grinder pkg-standalone-windows-${{ matrix.arch }} From d0e02eb891c07fd72a486cf729752794478c27fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 24 Jul 2024 15:01:10 -0700 Subject: [PATCH 18/25] Let dependabot check updates for composite actions (#2287) Co-authored-by: Natalie Weizenbaum --- .github/dependabot.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 44ca4f044..f1360f056 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,8 @@ updates: schedule: interval: "weekly" - package-ecosystem: "github-actions" - directory: "/" + directories: + - "/" + - "/.github/util/*/" schedule: interval: "weekly" From 7e1ea8094391f88cd38ab6c8ec1214bd5bf4e65f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:08:58 -0700 Subject: [PATCH 19/25] Bump dartdoc from 8.0.7 to 8.0.8 (#2289) Bumps [dartdoc](https://github.com/dart-lang/dartdoc) from 8.0.7 to 8.0.8. - [Release notes](https://github.com/dart-lang/dartdoc/releases) - [Changelog](https://github.com/dart-lang/dartdoc/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/dartdoc/commits) --- updated-dependencies: - dependency-name: dartdoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 715a93f5eb571e741e24e79315d88a2f52b6236f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:09:40 -0700 Subject: [PATCH 20/25] Bump bufbuild/buf-setup-action in /.github/util/initialize (#2288) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.30.0 to 1.35.1. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.30.0...v1.35.1) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/util/initialize/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/util/initialize/action.yml b/.github/util/initialize/action.yml index ba37f9376..6a02fbb3d 100644 --- a/.github/util/initialize/action.yml +++ b/.github/util/initialize/action.yml @@ -41,7 +41,7 @@ runs: if: runner.os == 'Windows' shell: powershell - - uses: bufbuild/buf-setup-action@v1.30.0 + - uses: bufbuild/buf-setup-action@v1.35.1 with: {github_token: "${{ inputs.github-token }}"} # This composite action requires bash, but bash is not available on windows-arm64 runner. From b0271a5f63c6c9e966b5817f89b1e4648056e8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Mon, 29 Jul 2024 18:36:00 -0700 Subject: [PATCH 21/25] Refactor duplicated code in CI (#2295) --- .github/util/initialize/action.yml | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/.github/util/initialize/action.yml b/.github/util/initialize/action.yml index 6a02fbb3d..cba0719ba 100644 --- a/.github/util/initialize/action.yml +++ b/.github/util/initialize/action.yml @@ -26,20 +26,10 @@ runs: # The composite action requires an explict shell, but bash is not available on windows-arm64 runner. # For the following commands conditionally use bash or powershell based on the runner.os: - run: dart pub get - if: runner.os != 'Windows' - shell: bash - - - run: dart pub get - if: runner.os == 'Windows' - shell: powershell + shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }} - run: npm install - if: runner.os != 'Windows' - shell: bash - - - run: npm install - if: runner.os == 'Windows' - shell: powershell + shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }} - uses: bufbuild/buf-setup-action@v1.35.1 with: {github_token: "${{ inputs.github-token }}"} @@ -59,13 +49,6 @@ runs: with: {repository: sass/sass, path: build/language} - name: Generate Dart from protobuf - if: runner.os != 'Windows' run: dart run grinder protobuf env: {UPDATE_SASS_SASS_REPO: false} - shell: bash - - - name: Generate Dart from protobuf - if: runner.os == 'Windows' - run: dart run grinder protobuf - env: {UPDATE_SASS_SASS_REPO: false} - shell: powershell + shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }} From 9f786f45901790167c18ed82860ae3e4e4c0fb31 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Tue, 30 Jul 2024 15:48:05 -0700 Subject: [PATCH 22/25] Fix analysis issues (#2294) --- analysis/pubspec.yaml | 4 ++-- lib/src/async_import_cache.dart | 3 +-- lib/src/extend/functions.dart | 2 +- lib/src/import_cache.dart | 5 ++--- lib/src/importer/node_package.dart | 3 +-- lib/src/io/js.dart | 4 ++-- lib/src/js/value/calculation.dart | 11 +++-------- test/browser_test.dart | 1 + test/cli/dart/colon_args_test.dart | 1 + test/cli/dart/deprecations_test.dart | 1 + test/cli/dart/errors_test.dart | 1 + test/cli/dart/repl_test.dart | 1 + test/cli/dart/source_maps_test.dart | 1 + test/cli/dart/update_test.dart | 1 + test/cli/dart/watch_test.dart | 1 + test/cli/dart_test.dart | 1 + test/cli/node/colon_args_test.dart | 1 + test/cli/node/deprecations_test.dart | 1 + test/cli/node/errors_test.dart | 1 + test/cli/node/repl_test.dart | 1 + test/cli/node/source_maps_test.dart | 1 + test/cli/node/update_test.dart | 1 + test/cli/node/watch_test.dart | 1 + test/cli/node_test.dart | 1 + test/compressed_test.dart | 1 + test/dart_api/function_test.dart | 1 + test/dart_api/importer_test.dart | 1 + test/dart_api/logger_test.dart | 1 + test/dart_api/value/boolean_test.dart | 1 + test/dart_api/value/calculation_test.dart | 1 + test/dart_api/value/color_test.dart | 1 + test/dart_api/value/function_test.dart | 1 + test/dart_api/value/list_test.dart | 1 + test/dart_api/value/map_test.dart | 1 + test/dart_api/value/null_test.dart | 1 + test/dart_api/value/number_test.dart | 1 + test/dart_api/value/string_test.dart | 1 + test/dart_api_test.dart | 1 + test/deprecations_test.dart | 1 + test/doc_comments_test.dart | 1 + test/double_check_test.dart | 1 + test/embedded/embedded_process.dart | 1 + test/embedded/file_importer_test.dart | 1 + test/embedded/function_test.dart | 1 + test/embedded/importer_test.dart | 1 + test/embedded/length_delimited_test.dart | 1 + test/embedded/protocol_test.dart | 1 + test/output_test.dart | 1 + test/repo_test.dart | 1 + test/source_map_test.dart | 1 + 50 files changed, 55 insertions(+), 20 deletions(-) diff --git a/analysis/pubspec.yaml b/analysis/pubspec.yaml index 4e9257b82..cbf04dedc 100644 --- a/analysis/pubspec.yaml +++ b/analysis/pubspec.yaml @@ -6,7 +6,7 @@ homepage: https://github.com/sass/dart-sass/tree/master/analysis publish_to: none environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: - lints: ^2.0.0 + lints: ^4.0.0 diff --git a/lib/src/async_import_cache.dart b/lib/src/async_import_cache.dart index 6d6e4fa8c..6704249d4 100644 --- a/lib/src/async_import_cache.dart +++ b/lib/src/async_import_cache.dart @@ -318,8 +318,7 @@ final class AsyncImportCache { // If multiple original URLs canonicalize to the same thing, choose the // shortest one. minBy( - _canonicalizeCache.values - .whereNotNull() + _canonicalizeCache.values.nonNulls .where((result) => result.$2 == canonicalUrl) .map((result) => result.originalUrl), (url) => url.path.length) diff --git a/lib/src/extend/functions.dart b/lib/src/extend/functions.dart index 2fb1f2555..ca1d8c123 100644 --- a/lib/src/extend/functions.dart +++ b/lib/src/extend/functions.dart @@ -916,4 +916,4 @@ Iterable _selectorPseudoArgs( .whereType() .where((pseudo) => pseudo.isClass == isClass && pseudo.name == name) .map((pseudo) => pseudo.selector) - .whereNotNull(); + .nonNulls; diff --git a/lib/src/import_cache.dart b/lib/src/import_cache.dart index 9590b0e5a..6b46bce21 100644 --- a/lib/src/import_cache.dart +++ b/lib/src/import_cache.dart @@ -5,7 +5,7 @@ // DO NOT EDIT. This file was generated from async_import_cache.dart. // See tool/grind/synchronize.dart for details. // -// Checksum: 4362e28e5cd425786c235d2a6a2bb60539403799 +// Checksum: f70eea612e1613ef93bad353803ad9479cda04aa // // ignore_for_file: unused_import @@ -313,8 +313,7 @@ final class ImportCache { // If multiple original URLs canonicalize to the same thing, choose the // shortest one. minBy( - _canonicalizeCache.values - .whereNotNull() + _canonicalizeCache.values.nonNulls .where((result) => result.$2 == canonicalUrl) .map((result) => result.originalUrl), (url) => url.path.length) diff --git a/lib/src/importer/node_package.dart b/lib/src/importer/node_package.dart index d621ccf94..1d142fa4d 100644 --- a/lib/src/importer/node_package.dart +++ b/lib/src/importer/node_package.dart @@ -3,7 +3,6 @@ // https://opensource.org/licenses/MIT. import 'package:cli_pkg/js.dart'; -import 'package:collection/collection.dart'; import 'package:sass/src/util/map.dart'; import 'package:sass/src/util/nullable.dart'; @@ -239,7 +238,7 @@ class NodePackageImporter extends Importer { return null; }) - .whereNotNull() + .nonNulls .toList(); return switch (matches) { diff --git a/lib/src/io/js.dart b/lib/src/io/js.dart index 94e4f1a13..fee609540 100644 --- a/lib/src/io/js.dart +++ b/lib/src/io/js.dart @@ -105,9 +105,9 @@ Future readStdin() async { process.stdin.on('data', allowInterop(([Object? chunk]) { sink.add(chunk as List); })); - process.stdin.on('end', allowInterop(([Object? _]) { + process.stdin.on('end', allowInterop(([Object? arg]) { // Callback for 'end' receives no args. - assert(_ == null); + assert(arg == null); sink.close(); })); process.stdin.on('error', allowInterop(([Object? e]) { diff --git a/lib/src/js/value/calculation.dart b/lib/src/js/value/calculation.dart index 51dfadae8..b8e97a4c5 100644 --- a/lib/src/js/value/calculation.dart +++ b/lib/src/js/value/calculation.dart @@ -55,15 +55,10 @@ final JSClass calculationClass = () { if ((value == null && !_isValidClampArg(min)) || (max == null && ![min, value].any(_isValidClampArg))) { jsThrow(JsError('Expected at least one SassString or ' - 'CalculationInterpolation in `${[ - min, - value, - max - ].whereNotNull()}`')); + 'CalculationInterpolation in `${[min, value, max].nonNulls}`')); } - [min, value, max].whereNotNull().forEach(_assertCalculationValue); - return SassCalculation.unsimplified( - 'clamp', [min, value, max].whereNotNull()); + [min, value, max].nonNulls.forEach(_assertCalculationValue); + return SassCalculation.unsimplified('clamp', [min, value, max].nonNulls); } }); diff --git a/test/browser_test.dart b/test/browser_test.dart index 4e4aa4af8..a6efa9785 100644 --- a/test/browser_test.dart +++ b/test/browser_test.dart @@ -1,4 +1,5 @@ @TestOn('browser') +library; import 'package:js/js.dart'; import 'package:node_interop/js.dart'; diff --git a/test/cli/dart/colon_args_test.dart b/test/cli/dart/colon_args_test.dart index 6a8da9f78..e91700110 100644 --- a/test/cli/dart/colon_args_test.dart +++ b/test/cli/dart/colon_args_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/cli/dart/deprecations_test.dart b/test/cli/dart/deprecations_test.dart index 4b4a4244f..babccae82 100644 --- a/test/cli/dart/deprecations_test.dart +++ b/test/cli/dart/deprecations_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/cli/dart/errors_test.dart b/test/cli/dart/errors_test.dart index 478d2129f..a2318f0db 100644 --- a/test/cli/dart/errors_test.dart +++ b/test/cli/dart/errors_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; diff --git a/test/cli/dart/repl_test.dart b/test/cli/dart/repl_test.dart index d19641e14..36828952d 100644 --- a/test/cli/dart/repl_test.dart +++ b/test/cli/dart/repl_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/cli/dart/source_maps_test.dart b/test/cli/dart/source_maps_test.dart index 133bf719d..7a97e5bd0 100644 --- a/test/cli/dart/source_maps_test.dart +++ b/test/cli/dart/source_maps_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/cli/dart/update_test.dart b/test/cli/dart/update_test.dart index ef401f916..12351e91b 100644 --- a/test/cli/dart/update_test.dart +++ b/test/cli/dart/update_test.dart @@ -4,6 +4,7 @@ // OS X's modification time reporting is flaky, so we skip these tests on it. @TestOn('vm && !mac-os') +library; import 'package:test/test.dart'; diff --git a/test/cli/dart/watch_test.dart b/test/cli/dart/watch_test.dart index b50568d4f..7288dc468 100644 --- a/test/cli/dart/watch_test.dart +++ b/test/cli/dart/watch_test.dart @@ -8,6 +8,7 @@ // File watching is inherently flaky at the OS level. To mitigate this, we do a // few retries when the tests fail. @Retry(3) +library; import 'package:test/test.dart'; diff --git a/test/cli/dart_test.dart b/test/cli/dart_test.dart index 27a14c626..4c8ee35c6 100644 --- a/test/cli/dart_test.dart +++ b/test/cli/dart_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:convert'; diff --git a/test/cli/node/colon_args_test.dart b/test/cli/node/colon_args_test.dart index 0fb26c139..3852ee2db 100644 --- a/test/cli/node/colon_args_test.dart +++ b/test/cli/node/colon_args_test.dart @@ -4,6 +4,7 @@ @TestOn('vm') @Tags(['node']) +library; import 'package:test/test.dart'; diff --git a/test/cli/node/deprecations_test.dart b/test/cli/node/deprecations_test.dart index 88e383d2b..47c9c2fb8 100644 --- a/test/cli/node/deprecations_test.dart +++ b/test/cli/node/deprecations_test.dart @@ -4,6 +4,7 @@ @TestOn('vm') @Tags(['node']) +library; import 'package:test/test.dart'; diff --git a/test/cli/node/errors_test.dart b/test/cli/node/errors_test.dart index 87220b350..25e5d8dc9 100644 --- a/test/cli/node/errors_test.dart +++ b/test/cli/node/errors_test.dart @@ -4,6 +4,7 @@ @TestOn('vm') @Tags(['node']) +library; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; diff --git a/test/cli/node/repl_test.dart b/test/cli/node/repl_test.dart index 3fe23d2f4..18a5bdd43 100644 --- a/test/cli/node/repl_test.dart +++ b/test/cli/node/repl_test.dart @@ -4,6 +4,7 @@ @TestOn('vm') @Tags(['node']) +library; import 'package:test/test.dart'; diff --git a/test/cli/node/source_maps_test.dart b/test/cli/node/source_maps_test.dart index cf9939c3b..a33b370db 100644 --- a/test/cli/node/source_maps_test.dart +++ b/test/cli/node/source_maps_test.dart @@ -4,6 +4,7 @@ @TestOn('vm') @Tags(['node']) +library; import 'package:test/test.dart'; diff --git a/test/cli/node/update_test.dart b/test/cli/node/update_test.dart index 614f25da6..b423b428a 100644 --- a/test/cli/node/update_test.dart +++ b/test/cli/node/update_test.dart @@ -5,6 +5,7 @@ // OS X's modification time reporting is flaky, so we skip these tests on it. @TestOn('vm && !mac-os') @Tags(['node']) +library; import 'package:test/test.dart'; diff --git a/test/cli/node/watch_test.dart b/test/cli/node/watch_test.dart index 780b649d7..2de6bf452 100644 --- a/test/cli/node/watch_test.dart +++ b/test/cli/node/watch_test.dart @@ -9,6 +9,7 @@ // File watching is inherently flaky at the OS level. To mitigate this, we do a // few retries when the tests fail. @Retry(3) +library; import 'package:test/test.dart'; diff --git a/test/cli/node_test.dart b/test/cli/node_test.dart index 9169cc6aa..b3224d0fd 100644 --- a/test/cli/node_test.dart +++ b/test/cli/node_test.dart @@ -4,6 +4,7 @@ @TestOn('vm') @Tags(['node']) +library; import 'dart:convert'; diff --git a/test/compressed_test.dart b/test/compressed_test.dart index 3e383b3f1..e3368dcaa 100644 --- a/test/compressed_test.dart +++ b/test/compressed_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/function_test.dart b/test/dart_api/function_test.dart index bebefde0d..68403d424 100644 --- a/test/dart_api/function_test.dart +++ b/test/dart_api/function_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/importer_test.dart b/test/dart_api/importer_test.dart index 28ec53bee..cc8ca08cb 100644 --- a/test/dart_api/importer_test.dart +++ b/test/dart_api/importer_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:convert'; diff --git a/test/dart_api/logger_test.dart b/test/dart_api/logger_test.dart index 979b2ba11..96ee56ac8 100644 --- a/test/dart_api/logger_test.dart +++ b/test/dart_api/logger_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; import 'package:source_span/source_span.dart'; diff --git a/test/dart_api/value/boolean_test.dart b/test/dart_api/value/boolean_test.dart index 8a0579707..d46da602d 100644 --- a/test/dart_api/value/boolean_test.dart +++ b/test/dart_api/value/boolean_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/calculation_test.dart b/test/dart_api/value/calculation_test.dart index ed284db04..4ebe47d62 100644 --- a/test/dart_api/value/calculation_test.dart +++ b/test/dart_api/value/calculation_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/color_test.dart b/test/dart_api/value/color_test.dart index 6535c8a0c..dfa1b9d3a 100644 --- a/test/dart_api/value/color_test.dart +++ b/test/dart_api/value/color_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/function_test.dart b/test/dart_api/value/function_test.dart index 03776d07c..dee752533 100644 --- a/test/dart_api/value/function_test.dart +++ b/test/dart_api/value/function_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/list_test.dart b/test/dart_api/value/list_test.dart index e49605ce5..bd283680a 100644 --- a/test/dart_api/value/list_test.dart +++ b/test/dart_api/value/list_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/map_test.dart b/test/dart_api/value/map_test.dart index e82ef7f17..a6c82d442 100644 --- a/test/dart_api/value/map_test.dart +++ b/test/dart_api/value/map_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/null_test.dart b/test/dart_api/value/null_test.dart index 4badc075a..e9770a7e4 100644 --- a/test/dart_api/value/null_test.dart +++ b/test/dart_api/value/null_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api/value/number_test.dart b/test/dart_api/value/number_test.dart index 42741fdf9..0a9c7d203 100644 --- a/test/dart_api/value/number_test.dart +++ b/test/dart_api/value/number_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:math' as math; diff --git a/test/dart_api/value/string_test.dart b/test/dart_api/value/string_test.dart index 61d8023b2..702015e58 100644 --- a/test/dart_api/value/string_test.dart +++ b/test/dart_api/value/string_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/dart_api_test.dart b/test/dart_api_test.dart index 2fd8d6737..9c9c5a3d1 100644 --- a/test/dart_api_test.dart +++ b/test/dart_api_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:package_config/package_config.dart'; import 'package:path/path.dart' as p; diff --git a/test/deprecations_test.dart b/test/deprecations_test.dart index 28cd1e2fd..7f70213ff 100644 --- a/test/deprecations_test.dart +++ b/test/deprecations_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/doc_comments_test.dart b/test/doc_comments_test.dart index 82e2f5252..699ff15a2 100644 --- a/test/doc_comments_test.dart +++ b/test/doc_comments_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:sass/src/ast/sass.dart'; import 'package:test/test.dart'; diff --git a/test/double_check_test.dart b/test/double_check_test.dart index 44def85ae..6b8f67e96 100644 --- a/test/double_check_test.dart +++ b/test/double_check_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:io'; import 'dart:convert'; diff --git a/test/embedded/embedded_process.dart b/test/embedded/embedded_process.dart index 30279b0ba..89740b25c 100644 --- a/test/embedded/embedded_process.dart +++ b/test/embedded/embedded_process.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:async'; import 'dart:convert'; diff --git a/test/embedded/file_importer_test.dart b/test/embedded/file_importer_test.dart index 8d5bf4ec2..3fd68af7c 100644 --- a/test/embedded/file_importer_test.dart +++ b/test/embedded/file_importer_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:path/path.dart' as p; import 'package:test/test.dart'; diff --git a/test/embedded/function_test.dart b/test/embedded/function_test.dart index 97e79f334..e76cda9f8 100644 --- a/test/embedded/function_test.dart +++ b/test/embedded/function_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/embedded/importer_test.dart b/test/embedded/importer_test.dart index fdfc904d2..2eb1b1efd 100644 --- a/test/embedded/importer_test.dart +++ b/test/embedded/importer_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:source_maps/source_maps.dart' as source_maps; import 'package:test/test.dart'; diff --git a/test/embedded/length_delimited_test.dart b/test/embedded/length_delimited_test.dart index e329d1fdc..1d4c6fb62 100644 --- a/test/embedded/length_delimited_test.dart +++ b/test/embedded/length_delimited_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:async'; import 'dart:typed_data'; diff --git a/test/embedded/protocol_test.dart b/test/embedded/protocol_test.dart index b77d376e0..b1ffdee97 100644 --- a/test/embedded/protocol_test.dart +++ b/test/embedded/protocol_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; diff --git a/test/output_test.dart b/test/output_test.dart index c9dcfca1a..4a5f40cff 100644 --- a/test/output_test.dart +++ b/test/output_test.dart @@ -7,6 +7,7 @@ // implementation-specific to verify in sass-spec. @TestOn('vm') +library; import 'package:test/test.dart'; diff --git a/test/repo_test.dart b/test/repo_test.dart index 54d89fdbc..637899e7f 100644 --- a/test/repo_test.dart +++ b/test/repo_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'dart:io'; diff --git a/test/source_map_test.dart b/test/source_map_test.dart index 61b91120f..df4d0e4af 100644 --- a/test/source_map_test.dart +++ b/test/source_map_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. @TestOn('vm') +library; import 'package:charcode/charcode.dart'; import 'package:source_maps/source_maps.dart'; From 8541f80702fed85b678880d18d375a5d0dea41ff Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 1 Aug 2024 11:45:24 -0700 Subject: [PATCH 23/25] Add a changelog entry for sass/embedded-host-node#313 (#2296) --- CHANGELOG.md | 10 ++++++++++ pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8533ae1c8..0e16ccc28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 1.78.0 + +### Embedded Sass + +* Explicitly expose a `sass` executable from the `sass-embedded` npm package. + This was intended to be included in 1.63.0, but due to the way + platform-specific dependency executables are installed it did not work as + intended. Now users can run `npx sass` for local installs or just `sass` when + `sass-embedded` is installed globally. + ## 1.77.8 * No user-visible changes. diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 7753afacf..cbedd7005 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 10.5.0 + +* No user-visible changes. + ## 10.4.8 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 565bb7d8d..8ae210dbc 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.8 +version: 10.5.0-dev description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=3.0.0 <4.0.0" dependencies: - sass: 1.77.8 + sass: 1.78.0 dev_dependencies: dartdoc: ">=6.0.0 <9.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 1c78769ae..61bb6f35e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.77.8 +version: 1.78.0-dev description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From 9aeefc96e41da92e125ff6b633c454e8ebb9317a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 1 Aug 2024 13:14:34 -0700 Subject: [PATCH 24/25] Fix dart vm lockup during shutdown with pending requests (#2279) Co-authored-by: Natalie Weizenbaum --- CHANGELOG.md | 3 +++ lib/src/embedded/compilation_dispatcher.dart | 16 +++++++++++----- lib/src/embedded/reusable_isolate.dart | 6 ++---- pubspec.yaml | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e16ccc28..fbd3776c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ intended. Now users can run `npx sass` for local installs or just `sass` when `sass-embedded` is installed globally. +* Fix an edge case where the Dart VM could hang when shutting down when requests + were in flight. + ## 1.77.8 * No user-visible changes. diff --git a/lib/src/embedded/compilation_dispatcher.dart b/lib/src/embedded/compilation_dispatcher.dart index e8c3764b5..8f69b2553 100644 --- a/lib/src/embedded/compilation_dispatcher.dart +++ b/lib/src/embedded/compilation_dispatcher.dart @@ -64,8 +64,12 @@ final class CompilationDispatcher { /// Listens for incoming `CompileRequests` and runs their compilations. void listen() { do { - var packet = _mailbox.take(); - if (packet.isEmpty) break; + Uint8List packet; + try { + packet = _mailbox.take(); + } on StateError catch (_) { + break; + } try { var (compilationId, messageBuffer) = parsePacket(packet); @@ -322,12 +326,14 @@ final class CompilationDispatcher { message.id = _outboundRequestId; _send(message); - var packet = _mailbox.take(); - if (packet.isEmpty) { + Uint8List packet; + try { + packet = _mailbox.take(); + } on StateError catch (_) { // Compiler is shutting down, throw without calling `_handleError` as we // don't want to report this as an actual error. _requestError = true; - throw StateError('Compiler is shutting down.'); + rethrow; } try { diff --git a/lib/src/embedded/reusable_isolate.dart b/lib/src/embedded/reusable_isolate.dart index 0ed9eec8c..5cdd6bbd8 100644 --- a/lib/src/embedded/reusable_isolate.dart +++ b/lib/src/embedded/reusable_isolate.dart @@ -122,10 +122,8 @@ class ReusableIsolate { _receivePort.close(); // If the isolate is blocking on [Mailbox.take], it won't even process a - // kill event, so we send an empty message to make sure it wakes up. - try { - _mailbox.put(Uint8List(0)); - } on StateError catch (_) {} + // kill event, so we closed the mailbox to nofity and wake it up. + _mailbox.close(); } } diff --git a/pubspec.yaml b/pubspec.yaml index 61bb6f35e..bb851e64e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: http: "^1.1.0" js: ^0.6.3 meta: ^1.3.0 - native_synchronization: ^0.2.0 + native_synchronization: ^0.3.0 node_interop: ^2.1.0 package_config: ^2.0.0 path: ^1.8.0 From 613fb17878c79a1a2b0eae472793e09c25be61de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Mon, 5 Aug 2024 20:08:15 -0700 Subject: [PATCH 25/25] Add a changelog entry for https://github.com/sass/embedded-host-node/pull/323 (#2302) Co-authored-by: Natalie Weizenbaum --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbd3776c4..37a74369b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ intended. Now users can run `npx sass` for local installs or just `sass` when `sass-embedded` is installed globally. +* Add linux-riscv64, linux-musl-riscv64, and android-riscv64 support for the + `sass-embedded` npm package. + * Fix an edge case where the Dart VM could hang when shutting down when requests were in flight.