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" diff --git a/.github/util/initialize/action.yml b/.github/util/initialize/action.yml index acfa759c2..cba0719ba 100644 --- a/.github/util/initialize/action.yml +++ b/.github/util/initialize/action.yml @@ -17,20 +17,38 @@ 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 - shell: bash + shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }} - run: npm install - shell: bash + shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }} - - 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. + # 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 run: dart run grinder protobuf env: {UPDATE_SASS_SASS_REPO: false} - shell: bash + shell: ${{ runner.os == 'Windows' && 'powershell' || 'bash' }} 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 5f4ba2639..27bc592a7 100644 --- a/.github/workflows/build-linux-musl.yml +++ b/.github/workflows/build-linux-musl.yml @@ -8,27 +8,27 @@ 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/386 + runner: ubuntu-latest + platform: linux/amd64 - 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 - # There is no docker image for riscv64 dart-sdk, build kernel snapshot instead. + runner: linux-arm64 + platform: linux/arm/v7 - arch: riscv64 - platform: linux/amd64 # linux/riscv64 + runner: ubuntu-latest + platform: linux/riscv64 steps: - uses: actions/checkout@v4 @@ -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 c8f5ddd41..4f0d3450c 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -8,24 +8,27 @@ 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/amd64 - - arch: arm - platform: linux/arm/v7 - arch: arm64 + runner: linux-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: arm + runner: linux-arm64 + platform: linux/arm/v7 - arch: riscv64 - platform: linux/amd64 # linux/riscv64 + runner: ubuntu-latest + platform: linux/riscv64 steps: - uses: actions/checkout@v4 @@ -46,6 +49,7 @@ jobs: EOF - name: Build + if: matrix.arch != 'riscv64' run: | docker run --rm -i \ --platform ${{ matrix.platform }} \ @@ -57,6 +61,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: 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index c6d344d64..39e64c69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.78.0 +## 1.79.0 * **Breaking change**: Passing a number with unit `%` to the `$alpha` parameter of `color.change()`, `color.adjust()`, `change-color()`, and `adjust-color()` @@ -188,6 +188,58 @@ * Remove `RgbColor`, `HslColor` and `HwbColor` SassScript values. +## 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. + +* 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. + +## 1.77.8 + +* No user-visible changes. + +## 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 + CSS output. + +## 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`. + +## 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/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/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 4301d13e1..930d49e08 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 423ad794c..acc86949e 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/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/deprecation.dart b/lib/src/deprecation.dart index 6b9360575..fc5d678b0 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: eb5e3889156f5ed12e119f11786f06f91a5f05c2 + // Checksum: b87f31f543f52c97431cce85ef11e92b6a71cfde /// Deprecation for passing a string directly to meta.call(). callString('call-string', @@ -90,14 +90,19 @@ 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 certain uses of built-in sass:color functions. color4Api('color-4-api', - deprecatedIn: '1.78.0', + deprecatedIn: '1.79.0', description: 'Certain uses of built-in sass:color functions.'), /// Deprecation for using global color functions instead of sass:color. colorFunctions('color-functions', - deprecatedIn: '1.78.0', + deprecatedIn: '1.79.0', description: 'Using global color functions instead of sass:color.'), /// Deprecation for @import rules. diff --git a/lib/src/embedded/compilation_dispatcher.dart b/lib/src/embedded/compilation_dispatcher.dart index 675216022..8f69b2553 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; @@ -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); @@ -125,20 +129,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) => @@ -308,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/lib/src/extend/extension_store.dart b/lib/src/extend/extension_store.dart index 5f760005d..c450bb7e8 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..ca1d8c123 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 @@ -908,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/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/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 b1971ed58..361727c1e 100644 --- a/lib/src/parse/stylesheet.dart +++ b/lib/src/parse/stylesheet.dart @@ -385,7 +385,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)); } @@ -537,7 +538,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)); } @@ -775,10 +777,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)); @@ -840,7 +847,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); } @@ -959,6 +969,7 @@ abstract class StylesheetParser extends Parser { } var configuration = _configuration(allowGuarded: true); + whitespace(); expectStatementSeparator("@forward rule"); var span = scanner.spanFrom(start); @@ -1424,8 +1435,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) { @@ -1547,7 +1557,7 @@ abstract class StylesheetParser extends Parser { Interpolation? value; if (scanner.peekChar() != $exclamation && !atEndOfStatement()) { - value = almostAnyValue(); + value = _interpolatedDeclarationValue(allowOpenBrace: false); } AtRule rule; @@ -1572,7 +1582,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)); } @@ -2745,13 +2755,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}) { @@ -2770,11 +2778,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: @@ -2791,12 +2809,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; @@ -2827,11 +2850,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. @@ -2851,7 +2882,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; @@ -2879,6 +2925,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); @@ -2904,13 +2953,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/lib/src/visitor/async_evaluate.dart b/lib/src/visitor/async_evaluate.dart index faebc5a84..7d1a489af 100644 --- a/lib/src/visitor/async_evaluate.dart +++ b/lib/src/visitor/async_evaluate.dart @@ -1191,6 +1191,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); @@ -2061,8 +2077,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) { @@ -2106,13 +2134,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 dc84eb4ea..36bb0477e 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: 76a5e462c0095a314ea445f2c236d7f046f7b7b1 +// Checksum: b40f3e7568d9e987dde6633424073afdc6a69349 // // ignore_for_file: unused_import @@ -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 = _interpolationToValue(node.name, warnForColor: true); if (_declarationName case var declarationName?) { name = CssValue("$declarationName-${name.value}", name.span); @@ -2051,8 +2067,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) { @@ -2096,13 +2124,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 dfb6bbae3..8061e65ab 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -49,6 +49,30 @@ * Added `SassNumber.convertValueToUnit()` as a shorthand for `SassNumber.convertValue()` with a single numerator. +## 10.5.0 + +* No user-visible changes. + +## 10.4.8 + +* No user-visible changes. + +## 10.4.7 + +* No user-visible changes. + +## 10.4.6 + +* No user-visible changes. + +## 10.4.5 + +* No user-visible changes. + +## 10.4.4 + +* No user-visible changes. + ## 10.4.3 * No user-visible changes. diff --git a/pubspec.yaml b/pubspec.yaml index 8db5f13f8..5b278ec31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.78.0-dev # TODO: update the color-4-api and color-functions deprecations when this is updated +version: 1.79.0-dev # TODO: update the color-4-api and color-functions deprecations when this is updated description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass @@ -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 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 9f8c1dbaf..aa637e93d 100644 --- a/test/dart_api/value/color_test.dart +++ b/test/dart_api/value/color_test.dart @@ -4,6 +4,7 @@ @Skip("TODO(nweiz): Update these for the new Color API") @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 157963477..9b3594c09 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 3b03c941b..ceb6ec929 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'; diff --git a/tool/grind.dart b/tool/grind.dart index b7e2620cf..615a22903 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.')