From 0f2c993505e01ac7d7ee5edc26e88909505dd207 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 11 Feb 2019 15:25:59 -0800 Subject: [PATCH 001/162] Boilerplate files --- CODE_OF_CONDUCT.md | 10 ++++++++++ CONTRIBUTING.md | 23 +++++++++++++++++++++++ LICENSE | 20 ++++++++++++++++++++ README.md | 11 +++++++++++ 4 files changed, 64 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..dfc4c84a7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,10 @@ +Sass is more than a technology; Sass is driven by the community of individuals +that power its development and use every day. As a community, we want to embrace +the very differences that have made our collaboration so powerful, and work +together to provide the best environment for learning, growing, and sharing of +ideas. It is imperative that we keep Sass a fun, welcoming, challenging, and +fair place to play. + +[The full community guidelines can be found on the Sass website.][link] + +[link]: http://sass-lang.com/community-guidelines diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..c980350f8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# How to Contribute + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement. You (or your employer) retain the copyright to your contribution; +this simply gives us permission to use and redistribute your contributions as +part of the project. Head over to to see +your current agreements on file or to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..8a27198c7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2019, Google LLC + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000..228642276 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +## Embedded Dart Sass + +This is a wrapper for [Dart Sass][] that implements the compiler side of the +[Embedded Sass protocol][]. It's designed to be embedded in a host language, +which then exposes an API for users to invoke Sass and define custom functions +and importers. + +[Dart Sass]: https://sass-lang.com/dart-sass +[Embedded Sass protocol]: https://github.com/sass/sass-embedded-protocol/blob/master/README.md#readme + +Disclaimer: this is not an official Google product. From be35dbb7cc0337ae0006906bd0fc21e684b4b9b5 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 29 Oct 2019 21:05:18 +0000 Subject: [PATCH 002/162] Add a length-delimited StreamChannelTransformer (#1) This implements the packet scheme that the embedded protocol uses when communicating over stdin and stdout. --- .gitignore | 30 ++++ .../util/length_delimited_transformer.dart | 114 +++++++++++++++ pubspec.yaml | 15 ++ test/length_delimited_test.dart | 137 ++++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 .gitignore create mode 100644 lib/src/util/length_delimited_transformer.dart create mode 100644 pubspec.yaml create mode 100644 test/length_delimited_test.dart diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2bc89f310 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Created by https://www.gitignore.io/api/dart +# Edit at https://www.gitignore.io/?templates=dart + +### Dart ### +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +# End of https://www.gitignore.io/api/dart + +# Generated protocol buffer files. +*.pb*.dart diff --git a/lib/src/util/length_delimited_transformer.dart b/lib/src/util/length_delimited_transformer.dart new file mode 100644 index 000000000..c516fb5fb --- /dev/null +++ b/lib/src/util/length_delimited_transformer.dart @@ -0,0 +1,114 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:async'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:async/async.dart'; +import 'package:stream_channel/stream_channel.dart'; + +/// A [StreamChannelTransformer] that converts a channel that sends and receives +/// arbitrarily-chunked binary data to one that sends and receives packets of +/// set length using [lengthDelimitedEncoder] and [lengthDelimitedDecoder]. +final StreamChannelTransformer> lengthDelimited = + StreamChannelTransformer>(lengthDelimitedDecoder, + StreamSinkTransformer.fromStreamTransformer(lengthDelimitedEncoder)); + +/// A transformer that converts an arbitrarily-chunked byte stream where each +/// packet is prefixed with a 32-bit little-endian number indicating its length +/// into a stream of packet contents. +final lengthDelimitedDecoder = + StreamTransformer, Uint8List>.fromBind((stream) { + // The buffer into which the four-byte little-endian length of the next packet + // will be written. + var lengthBuffer = Uint8List(4); + + // The index of the next byte to write to [lengthBuffer]. Once this is equal + // to [lengthBuffer.length], the full length is available. + var lengthBufferIndex = 0; + + // The length of the next message, in bytes, read from [lengthBuffer] once + // it's full. + int nextMessageLength; + + // The buffer into which the packet data itself is written. Initialized once + // [nextMessageLength] is known. + Uint8List buffer; + + // The index of the next byte to write to [buffer]. Once this is equal to + // [buffer.length] (or equivalently [nextMessageLength]), the full packet is + // available. + int bufferIndex; + + // It seems a little silly to use a nested [StreamTransformer] here, but we + // need the outer one to establish a closure context so we can share state + // across different input chunks, and the inner one takes care of all the + // boilerplate of creating a new stream based on [stream]. + return stream + .transform(StreamTransformer.fromHandlers(handleData: (chunk, sink) { + // The index of the next byte to read from [chunk]. We have to track this + // because the chunk may contain the length *and* the message, or even + // multiple messages. + var i = 0; + + // Adds bytes from [chunk] to [destination] at [destinationIndex] without + // overflowing the bounds of [destination], and increments [i] for each byte + // written. + // + // Returns the number of bytes written. + int writeFromChunk(Uint8List destination, int destinationIndex) { + var bytesToWrite = + math.min(destination.length - destinationIndex, chunk.length - i); + destination.setRange( + destinationIndex, destinationIndex + bytesToWrite, chunk, i); + i += bytesToWrite; + return bytesToWrite; + } + + while (i < chunk.length) { + // We can be in one of two states here: + // + // * Both [nextMessageLength] and [buffer] are `null`, in which case we're + // waiting until we have four bytes in [lengthBuffer] to know how big of + // a buffer to allocate. + // + // * Neither [nextMessageLength] nor [buffer] are `null`, in which case + // we're waiting for [buffer] to have [nextMessageLength] in it before + // we send it to [queue.local.sink] and start waiting for the next + // message. + if (nextMessageLength == null) { + lengthBufferIndex += writeFromChunk(lengthBuffer, lengthBufferIndex); + if (lengthBufferIndex < 4) return; + + nextMessageLength = + ByteData.view(lengthBuffer.buffer).getUint32(0, Endian.little); + buffer = Uint8List(nextMessageLength); + bufferIndex = 0; + } + + bufferIndex += writeFromChunk(buffer, bufferIndex); + if (bufferIndex < nextMessageLength) return; + + sink.add(Uint8List.view(buffer.buffer, 0, nextMessageLength)); + lengthBufferIndex = 0; + nextMessageLength = null; + buffer = null; + bufferIndex = null; + } + })); +}); + +/// A transformer that adds 32-bit little-endian numbers indicating the length +/// of each packet, so that they can safely be sent over a medium that doesn't +/// preserve packet boundaries. +final lengthDelimitedEncoder = + StreamTransformer>.fromHandlers( + handleData: (message, sink) { + var messageLength = Uint8List(4); + ByteData.view(messageLength.buffer) + .setUint32(0, message.length, Endian.little); + sink.add(messageLength); + sink.add(message); +}); diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 000000000..1df7cb78e --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,15 @@ +name: sass_embedded +version: 1.0.0-dev +description: An implementation of the Sass embedded protocol using Dart Sass. +author: Sass Team +homepage: https://github.com/sass/dart-sass-embedded + +environment: + sdk: '>=2.4.0 <3.0.0' + +dependencies: + async: ">=1.13.0 <3.0.0" + stream_channel: ">=1.6.0 <3.0.0" + +dev_dependencies: + test: ^1.0.0 diff --git a/test/length_delimited_test.dart b/test/length_delimited_test.dart new file mode 100644 index 000000000..f309ea7eb --- /dev/null +++ b/test/length_delimited_test.dart @@ -0,0 +1,137 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; + +import 'package:async/async.dart'; +import 'package:test/test.dart'; + +void main() { + group("encoder", () { + Sink> sink; + Stream> stream; + setUp(() { + var controller = StreamController>(); + sink = controller.sink; + stream = controller.stream.transform(lengthDelimitedEncoder); + }); + + test("encodes an empty message", () { + sink.add([]); + sink.close(); + expect(collectBytes(stream), completion(equals([0, 0, 0, 0]))); + }); + + test("encodes a message of length 1", () { + sink.add([123]); + sink.close(); + expect(collectBytes(stream), completion(equals([1, 0, 0, 0, 123]))); + }); + + test("encodes a message of length greater than 256", () { + sink.add(List.filled(300, 1)); + sink.close(); + expect(collectBytes(stream), + completion(equals([44, 1, 0, 0, ...List.filled(300, 1)]))); + }); + + test("encodes multiple messages", () { + sink.add([10]); + sink.add([20, 30]); + sink.add([40, 50, 60]); + sink.close(); + expect( + collectBytes(stream), + completion(equals( + [1, 0, 0, 0, 10, 2, 0, 0, 0, 20, 30, 3, 0, 0, 0, 40, 50, 60]))); + }); + }); + + group("decoder", () { + Sink> sink; + StreamQueue queue; + setUp(() { + var controller = StreamController>(); + sink = controller.sink; + queue = StreamQueue(controller.stream.transform(lengthDelimitedDecoder)); + }); + + group("decodes an empty message", () { + test("from a single chunk", () { + sink.add([0, 0, 0, 0]); + expect(queue, emits(isEmpty)); + }); + + test("from multiple chunks", () { + sink.add([0, 0]); + sink.add([0, 0]); + expect(queue, emits(isEmpty)); + }); + + test("from one chunk per byte", () { + sink..add([0])..add([0])..add([0])..add([0]); + expect(queue, emits(isEmpty)); + }); + + test("from a chunk that contains more data", () { + sink.add([0, 0, 0, 0, 1, 0, 0, 0, 100]); + expect(queue, emits(isEmpty)); + }); + }); + + group("decodes a longer message", () { + test("from a single chunk", () { + sink.add([4, 0, 0, 0, 1, 2, 3, 4]); + expect(queue, emits([1, 2, 3, 4])); + }); + + test("from multiple chunks", () { + sink..add([4, 0])..add([0, 0, 1, 2])..add([3, 4]); + expect(queue, emits([1, 2, 3, 4])); + }); + + test("from one chunk per byte", () { + for (var byte in [4, 0, 0, 0, 1, 2, 3, 4]) { + sink.add([byte]); + } + expect(queue, emits([1, 2, 3, 4])); + }); + + test("from a chunk that contains more data", () { + sink.add([4, 0, 0, 0, 1, 2, 3, 4, 1, 0, 0, 0]); + expect(queue, emits([1, 2, 3, 4])); + }); + + test("of length greater than 256", () { + sink.add([44, 1, 0, 0, ...List.filled(300, 1)]); + expect(queue, emits(List.filled(300, 1))); + }); + }); + + group("decodes multiple messages", () { + test("from single chunk", () { + sink.add([4, 0, 0, 0, 1, 2, 3, 4, 2, 0, 0, 0, 101, 102]); + expect(queue, emits([1, 2, 3, 4])); + expect(queue, emits([101, 102])); + }); + + test("from multiple chunks", () { + sink..add([4, 0])..add([0, 0, 1, 2, 3, 4, 2, 0])..add([0, 0, 101, 102]); + expect(queue, emits([1, 2, 3, 4])); + expect(queue, emits([101, 102])); + }); + + test("from one chunk per byte", () { + for (var byte in [4, 0, 0, 0, 1, 2, 3, 4, 2, 0, 0, 0, 101, 102]) { + sink.add([byte]); + } + expect(queue, emits([1, 2, 3, 4])); + expect(queue, emits([101, 102])); + }); + }); + }); +} From a6278310cb35056e744315a4235b0508d3415b05 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 29 Oct 2019 17:00:57 -0700 Subject: [PATCH 003/162] Enable Travis --- .travis.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..0ca1744c5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: dart +branches: + only: + - master + # Semantic version tags and legacy branches of the form "1.2.x". + - "/^\\d+\\.\\d+\\.(\\d+([+-].*)?|x)$/" + +cache: + directories: + - $HOME/.pub-cache + +jobs: + include: + + # Testing + - dart: stable + dart_task: test + - dart: dev + dart_task: test + - dart: stable + os: windows + dart_task: test + - dart: stable + os: osx + dart_task: test + + # Static checks + - dart_task: {dartanalyzer: --fatal-warnings ./} + - dart_task: dartfmt From 7f75f80fb4a2c9446d41c657685a6e9d5dfb5a2a Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 30 Oct 2019 12:10:20 -0700 Subject: [PATCH 004/162] Make the test StreamController work with lengthDelimitedEncoder --- test/length_delimited_test.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/length_delimited_test.dart b/test/length_delimited_test.dart index f309ea7eb..c0cd1ce2e 100644 --- a/test/length_delimited_test.dart +++ b/test/length_delimited_test.dart @@ -17,7 +17,9 @@ void main() { setUp(() { var controller = StreamController>(); sink = controller.sink; - stream = controller.stream.transform(lengthDelimitedEncoder); + stream = controller.stream + .map((chunk) => Uint8List.fromList(chunk)) + .transform(lengthDelimitedEncoder); }); test("encodes an empty message", () { From 3bf67e0011efd9087ecf1aad2177f07f53d28105 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 16 Oct 2019 16:25:37 -0700 Subject: [PATCH 005/162] Add a grinder task to generate protocol buffer libraries --- pubspec.yaml | 3 +++ tool/grind.dart | 43 +++++++++++++++++++++++++++++++++++++++++++ tool/utils.dart | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tool/grind.dart create mode 100644 tool/utils.dart diff --git a/pubspec.yaml b/pubspec.yaml index 1df7cb78e..079e0d635 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,10 @@ environment: dependencies: async: ">=1.13.0 <3.0.0" + protobuf: ^1.0.0 stream_channel: ">=1.6.0 <3.0.0" dev_dependencies: + grinder: ^0.8.0 + path: ^1.6.0 test: ^1.0.0 diff --git a/tool/grind.dart b/tool/grind.dart new file mode 100644 index 000000000..27795f057 --- /dev/null +++ b/tool/grind.dart @@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:io'; + +import 'package:grinder/grinder.dart'; + +import 'utils.dart'; + +main(List args) => grind(args); + +@Task('Compile the protocol buffer definition to a Dart library.') +protobuf() async { + Directory('build').createSync(recursive: true); + + // Make sure we use the version of protoc_plugin defined by our pubspec, + // rather than whatever version the developer might have globally installed. + log("Writing protoc-gen-dart"); + if (Platform.isWindows) { + File('build/protoc-gen-dart.bat').writeAsStringSync(''' +@echo off +pub run protoc_plugin %* +'''); + } else { + File('build/protoc-gen-dart') + .writeAsStringSync('pub run protoc_plugin "\$@"'); + runProcess('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); + } + + await cloneOrPull("git://github.com/sass/embedded-protocol"); + await runAsync("protoc", + arguments: [ + "-Ibuild/embedded-protocol", + "embedded_sass.proto", + "--dart_out=lib/src/" + ], + runOptions: RunOptions(environment: { + "PATH": 'build' + + (Platform.isWindows ? ";" : ":") + + Platform.environment["PATH"] + })); +} diff --git a/tool/utils.dart b/tool/utils.dart new file mode 100644 index 000000000..d5059b543 --- /dev/null +++ b/tool/utils.dart @@ -0,0 +1,42 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:io'; + +import 'package:grinder/grinder.dart'; +import 'package:path/path.dart' as p; + +/// Ensure that the repository at [url] is cloned into the build directory and +/// pointing to the latest master revision. +/// +/// Returns the path to the repository. +Future cloneOrPull(String url) async => + cloneOrCheckout(url, "origin/master"); + +/// Ensure that the repository at [url] is cloned into the build directory and +/// pointing to [ref]. +/// +/// Returns the path to the repository. +Future cloneOrCheckout(String url, String ref) async { + var name = p.url.basename(url); + if (p.url.extension(name) == ".git") name = p.url.withoutExtension(name); + + var path = p.join("build", name); + + if (Directory(p.join(path, '.git')).existsSync()) { + log("Updating $url"); + await runAsync("git", + arguments: ["fetch", "origin"], workingDirectory: path); + } else { + delete(Directory(path)); + await runAsync("git", arguments: ["clone", url, path]); + await runAsync("git", + arguments: ["config", "advice.detachedHead", "false"], + workingDirectory: path); + } + await runAsync("git", arguments: ["checkout", ref], workingDirectory: path); + log(""); + + return path; +} From ea4f9f72047c165721e64f67d4e8781e94f483f2 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 1 Nov 2019 14:19:57 -0700 Subject: [PATCH 006/162] Generate protobufs on Travis --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0ca1744c5..9c6f8c345 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,24 @@ cache: directories: - $HOME/.pub-cache +env: + global: + - PROTOBUF_VERSION=3.10.1 + - PATH="$HOME/protoc/bin:$PATH" + +before_install: +- if [[ "$TRAVIS_OS_NAME" = windows ]]; then + curl -Lo protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-win64.zip; + else + curl -Lo protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-${TRAVIS_OS_NAME}-x86_64.zip; + fi +- unzip -d "$HOME/protoc" protoc.zip + +before_script: +- pub run grinder protobuf +# Format the generated code or else the formatter task will get upset. +- dartfmt -w --fix lib/src/embedded_sass.pb* + jobs: include: From 7489d5796de6e3b2e9e9ab5885216b0f9eac220b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 25 Oct 2019 13:00:47 -0700 Subject: [PATCH 007/162] Add a very basic protocol dispatcher and a few tests Currently this doesn't actually invoke the compiler, it just always returns the expanded output for "a {b: c}". --- bin/dart_sass_embedded.dart | 31 ++++++ lib/src/dispatcher.dart | 120 +++++++++++++++++++++++ pubspec.yaml | 5 + test/embedded_process.dart | 183 ++++++++++++++++++++++++++++++++++++ test/protocol_test.dart | 47 +++++++++ test/utils.dart | 61 ++++++++++++ 6 files changed, 447 insertions(+) create mode 100644 bin/dart_sass_embedded.dart create mode 100644 lib/src/dispatcher.dart create mode 100644 test/embedded_process.dart create mode 100644 test/protocol_test.dart create mode 100644 test/utils.dart diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart new file mode 100644 index 000000000..236951dfa --- /dev/null +++ b/bin/dart_sass_embedded.dart @@ -0,0 +1,31 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:io'; + +import 'package:stream_channel/stream_channel.dart'; + +import 'package:sass_embedded/src/dispatcher.dart'; +import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; + +void main(List args) { + if (args.isNotEmpty) { + stderr.writeln( + "This executable is not intended to be executed with arguments.\n" + "See https://github.com/sass/embedded-protocol#readme for details."); + // USAGE error from https://bit.ly/2poTt90 + exitCode = 64; + return; + } + + var dispatcher = Dispatcher( + StreamChannel.withGuarantees(stdin, stdout, allowSinkErrors: false) + .transform(lengthDelimited)); + dispatcher.listen((request) { + return OutboundMessage_CompileResponse() + ..success = (OutboundMessage_CompileResponse_CompileSuccess() + ..css = "a {\n b: c;\n}\n"); + }); +} diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart new file mode 100644 index 000000000..8d9e021e1 --- /dev/null +++ b/lib/src/dispatcher.dart @@ -0,0 +1,120 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:protobuf/protobuf.dart'; +import 'package:stack_trace/stack_trace.dart'; +import 'package:stream_channel/stream_channel.dart'; + +import 'embedded_sass.pb.dart'; + +/// A class that dispatches messages to and from the host. +class Dispatcher { + /// The channel of encoded protocol buffers, connected to the host. + final StreamChannel _channel; + + /// Creates a [Dispatcher] that sends and receives encoded protocol buffers + /// over [channel]. + Dispatcher(this._channel); + + /// Listens for incoming `CompileRequests` and passes them to [callback]. + /// + /// The callback must return a `CompileResponse` which is sent to the host. It + /// doesn't need to set [OutboundMessage_CompileResponse.id]; the [Dispatcher] + /// will take care of that. + /// + /// This may only be called once. + void listen( + FutureOr callback( + InboundMessage_CompileRequest request)) { + _channel.stream.listen((binaryMessage) async { + InboundMessage message; + try { + try { + message = InboundMessage.fromBuffer(binaryMessage); + } on InvalidProtocolBufferException catch (error) { + throw _parseError(error.message); + } + + switch (message.whichMessage()) { + case InboundMessage_Message.error: + var error = message.ensureError(); + stderr + .write("Host reported ${error.type.name.toLowerCase()} error"); + if (error.id != -1) stderr.write(" with request ${error.id}"); + stderr.writeln(": ${error.message}"); + // SOFTWARE error from https://bit.ly/2poTt90 + exitCode = 70; + _channel.sink.close(); + break; + + case InboundMessage_Message.compileRequest: + var request = message.ensureCompileRequest(); + var response = await callback(request); + response.id = request.id; + _send(OutboundMessage()..compileResponse = response); + break; + + case InboundMessage_Message.notSet: + // PROTOCOL error from https://bit.ly/2poTt90 + exitCode = 76; + throw _parseError("InboundMessage.message is not set."); + + default: + // PROTOCOL error from https://bit.ly/2poTt90 + exitCode = 76; + throw _parseError( + "Unknown message type: ${message.toDebugString()}"); + } + } on ProtocolError catch (error) { + error.id = _messageId(message) ?? -1; + stderr.write("Host caused ${error.type.name.toLowerCase()} error"); + if (error.id != -1) stderr.write(" with request ${error.id}"); + stderr.writeln(": ${error.message}"); + _send(OutboundMessage()..error = error); + } catch (error, stackTrace) { + var errorMessage = "$error\n${Chain.forTrace(stackTrace)}"; + stderr.write("Internal compiler error: $errorMessage"); + _send(OutboundMessage() + ..error = (ProtocolError() + ..type = ProtocolError_ErrorType.INTERNAL + ..id = _messageId(message) ?? -1 + ..message = errorMessage)); + _channel.sink.close(); + } + }); + } + + /// Sends [message] to the host. + void _send(OutboundMessage message) => + _channel.sink.add(message.writeToBuffer()); + + /// Returns a [ProtocolError] with type `PARSE` and the given [message]. + ProtocolError _parseError(String message) => ProtocolError() + ..type = ProtocolError_ErrorType.PARSE + ..message = message; + + /// Returns the id for [message] if it it's a request or response, or `null` + /// otherwise. + int _messageId(InboundMessage message) { + if (message == null) return null; + switch (message.whichMessage()) { + case InboundMessage_Message.compileRequest: + return message.ensureCompileRequest().id; + case InboundMessage_Message.canonicalizeResponse: + return message.ensureCanonicalizeResponse().id; + case InboundMessage_Message.importResponse: + return message.ensureImportResponse().id; + case InboundMessage_Message.functionCallRequest: + return message.ensureFunctionCallRequest().id; + case InboundMessage_Message.functionCallResponse: + return message.ensureFunctionCallResponse().id; + default: + return null; + } + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 079e0d635..e46f0ceec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,12 +7,17 @@ homepage: https://github.com/sass/dart-sass-embedded environment: sdk: '>=2.4.0 <3.0.0' +executables: + dart-sass-embedded: dart_sass_embedded + dependencies: async: ">=1.13.0 <3.0.0" protobuf: ^1.0.0 + stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" dev_dependencies: grinder: ^0.8.0 + protoc_plugin: ^19.0.0 path: ^1.6.0 test: ^1.0.0 diff --git a/test/embedded_process.dart b/test/embedded_process.dart new file mode 100644 index 000000000..167c69d59 --- /dev/null +++ b/test/embedded_process.dart @@ -0,0 +1,183 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:async/async.dart'; +import 'package:test/test.dart'; + +import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; + +/// A wrapper for [Process] that provides a convenient API for testing the +/// embedded Sass process. +/// +/// If the test fails, this will automatically print out any stderr and protocol +/// buffers from the process to aid debugging. +/// +/// This API is based on the `test_process` package. +class EmbeddedProcess { + /// The underlying process. + final Process _process; + + /// A [StreamQueue] that emits each outbound protocol buffer from the process. + StreamQueue get outbound => _outbound; + StreamQueue _outbound; + + /// A [StreamQueue] that emits each line of stderr from the process. + StreamQueue get stderr => _stderr; + StreamQueue _stderr; + + /// A splitter that can emit new copies of [outbound]. + final StreamSplitter _outboundSplitter; + + /// A splitter that can emit new copies of [stderr]. + final StreamSplitter _stderrSplitter; + + /// A sink into which inbound messages can be passed to the process. + final Sink inbound; + + /// The raw standard input byte sink. + IOSink get stdin => _process.stdin; + + /// A log that includes lines from [stderr] and human-friendly serializations + /// of protocol buffers from [outbound] + final _log = []; + + /// Whether [_log] has been passed to [printOnFailure] yet. + bool _loggedOutput = false; + + /// Returns a [Future] which completes to the exit code of the process, once + /// it completes. + Future get exitCode => _process.exitCode; + + /// The process ID of the process. + int get pid => _process.pid; + + /// Completes to [_process]'s exit code if it's exited, otherwise completes to + /// `null` immediately. + Future get _exitCodeOrNull async => + await exitCode.timeout(Duration.zero, onTimeout: () => null); + + /// Starts a process. + /// + /// [executable], [workingDirectory], [environment], + /// [includeParentEnvironment], and [runInShell] have the same meaning as for + /// [Process.start]. + /// + /// If [forwardOutput] is `true`, the process's [outbound] messages and + /// [stderr] will be printed to the console as they appear. This is only + /// intended to be set temporarily to help when debugging test failures. + static Future start( + {String workingDirectory, + Map environment, + bool includeParentEnvironment = true, + bool runInShell = false, + bool forwardOutput = false}) async { + // TODO(nweiz): Support running from a native executable. + var process = await Process.start( + Platform.executable, ["bin/dart_sass_embedded.dart"], + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell); + + return EmbeddedProcess._(process, forwardOutput: forwardOutput); + } + + /// Creates a [EmbeddedProcess] for [process]. + /// + /// The [forwardOutput] argument is the same as that to [start]. + EmbeddedProcess._(Process process, {bool forwardOutput = false}) + : _process = process, + _outboundSplitter = StreamSplitter(process.stdout + .transform(lengthDelimitedDecoder) + .map((message) => OutboundMessage.fromBuffer(message))), + _stderrSplitter = StreamSplitter(process.stderr + .transform(utf8.decoder) + .transform(const LineSplitter())), + inbound = StreamSinkTransformer>.fromHandlers( + handleData: (message, sink) => + sink.add(message.writeToBuffer())).bind( + StreamSinkTransformer.fromStreamTransformer(lengthDelimitedEncoder) + .bind(process.stdin)) { + addTearDown(_tearDown); + expect(_process.exitCode.then((_) => _logOutput()), completes, + reason: "Process `dart_sass_embedded` never exited."); + + _outbound = StreamQueue(_outboundSplitter.split()); + _stderr = StreamQueue(_stderrSplitter.split()); + + _outboundSplitter.split().listen((message) { + for (var line in message.toDebugString().split("\n")) { + if (forwardOutput) print(line); + _log.add(" $line"); + } + }); + + _stderrSplitter.split().listen((line) { + if (forwardOutput) print(line); + _log.add("[e] $line"); + }); + } + + /// A callback that's run when the test completes. + Future _tearDown() async { + // If the process is already dead, do nothing. + if (await _exitCodeOrNull != null) return; + + _process.kill(ProcessSignal.sigkill); + + // Log output now rather than waiting for the exitCode callback so that + // it's visible even if we time out waiting for the process to die. + await _logOutput(); + } + + /// Formats the contents of [_log] and passes them to [printOnFailure]. + Future _logOutput() async { + if (_loggedOutput) return; + _loggedOutput = true; + + var exitCodeOrNull = await _exitCodeOrNull; + + // Wait a timer tick to ensure that all available lines have been flushed to + // [_log]. + await Future.delayed(Duration.zero); + + var buffer = StringBuffer(); + buffer.write("Process `dart_sass_embedded` "); + if (exitCodeOrNull == null) { + buffer.write("was killed with SIGKILL in a tear-down."); + } else { + buffer.write("exited with exitCode $exitCodeOrNull."); + } + buffer.writeln(" Output:"); + buffer.writeln(_log.join("\n")); + + printOnFailure(buffer.toString()); + } + + /// Kills the process (with SIGKILL on POSIX operating systems), and returns a + /// future that completes once it's dead. + /// + /// If this is called after the process is already dead, it does nothing. + Future kill() async { + _process.kill(ProcessSignal.sigkill); + await exitCode; + } + + /// Waits for the process to exit, and verifies that the exit code matches + /// [expectedExitCode] (if given). + /// + /// If this is called after the process is already dead, it verifies its + /// existing exit code. + Future shouldExit([expectedExitCode]) async { + var exitCode = await this.exitCode; + if (expectedExitCode == null) return; + expect(exitCode, expectedExitCode, + reason: "Process `dart_sass_embedded` had an unexpected exit code."); + } +} diff --git a/test/protocol_test.dart b/test/protocol_test.dart new file mode 100644 index 000000000..6daab4665 --- /dev/null +++ b/test/protocol_test.dart @@ -0,0 +1,47 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:test/test.dart'; + +import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +import 'embedded_process.dart'; +import 'utils.dart'; + +void main() { + EmbeddedProcess process; + setUp(() async { + process = await EmbeddedProcess.start(); + }); + + group("gracefully handles a protocol error", () { + test("caused by an empty message", () async { + process.inbound.add(InboundMessage()); + await expectParseError(process, "InboundMessage.message is not set."); + await process.kill(); + }); + + test("caused by an invalid message", () async { + process.stdin.add([1, 0, 0, 0, 0]); + await expectParseError( + process, "Protocol message contained an invalid tag (zero)."); + await process.kill(); + }); + + test("without shutting down the compiler", () async { + process.inbound.add(InboundMessage()); + await expectParseError(process, "InboundMessage.message is not set."); + + process.inbound.add(compileString("a {b: c}")); + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + }); + + test("compiles a CSS from a string", () async { + process.inbound.add(compileString("a {b: c}")); + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); +} diff --git a/test/utils.dart b/test/utils.dart new file mode 100644 index 000000000..cfe3ff96d --- /dev/null +++ b/test/utils.dart @@ -0,0 +1,61 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:test/test.dart'; + +import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +import 'embedded_process.dart'; + +/// Returns a [InboundMessage] that compiles the given plain CSS +/// string. +InboundMessage compileString(String css) => InboundMessage() + ..compileRequest = (InboundMessage_CompileRequest() + ..string = (InboundMessage_CompileRequest_StringInput()..source = css)); + +/// Asserts that [process] emits a [ProtocolError] parse error with the given +/// [message] on its protobuf stream and prints a notice on stderr. +Future expectParseError(EmbeddedProcess process, message) async { + await expectLater(process.outbound, + emits(isProtocolError(-1, ProtocolError_ErrorType.PARSE, message))); + await expectLater(process.stderr, emits("Host caused parse error: $message")); +} + +/// Asserts that an [OutboundMessage] is a [ProtocolError] with the given [id], +/// [type], and optionally [message]. +Matcher isProtocolError(int id, ProtocolError_ErrorType type, [message]) => + predicate((value) { + expect(value, isA()); + var outboundMessage = value as OutboundMessage; + expect(outboundMessage.hasError(), isTrue, + reason: "Expected $message to be a ProtocolError"); + expect(outboundMessage.error.id, equals(id)); + expect(outboundMessage.error.type, equals(type)); + if (message != null) expect(outboundMessage.error.message, message); + return true; + }); + +/// Asserts that [message] is an [OutboundMessage] with a [CompileResponse] and +/// returns it. +OutboundMessage_CompileResponse getCompileResponse(value) { + expect(value, isA()); + var message = value as OutboundMessage; + expect(message.hasCompileResponse(), isTrue, + reason: "Expected $message to have a CompileResponse"); + return message.compileResponse; +} + +/// Asserts that an [OutboundMessage] is a [CompileResponse] with CSS that +/// matches [css]. +/// +/// If [css] is a [String], this automatically wraps it in +/// [equalsIgnoringWhitespace]. +Matcher isSuccess(css) => predicate((value) { + var response = getCompileResponse(value); + expect(response.hasSuccess(), isTrue, + reason: "Expected $response to be successful"); + expect(response.success.css, + css is String ? equalsIgnoringWhitespace(css) : css); + return true; + }); From 2b11aa1c218641135c2b747d22ad22bdcdec8cfd Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 29 Oct 2019 17:21:52 -0700 Subject: [PATCH 008/162] Use cli_pkg to deploy to GitHub --- pubspec.yaml | 4 ++++ tool/grind.dart | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e46f0ceec..f2c887020 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,11 @@ dependencies: stream_channel: ">=1.6.0 <3.0.0" dev_dependencies: + cli_pkg: ^1.0.0 grinder: ^0.8.0 protoc_plugin: ^19.0.0 path: ^1.6.0 test: ^1.0.0 + +dependency_overrides: + cli_pkg: {git: git://github.com/google/dart_cli_pkg} diff --git a/tool/grind.dart b/tool/grind.dart index 27795f057..6b15916da 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -4,11 +4,15 @@ import 'dart:io'; +import 'package:cli_pkg/cli_pkg.dart' as pkg; import 'package:grinder/grinder.dart'; import 'utils.dart'; -main(List args) => grind(args); +main(List args) { + pkg.addGithubTasks(); + grind(args); +} @Task('Compile the protocol buffer definition to a Dart library.') protobuf() async { From ebdcb23d79f1f1bfc3e0dd4ca6d76ded1c8da70e Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 29 Oct 2019 17:22:06 -0700 Subject: [PATCH 009/162] Run from script or native snapshots in tests if available --- test/embedded_process.dart | 11 +++++- test/protocol_test.dart | 2 + test/utils.dart | 79 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/test/embedded_process.dart b/test/embedded_process.dart index 167c69d59..bb3a8d294 100644 --- a/test/embedded_process.dart +++ b/test/embedded_process.dart @@ -7,11 +7,15 @@ import 'dart:convert'; import 'dart:io'; import 'package:async/async.dart'; +import 'package:grinder/grinder.dart'; +import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; +import 'utils.dart'; + /// A wrapper for [Process] that provides a convenient API for testing the /// embedded Sass process. /// @@ -77,9 +81,12 @@ class EmbeddedProcess { bool includeParentEnvironment = true, bool runInShell = false, bool forwardOutput = false}) async { - // TODO(nweiz): Support running from a native executable. + var scriptOrSnapshot = executablePath; var process = await Process.start( - Platform.executable, ["bin/dart_sass_embedded.dart"], + executablePath.endsWith(".native") + ? p.join(sdkDir.path, "bin", "dartaotruntime") + : Platform.executable, + [scriptOrSnapshot], workingDirectory: workingDirectory, environment: environment, includeParentEnvironment: includeParentEnvironment, diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 6daab4665..920dd8a72 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -10,6 +10,8 @@ import 'embedded_process.dart'; import 'utils.dart'; void main() { + ensureExecutableUpToDate(); + EmbeddedProcess process; setUp(() async { process = await EmbeddedProcess.start(); diff --git a/test/utils.dart b/test/utils.dart index cfe3ff96d..f0c2e2565 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -2,12 +2,91 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'dart:io'; + +import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; import 'embedded_process.dart'; +/// Whether [ensureExecutableUpToDate] has been called. +var _ensuredExecutableUpToDate = false; + +/// Returns the path to the executable to execute. +/// +/// This may be a raw Dart executable, a script snapshot that ends in +/// `.snapshot`, or a native-code snapshot that ends in `.native`. +final String executablePath = () { + expect(_ensuredExecutableUpToDate, isTrue, + reason: + "ensureExecutableUpToDate() must be called at top of the test file."); + + var nativeSnapshot = "build/dart_sass_embedded.dart.native"; + if (File(nativeSnapshot).existsSync()) return nativeSnapshot; + + var bytecodeSnapshot = "build/dart_sass_embedded.dart.snapshot"; + if (File(bytecodeSnapshot).existsSync()) return bytecodeSnapshot; + + return "bin/dart_sass_embedded.dart"; +}(); + +/// Creates a [setUpAll] that verifies that the compiled form of the migrator +/// executable is up-to-date, if necessary. +/// +/// This should always be called before [runMigrator]. +void ensureExecutableUpToDate() { + setUpAll(() { + _ensuredExecutableUpToDate = true; + + if (!executablePath.endsWith(".dart")) { + _ensureUpToDate( + executablePath, + "pub run grinder protobuf " + "pkg-compile-${Platform.isWindows ? 'snapshot' : 'native'}"); + } + }); +} + +/// Ensures that [path] (usually a compilation artifact) has been modified more +/// recently than all this package's source files. +/// +/// If [path] isn't up-to-date, this throws an error encouraging the user to run +/// [commandToRun]. +void _ensureUpToDate(String path, String commandToRun) { + // Ensure path is relative so the error messages are more readable. + path = p.relative(path); + if (!File(path).existsSync()) { + throw "$path does not exist. Run $commandToRun."; + } + + var lastModified = File(path).lastModifiedSync(); + var entriesToCheck = Directory("lib").listSync(recursive: true).toList(); + + // If we have a dependency override, "pub run" will touch the lockfile to mark + // it as newer than the pubspec, which makes it unsuitable to use for + // freshness checking. + if (File("pubspec.yaml") + .readAsStringSync() + .contains("dependency_overrides")) { + entriesToCheck.add(File("pubspec.yaml")); + } else { + entriesToCheck.add(File("pubspec.lock")); + } + + for (var entry in entriesToCheck) { + if (entry is File) { + var entryLastModified = entry.lastModifiedSync(); + if (lastModified.isBefore(entryLastModified)) { + throw "${entry.path} was modified after ${p.prettyUri(p.toUri(path))} " + "was generated.\n" + "Run $commandToRun."; + } + } + } +} + /// Returns a [InboundMessage] that compiles the given plain CSS /// string. InboundMessage compileString(String css) => InboundMessage() From 3de78be2f08ab15ed2654730c2b4c1cf04c28a5a Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 4 Nov 2019 19:50:50 -0800 Subject: [PATCH 010/162] Plug in the actual Sass compiler (#5) This now supports real CompileRequest and CompileResponses, although it's missing features like importers, custom functions, and source maps. --- bin/dart_sass_embedded.dart | 92 +++++++++++++- lib/src/dispatcher.dart | 7 +- lib/src/utils.dart | 11 ++ pubspec.yaml | 4 + test/protocol_test.dart | 236 +++++++++++++++++++++++++++++++++++- test/utils.dart | 49 ++++++-- tool/grind.dart | 2 +- 7 files changed, 383 insertions(+), 18 deletions(-) create mode 100644 lib/src/utils.dart diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 236951dfa..4b0e1eaac 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -3,12 +3,18 @@ // https://opensource.org/licenses/MIT. import 'dart:io'; +import 'dart:convert'; +import 'package:sass/sass.dart' as sass; +import 'package:source_maps/source_maps.dart' as source_maps; +import 'package:source_span/source_span.dart'; import 'package:stream_channel/stream_channel.dart'; import 'package:sass_embedded/src/dispatcher.dart'; -import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/embedded_sass.pb.dart' as proto; +import 'package:sass_embedded/src/embedded_sass.pb.dart' hide SourceSpan; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; +import 'package:sass_embedded/src/utils.dart'; void main(List args) { if (args.isNotEmpty) { @@ -23,9 +29,87 @@ void main(List args) { var dispatcher = Dispatcher( StreamChannel.withGuarantees(stdin, stdout, allowSinkErrors: false) .transform(lengthDelimited)); + dispatcher.listen((request) { - return OutboundMessage_CompileResponse() - ..success = (OutboundMessage_CompileResponse_CompileSuccess() - ..css = "a {\n b: c;\n}\n"); + var style = + request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED + ? sass.OutputStyle.compressed + : sass.OutputStyle.expanded; + + try { + String result; + source_maps.SingleMapping sourceMap; + var sourceMapCallback = request.sourceMap + ? (source_maps.SingleMapping map) => sourceMap = map + : null; + switch (request.whichInput()) { + case InboundMessage_CompileRequest_Input.string: + var input = request.string; + result = sass.compileString(input.source, + syntax: _syntaxToSyntax(input.syntax), + style: style, + url: input.url.isEmpty ? null : input.url, + sourceMap: sourceMapCallback); + break; + + case InboundMessage_CompileRequest_Input.path: + try { + result = sass.compile(request.path, + style: style, sourceMap: sourceMapCallback); + } on FileSystemException catch (error) { + return OutboundMessage_CompileResponse() + ..failure = (OutboundMessage_CompileResponse_CompileFailure() + ..message = error.path == null + ? error.message + : "${error.message}: ${error.path}"); + } + break; + + case InboundMessage_CompileRequest_Input.notSet: + throw mandatoryError("CompileRequest.input"); + } + + var success = OutboundMessage_CompileResponse_CompileSuccess() + ..css = result; + if (sourceMap != null) { + success.sourceMap = json.encode(sourceMap.toJson()); + } + return OutboundMessage_CompileResponse()..success = success; + } on sass.SassException catch (error) { + return OutboundMessage_CompileResponse() + ..failure = (OutboundMessage_CompileResponse_CompileFailure() + ..message = error.message + ..span = _protofySpan(error.span) + ..stackTrace = error.trace.toString()); + } }); } + +/// Converts a protocol buffer syntax enum into a Sass API syntax enum. +sass.Syntax _syntaxToSyntax(InboundMessage_Syntax syntax) { + switch (syntax) { + case InboundMessage_Syntax.SCSS: + return sass.Syntax.scss; + case InboundMessage_Syntax.INDENTED: + return sass.Syntax.sass; + case InboundMessage_Syntax.CSS: + return sass.Syntax.css; + default: + throw "Unknown syntax $syntax."; + } +} + +/// Converts a Dart source span to a protocol buffer source span. +proto.SourceSpan _protofySpan(SourceSpanWithContext span) => proto.SourceSpan() + ..text = span.text + ..start = _protofyLocation(span.start) + ..end = _protofyLocation(span.end) + ..url = span.sourceUrl?.toString() ?? "" + ..context = span.context; + +/// Converts a Dart source location to a protocol buffer source location. +SourceSpan_SourceLocation _protofyLocation(SourceLocation location) => + SourceSpan_SourceLocation() + ..offset = location.offset + ..line = location.line + ..column = location.column; diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 8d9e021e1..dc56b69e5 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -23,9 +23,10 @@ class Dispatcher { /// Listens for incoming `CompileRequests` and passes them to [callback]. /// - /// The callback must return a `CompileResponse` which is sent to the host. It - /// doesn't need to set [OutboundMessage_CompileResponse.id]; the [Dispatcher] - /// will take care of that. + /// The callback must return a `CompileResponse` which is sent to the host. + /// The callback may throw [ProtocolError]s, which will be sent back to the + /// host. Neither `CompileResponse`s nor [ProtocolError]s need to set their + /// `id` fields; the [Dispatcher] will take care of that. /// /// This may only be called once. void listen( diff --git a/lib/src/utils.dart b/lib/src/utils.dart new file mode 100644 index 000000000..a6171290d --- /dev/null +++ b/lib/src/utils.dart @@ -0,0 +1,11 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'embedded_sass.pb.dart'; + +/// Returns a [ProtocolError] indicating that a mandatory field with the givne +/// [fieldName] was missing. +ProtocolError mandatoryError(String fieldName) => ProtocolError() + ..type = ProtocolError_ErrorType.PARAMS + ..message = "Missing mandatory field $fieldName"; diff --git a/pubspec.yaml b/pubspec.yaml index f2c887020..a167ef48f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,6 +13,9 @@ executables: dependencies: async: ">=1.13.0 <3.0.0" protobuf: ^1.0.0 + sass: ^1.21.0 + source_maps: ^0.10.5 + source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" @@ -22,6 +25,7 @@ dev_dependencies: protoc_plugin: ^19.0.0 path: ^1.6.0 test: ^1.0.0 + test_descriptor: ^1.0.0 dependency_overrides: cli_pkg: {git: git://github.com/google/dart_cli_pkg} diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 920dd8a72..dc1a412eb 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -2,7 +2,10 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:path/path.dart' as p; +import 'package:source_maps/source_maps.dart' as source_maps; import 'package:test/test.dart'; +import 'package:test_descriptor/test_descriptor.dart' as d; import 'package:sass_embedded/src/embedded_sass.pb.dart'; @@ -41,9 +44,236 @@ void main() { }); }); - test("compiles a CSS from a string", () async { - process.inbound.add(compileString("a {b: c}")); - await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + group("compiles CSS from", () { + test("an SCSS string by default", () async { + process.inbound.add(compileString("a {b: 1px + 2px}")); + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + + test("an SCSS string explicitly", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + syntax: InboundMessage_Syntax.SCSS)); + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + + test("an indented syntax string", () async { + process.inbound.add(compileString("a\n b: 1px + 2px", + syntax: InboundMessage_Syntax.INDENTED)); + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + + test("a plain CSS string", () async { + process.inbound + .add(compileString("a {b: c}", syntax: InboundMessage_Syntax.CSS)); + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + + test("an absolute path", () async { + await d.file("test.scss", "a {b: 1px + 2px}").create(); + + process.inbound.add(InboundMessage() + ..compileRequest = (InboundMessage_CompileRequest() + ..path = p.absolute(d.path("test.scss")))); + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + + test("a relative path", () async { + await d.file("test.scss", "a {b: 1px + 2px}").create(); + + process.inbound.add(InboundMessage() + ..compileRequest = (InboundMessage_CompileRequest() + ..path = p.relative(d.path("test.scss")))); + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + }); + + group("compiles CSS in", () { + test("expanded mode", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + style: InboundMessage_CompileRequest_OutputStyle.EXPANDED)); + await expectLater( + process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); + await process.kill(); + }); + + test("compressed mode", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + style: InboundMessage_CompileRequest_OutputStyle.COMPRESSED)); + await expectLater(process.outbound, emits(isSuccess(equals("a{b:3px}")))); + await process.kill(); + }); + + test("expanded mode when nested mode is passed", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + style: InboundMessage_CompileRequest_OutputStyle.NESTED)); + await expectLater( + process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); + await process.kill(); + }); + + test("expanded mode when compact mode is passed", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + style: InboundMessage_CompileRequest_OutputStyle.COMPACT)); + await expectLater( + process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); + await process.kill(); + }); + }); + + test("doesn't include a source map by default", () async { + process.inbound.add(compileString("a {b: 1px + 2px}")); + await expectLater(process.outbound, + emits(isSuccess("a { b: 3px; }", sourceMap: isEmpty))); + await process.kill(); + }); + + test("doesn't include a source map with source_map: false", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", sourceMap: false)); + await expectLater(process.outbound, + emits(isSuccess("a { b: 3px; }", sourceMap: isEmpty))); await process.kill(); }); + + test("includes a source map if source_map is true", () async { + process.inbound.add(compileString("a {b: 1px + 2px}", sourceMap: true)); + await expectLater( + process.outbound, + emits(isSuccess("a { b: 3px; }", sourceMap: predicate((map) { + var mapping = source_maps.parse(map); + var span = mapping.spanFor(2, 5); + expect(span.start.line, equals(0)); + expect(span.start.column, equals(3)); + expect(span.end, equals(span.start)); + return true; + })))); + await process.kill(); + }); + + group("gracefully handles an error", () { + test("from invalid syntax", () async { + process.inbound.add(compileString("a {b: }")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals("Expected expression.")); + expect(failure.span.text, isEmpty); + expect(failure.span.start, equals(location(6, 0, 6))); + expect(failure.span.end, equals(location(6, 0, 6))); + expect(failure.span.url, isEmpty); + expect(failure.span.context, equals("a {b: }")); + expect(failure.stackTrace, equals("- 1:7 root stylesheet\n")); + await process.kill(); + }); + + test("from the runtime", () async { + process.inbound.add(compileString("a {b: 1px + 1em}")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals("Incompatible units em and px.")); + expect(failure.span.text, "1px + 1em"); + expect(failure.span.start, equals(location(6, 0, 6))); + expect(failure.span.end, equals(location(15, 0, 15))); + expect(failure.span.url, isEmpty); + expect(failure.span.context, equals("a {b: 1px + 1em}")); + expect(failure.stackTrace, equals("- 1:7 root stylesheet\n")); + await process.kill(); + }); + + test("from a missing file", () async { + process.inbound.add(InboundMessage() + ..compileRequest = + (InboundMessage_CompileRequest()..path = d.path("test.scss"))); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, startsWith("Cannot open file: ")); + expect(failure.message.split(":").last.trim(), + equalsPath(d.path('test.scss'))); + expect(failure.span, equals(SourceSpan())); + expect(failure.stackTrace, isEmpty); + await process.kill(); + }); + + test("with a multi-line source span", () async { + process.inbound.add(compileString(""" +a { + b: 1px + + 1em; +} +""")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.span.text, "1px +\n 1em"); + expect(failure.span.start, equals(location(9, 1, 5))); + expect(failure.span.end, equals(location(23, 2, 8))); + expect(failure.span.url, isEmpty); + expect(failure.span.context, equals(" b: 1px +\n 1em;\n")); + expect(failure.stackTrace, equals("- 2:6 root stylesheet\n")); + await process.kill(); + }); + + test("with multiple stack trace entries", () async { + process.inbound.add(compileString(""" +@function fail() { + @return 1px + 1em; +} + +a { + b: fail(); +} +""")); + + var failure = getCompileFailure(await process.outbound.next); + expect( + failure.stackTrace, + equals("- 2:11 fail()\n" + "- 6:6 root stylesheet\n")); + await process.kill(); + }); + + group("and includes the URL from", () { + test("a string input", () async { + process.inbound + .add(compileString("a {b: 1px + 1em}", url: "foo://bar/baz")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.span.url, equals("foo://bar/baz")); + expect( + failure.stackTrace, equals("foo://bar/baz 1:7 root stylesheet\n")); + await process.kill(); + }); + + test("a path input", () async { + await d.file("test.scss", "a {b: 1px + 1em}").create(); + var path = d.path("test.scss"); + process.inbound.add(InboundMessage() + ..compileRequest = (InboundMessage_CompileRequest()..path = path)); + + var failure = getCompileFailure(await process.outbound.next); + expect(p.fromUri(failure.span.url), equalsPath(path)); + expect(failure.stackTrace, endsWith(" 1:7 root stylesheet\n")); + expect(failure.stackTrace.split(" ").first, equalsPath(path)); + await process.kill(); + }); + }); + + test("caused by using Sass features in CSS", () async { + process.inbound.add( + compileString("a {b: 1px + 2px}", syntax: InboundMessage_Syntax.CSS)); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals("Operators aren't allowed in plain CSS.")); + expect(failure.span.text, "+"); + expect(failure.span.start, equals(location(10, 0, 10))); + expect(failure.span.end, equals(location(11, 0, 11))); + expect(failure.span.url, isEmpty); + expect(failure.span.context, equals("a {b: 1px + 2px}")); + expect(failure.stackTrace, equals("- 1:11 root stylesheet\n")); + await process.kill(); + }); + }); } diff --git a/test/utils.dart b/test/utils.dart index f0c2e2565..f4e2af5db 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -89,9 +89,21 @@ void _ensureUpToDate(String path, String commandToRun) { /// Returns a [InboundMessage] that compiles the given plain CSS /// string. -InboundMessage compileString(String css) => InboundMessage() - ..compileRequest = (InboundMessage_CompileRequest() - ..string = (InboundMessage_CompileRequest_StringInput()..source = css)); +InboundMessage compileString(String css, + {InboundMessage_Syntax syntax, + InboundMessage_CompileRequest_OutputStyle style, + String url, + bool sourceMap}) { + var input = InboundMessage_CompileRequest_StringInput()..source = css; + if (syntax != null) input.syntax = syntax; + if (url != null) input.url = url; + + var request = InboundMessage_CompileRequest()..string = input; + if (style != null) request.style = style; + if (sourceMap != null) request.sourceMap = sourceMap; + + return InboundMessage()..compileRequest = request; +} /// Asserts that [process] emits a [ProtocolError] parse error with the given /// [message] on its protobuf stream and prints a notice on stderr. @@ -115,7 +127,16 @@ Matcher isProtocolError(int id, ProtocolError_ErrorType type, [message]) => return true; }); -/// Asserts that [message] is an [OutboundMessage] with a [CompileResponse] and +/// Asserts that [message] is an [OutboundMessage] with a +/// `CompileResponse.Failure` and returns it. +OutboundMessage_CompileResponse_CompileFailure getCompileFailure(value) { + var response = getCompileResponse(value); + expect(response.hasFailure(), isTrue, + reason: "Expected $response to be a failure"); + return response.failure; +} + +/// Asserts that [message] is an [OutboundMessage] with a `CompileResponse` and /// returns it. OutboundMessage_CompileResponse getCompileResponse(value) { expect(value, isA()); @@ -125,16 +146,30 @@ OutboundMessage_CompileResponse getCompileResponse(value) { return message.compileResponse; } -/// Asserts that an [OutboundMessage] is a [CompileResponse] with CSS that -/// matches [css]. +/// Asserts that an [OutboundMessage] is a `CompileResponse` with CSS that +/// matches [css], with a source map that matches [sourceMap] (if passed). /// /// If [css] is a [String], this automatically wraps it in /// [equalsIgnoringWhitespace]. -Matcher isSuccess(css) => predicate((value) { +Matcher isSuccess(css, {sourceMap}) => predicate((value) { var response = getCompileResponse(value); expect(response.hasSuccess(), isTrue, reason: "Expected $response to be successful"); expect(response.success.css, css is String ? equalsIgnoringWhitespace(css) : css); + if (sourceMap != null) expect(response.success.sourceMap, sourceMap); return true; }); + +/// Returns a [SourceSpan_SourceLocation] with the given [offset], [line], and +/// [column]. +SourceSpan_SourceLocation location(int offset, int line, int column) => + SourceSpan_SourceLocation() + ..offset = offset + ..line = line + ..column = column; + +/// Returns a matcher that verifies whether the given value refers to the same +/// path as [expected]. +Matcher equalsPath(String expected) => predicate( + (actual) => p.equals(actual, expected), "equals $expected"); diff --git a/tool/grind.dart b/tool/grind.dart index 6b15916da..8da27d842 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -29,7 +29,7 @@ pub run protoc_plugin %* } else { File('build/protoc-gen-dart') .writeAsStringSync('pub run protoc_plugin "\$@"'); - runProcess('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); + run('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); } await cloneOrPull("git://github.com/sass/embedded-protocol"); From ec05600af2090055dab3e40d7c85abe3f85f1719 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 5 Nov 2019 13:51:08 -0800 Subject: [PATCH 011/162] Emit LogEvents (#6) --- bin/dart_sass_embedded.dart | 26 +++--------- lib/src/dispatcher.dart | 4 ++ lib/src/logger.dart | 43 ++++++++++++++++++++ lib/src/utils.dart | 23 ++++++++++- test/protocol_test.dart | 79 +++++++++++++++++++++++++++++++++++++ test/utils.dart | 14 ++++++- 6 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 lib/src/logger.dart diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 4b0e1eaac..d7d0d5e61 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -7,12 +7,11 @@ import 'dart:convert'; import 'package:sass/sass.dart' as sass; import 'package:source_maps/source_maps.dart' as source_maps; -import 'package:source_span/source_span.dart'; import 'package:stream_channel/stream_channel.dart'; import 'package:sass_embedded/src/dispatcher.dart'; -import 'package:sass_embedded/src/embedded_sass.pb.dart' as proto; -import 'package:sass_embedded/src/embedded_sass.pb.dart' hide SourceSpan; +import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/logger.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; import 'package:sass_embedded/src/utils.dart'; @@ -35,6 +34,7 @@ void main(List args) { request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED ? sass.OutputStyle.compressed : sass.OutputStyle.expanded; + var logger = Logger(dispatcher, request.id); try { String result; @@ -46,6 +46,7 @@ void main(List args) { case InboundMessage_CompileRequest_Input.string: var input = request.string; result = sass.compileString(input.source, + logger: logger, syntax: _syntaxToSyntax(input.syntax), style: style, url: input.url.isEmpty ? null : input.url, @@ -55,7 +56,7 @@ void main(List args) { case InboundMessage_CompileRequest_Input.path: try { result = sass.compile(request.path, - style: style, sourceMap: sourceMapCallback); + logger: logger, style: style, sourceMap: sourceMapCallback); } on FileSystemException catch (error) { return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() @@ -79,7 +80,7 @@ void main(List args) { return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() ..message = error.message - ..span = _protofySpan(error.span) + ..span = protofySpan(error.span) ..stackTrace = error.trace.toString()); } }); @@ -98,18 +99,3 @@ sass.Syntax _syntaxToSyntax(InboundMessage_Syntax syntax) { throw "Unknown syntax $syntax."; } } - -/// Converts a Dart source span to a protocol buffer source span. -proto.SourceSpan _protofySpan(SourceSpanWithContext span) => proto.SourceSpan() - ..text = span.text - ..start = _protofyLocation(span.start) - ..end = _protofyLocation(span.end) - ..url = span.sourceUrl?.toString() ?? "" - ..context = span.context; - -/// Converts a Dart source location to a protocol buffer source location. -SourceSpan_SourceLocation _protofyLocation(SourceLocation location) => - SourceSpan_SourceLocation() - ..offset = location.offset - ..line = location.line - ..column = location.column; diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index dc56b69e5..c8c4b212a 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -90,6 +90,10 @@ class Dispatcher { }); } + /// Sends [event] to the host. + void sendLog(OutboundMessage_LogEvent event) => + _send(OutboundMessage()..logEvent = event); + /// Sends [message] to the host. void _send(OutboundMessage message) => _channel.sink.add(message.writeToBuffer()); diff --git a/lib/src/logger.dart b/lib/src/logger.dart new file mode 100644 index 000000000..09bea878f --- /dev/null +++ b/lib/src/logger.dart @@ -0,0 +1,43 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:sass/sass.dart' as sass; +import 'package:source_span/source_span.dart'; +import 'package:stack_trace/stack_trace.dart'; + +import 'dispatcher.dart'; +import 'embedded_sass.pb.dart' hide SourceSpan; +import 'utils.dart'; + +/// A Sass logger that sends log messages as `LogEvent`s. +class Logger implements sass.Logger { + /// The [Dispatcher] to which to send events. + final Dispatcher _dispatcher; + + /// The ID of the compilation to which this logger is passed. + final int _compilationId; + + Logger(this._dispatcher, this._compilationId); + + void debug(String message, SourceSpan span) { + _dispatcher.sendLog(OutboundMessage_LogEvent() + ..compilationId = _compilationId + ..type = OutboundMessage_LogEvent_Type.DEBUG + ..message = message + ..span = protofySpan(span)); + } + + void warn(String message, + {FileSpan span, Trace trace, bool deprecation = false}) { + var event = OutboundMessage_LogEvent() + ..compilationId = _compilationId + ..type = deprecation + ? OutboundMessage_LogEvent_Type.DEPRECATION_WARNING + : OutboundMessage_LogEvent_Type.WARNING + ..message = message; + if (span != null) event.span = protofySpan(span); + if (trace != null) event.stackTrace = trace.toString(); + _dispatcher.sendLog(event); + } +} diff --git a/lib/src/utils.dart b/lib/src/utils.dart index a6171290d..073fa8ffa 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,10 +2,31 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'embedded_sass.pb.dart'; +import 'package:source_span/source_span.dart'; + +import 'embedded_sass.pb.dart' as proto; +import 'embedded_sass.pb.dart' hide SourceSpan; /// Returns a [ProtocolError] indicating that a mandatory field with the givne /// [fieldName] was missing. ProtocolError mandatoryError(String fieldName) => ProtocolError() ..type = ProtocolError_ErrorType.PARAMS ..message = "Missing mandatory field $fieldName"; + +/// Converts a Dart source span to a protocol buffer source span. +proto.SourceSpan protofySpan(SourceSpan span) { + var protoSpan = proto.SourceSpan() + ..text = span.text + ..start = _protofyLocation(span.start) + ..end = _protofyLocation(span.end) + ..url = span.sourceUrl?.toString() ?? ""; + if (span is SourceSpanWithContext) protoSpan.context = span.context; + return protoSpan; +} + +/// Converts a Dart source location to a protocol buffer source location. +SourceSpan_SourceLocation _protofyLocation(SourceLocation location) => + SourceSpan_SourceLocation() + ..offset = location.offset + ..line = location.line + ..column = location.column; diff --git a/test/protocol_test.dart b/test/protocol_test.dart index dc1a412eb..ab72aef6b 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -155,6 +155,85 @@ void main() { await process.kill(); }); + group("emits a log event", () { + test("for a @debug rule", () async { + process.inbound.add(compileString("a {@debug hello}")); + + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(0)); + expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.DEBUG)); + expect(logEvent.message, equals("hello")); + expect(logEvent.span.text, equals("@debug hello")); + expect(logEvent.span.start, equals(location(3, 0, 3))); + expect(logEvent.span.end, equals(location(15, 0, 15))); + expect(logEvent.span.context, equals("a {@debug hello}")); + expect(logEvent.stackTrace, isEmpty); + await process.kill(); + }); + + test("for a @warn rule", () async { + process.inbound.add(compileString("a {@warn hello}")); + + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(0)); + expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.WARNING)); + expect(logEvent.message, equals("hello")); + expect(logEvent.span, equals(SourceSpan())); + expect(logEvent.stackTrace, equals("- 1:4 root stylesheet\n")); + await process.kill(); + }); + + test("for a parse-time deprecation warning", () async { + process.inbound.add(compileString("@if true {} @elseif true {}")); + + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(0)); + expect(logEvent.type, + equals(OutboundMessage_LogEvent_Type.DEPRECATION_WARNING)); + expect( + logEvent.message, + equals( + '@elseif is deprecated and will not be supported in future Sass ' + 'versions.\n' + 'Use "@else if" instead.')); + expect(logEvent.span.text, equals("@elseif")); + expect(logEvent.span.start, equals(location(12, 0, 12))); + expect(logEvent.span.end, equals(location(19, 0, 19))); + expect(logEvent.span.context, equals("@if true {} @elseif true {}")); + expect(logEvent.stackTrace, isEmpty); + await process.kill(); + }); + + test("for a runtime deprecation warning", () async { + process.inbound.add(compileString("a {\$var: value !global}")); + + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(0)); + expect(logEvent.type, + equals(OutboundMessage_LogEvent_Type.DEPRECATION_WARNING)); + expect( + logEvent.message, + equals("As of Dart Sass 2.0.0, !global assignments won't be able to\n" + "declare new variables. Consider adding `\$var: null` at the " + "root of the\n" + "stylesheet.")); + expect(logEvent.span.text, equals("\$var: value !global")); + expect(logEvent.span.start, equals(location(3, 0, 3))); + expect(logEvent.span.end, equals(location(22, 0, 22))); + expect(logEvent.span.context, equals("a {\$var: value !global}")); + expect(logEvent.stackTrace, "- 1:4 root stylesheet\n"); + await process.kill(); + }); + + test("with the same ID as the CompileRequest", () async { + process.inbound.add(compileString("@debug hello", id: 12345)); + + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(12345)); + await process.kill(); + }); + }); + group("gracefully handles an error", () { test("from invalid syntax", () async { process.inbound.add(compileString("a {b: }")); diff --git a/test/utils.dart b/test/utils.dart index f4e2af5db..6b7aaa6fa 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -90,7 +90,8 @@ void _ensureUpToDate(String path, String commandToRun) { /// Returns a [InboundMessage] that compiles the given plain CSS /// string. InboundMessage compileString(String css, - {InboundMessage_Syntax syntax, + {int id, + InboundMessage_Syntax syntax, InboundMessage_CompileRequest_OutputStyle style, String url, bool sourceMap}) { @@ -99,6 +100,7 @@ InboundMessage compileString(String css, if (url != null) input.url = url; var request = InboundMessage_CompileRequest()..string = input; + if (id != null) request.id = id; if (style != null) request.style = style; if (sourceMap != null) request.sourceMap = sourceMap; @@ -146,6 +148,16 @@ OutboundMessage_CompileResponse getCompileResponse(value) { return message.compileResponse; } +/// Asserts that [message] is an [OutboundMessage] with a `LogEvent` and +/// returns it. +OutboundMessage_LogEvent getLogEvent(value) { + expect(value, isA()); + var message = value as OutboundMessage; + expect(message.hasLogEvent(), isTrue, + reason: "Expected $message to have a LogEvent"); + return message.logEvent; +} + /// Asserts that an [OutboundMessage] is a `CompileResponse` with CSS that /// matches [css], with a source map that matches [sourceMap] (if passed). /// From 053e3eacd3026887cd317dc04f085d71685abf8d Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 5 Nov 2019 13:51:14 -0800 Subject: [PATCH 012/162] Compile a snapshot before testing on Travis (#7) --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9c6f8c345..62fa423b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,13 @@ before_script: # Format the generated code or else the formatter task will get upset. - dartfmt -w --fix lib/src/embedded_sass.pb* +# TODO(nweiz): always compile native when we're running on Dart 2.7. +- if [[ "$TRAVIS_OS_NAME" = windows ]]; then + pub run grinder pkg-compile-snapshot; + else + pub run grinder pkg-compile-native; + fi + jobs: include: From 95bb3aceb653e052e2735690b91f9183457872fe Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 7 Nov 2019 16:03:47 -0800 Subject: [PATCH 013/162] Add support for importers (#8) --- bin/dart_sass_embedded.dart | 48 ++-- lib/src/dispatcher.dart | 130 ++++++++-- lib/src/importer.dart | 109 ++++++++ lib/src/utils.dart | 30 ++- pubspec.yaml | 1 + test/importer_test.dart | 499 ++++++++++++++++++++++++++++++++++++ test/protocol_test.dart | 4 +- test/utils.dart | 46 +++- 8 files changed, 823 insertions(+), 44 deletions(-) create mode 100644 lib/src/importer.dart create mode 100644 test/importer_test.dart diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index d7d0d5e61..66cbeff6e 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -11,6 +11,7 @@ import 'package:stream_channel/stream_channel.dart'; import 'package:sass_embedded/src/dispatcher.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/importer.dart'; import 'package:sass_embedded/src/logger.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; import 'package:sass_embedded/src/utils.dart'; @@ -29,7 +30,13 @@ void main(List args) { StreamChannel.withGuarantees(stdin, stdout, allowSinkErrors: false) .transform(lengthDelimited)); - dispatcher.listen((request) { + dispatcher.listen((request) async { + // Wait a single microtask tick so that we're running in a separate + // microtask from the initial request dispatch. Otherwise, [waitFor] will + // deadlock the event loop fiber that would otherwise be checking stdin for + // new input. + await Future.value(); + var style = request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED ? sass.OutputStyle.compressed @@ -42,12 +49,30 @@ void main(List args) { var sourceMapCallback = request.sourceMap ? (source_maps.SingleMapping map) => sourceMap = map : null; + + var importers = request.importers.map((importer) { + switch (importer.whichImporter()) { + case InboundMessage_CompileRequest_Importer_Importer.path: + return sass.FilesystemImporter(importer.path); + + case InboundMessage_CompileRequest_Importer_Importer.importerId: + return Importer(dispatcher, request.id, importer.importerId); + + case InboundMessage_CompileRequest_Importer_Importer.notSet: + throw mandatoryError("Importer.importer"); + + default: + throw "Unknown Importer.importer $importer."; + } + }); + switch (request.whichInput()) { case InboundMessage_CompileRequest_Input.string: var input = request.string; result = sass.compileString(input.source, logger: logger, - syntax: _syntaxToSyntax(input.syntax), + importers: importers, + syntax: syntaxToSyntax(input.syntax), style: style, url: input.url.isEmpty ? null : input.url, sourceMap: sourceMapCallback); @@ -56,7 +81,10 @@ void main(List args) { case InboundMessage_CompileRequest_Input.path: try { result = sass.compile(request.path, - logger: logger, style: style, sourceMap: sourceMapCallback); + logger: logger, + importers: importers, + style: style, + sourceMap: sourceMapCallback); } on FileSystemException catch (error) { return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() @@ -85,17 +113,3 @@ void main(List args) { } }); } - -/// Converts a protocol buffer syntax enum into a Sass API syntax enum. -sass.Syntax _syntaxToSyntax(InboundMessage_Syntax syntax) { - switch (syntax) { - case InboundMessage_Syntax.SCSS: - return sass.Syntax.scss; - case InboundMessage_Syntax.INDENTED: - return sass.Syntax.sass; - case InboundMessage_Syntax.CSS: - return sass.Syntax.css; - default: - throw "Unknown syntax $syntax."; - } -} diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index c8c4b212a..299f6d9b0 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -11,12 +11,20 @@ import 'package:stack_trace/stack_trace.dart'; import 'package:stream_channel/stream_channel.dart'; import 'embedded_sass.pb.dart'; +import 'utils.dart'; /// A class that dispatches messages to and from the host. class Dispatcher { /// The channel of encoded protocol buffers, connected to the host. final StreamChannel _channel; + /// Completers awaiting responses to outbound requests. + /// + /// The completers are located at indexes in this list matching the request + /// IDs. `null` elements indicate IDs whose requests have been responded to, + /// and which are therefore free to re-use. + final _outstandingRequests = >[]; + /// Creates a [Dispatcher] that sends and receives encoded protocol buffers /// over [channel]. Dispatcher(this._channel); @@ -43,7 +51,7 @@ class Dispatcher { switch (message.whichMessage()) { case InboundMessage_Message.error: - var error = message.ensureError(); + var error = message.error; stderr .write("Host reported ${error.type.name.toLowerCase()} error"); if (error.id != -1) stderr.write(" with request ${error.id}"); @@ -54,12 +62,22 @@ class Dispatcher { break; case InboundMessage_Message.compileRequest: - var request = message.ensureCompileRequest(); + var request = message.compileRequest; var response = await callback(request); response.id = request.id; _send(OutboundMessage()..compileResponse = response); break; + case InboundMessage_Message.canonicalizeResponse: + var response = message.canonicalizeResponse; + _dispatchResponse(response.id, response); + break; + + case InboundMessage_Message.importResponse: + var response = message.importResponse; + _dispatchResponse(response.id, response); + break; + case InboundMessage_Message.notSet: // PROTOCOL error from https://bit.ly/2poTt90 exitCode = 76; @@ -72,19 +90,18 @@ class Dispatcher { "Unknown message type: ${message.toDebugString()}"); } } on ProtocolError catch (error) { - error.id = _messageId(message) ?? -1; + error.id = _inboundId(message) ?? -1; stderr.write("Host caused ${error.type.name.toLowerCase()} error"); if (error.id != -1) stderr.write(" with request ${error.id}"); stderr.writeln(": ${error.message}"); - _send(OutboundMessage()..error = error); + sendError(error); } catch (error, stackTrace) { var errorMessage = "$error\n${Chain.forTrace(stackTrace)}"; stderr.write("Internal compiler error: $errorMessage"); - _send(OutboundMessage() - ..error = (ProtocolError() - ..type = ProtocolError_ErrorType.INTERNAL - ..id = _messageId(message) ?? -1 - ..message = errorMessage)); + sendError(ProtocolError() + ..type = ProtocolError_ErrorType.INTERNAL + ..id = _inboundId(message) ?? -1 + ..message = errorMessage); _channel.sink.close(); } }); @@ -94,6 +111,62 @@ class Dispatcher { void sendLog(OutboundMessage_LogEvent event) => _send(OutboundMessage()..logEvent = event); + /// Sends [error] to the host. + void sendError(ProtocolError error) => + _send(OutboundMessage()..error = error); + + Future sendCanonicalizeRequest( + OutboundMessage_CanonicalizeRequest request) => + _sendRequest( + OutboundMessage()..canonicalizeRequest = request); + + Future sendImportRequest( + OutboundMessage_ImportRequest request) => + _sendRequest( + OutboundMessage()..importRequest = request); + + /// Sends [request] to the host and returns the message sent in response. + Future _sendRequest( + OutboundMessage request) async { + var id = _nextRequestId(); + _setOutboundId(request, id); + _send(request); + + var completer = Completer(); + _outstandingRequests[id] = completer; + return completer.future; + } + + /// Returns an available request ID, and guarantees that its slot is available + /// in [_outstandingRequests]. + int _nextRequestId() { + for (var i = 0; i < _outstandingRequests.length; i++) { + if (_outstandingRequests[i] == null) return i; + } + + // If there are no empty slots, add another one. + _outstandingRequests.add(null); + return _outstandingRequests.length - 1; + } + + /// Dispatches [response] to the appropriate outstanding request. + /// + /// Throws an error if there's no outstanding request with the given [id] or + /// if that request is expecting a different type of response. + void _dispatchResponse(int id, T response) { + var completer = + id < _outstandingRequests.length ? _outstandingRequests[id] : null; + if (completer == null) { + throw paramsError( + "Response ID $id doesn't match any outstanding requests."); + } else if (completer is! Completer) { + throw paramsError("Request ID $id doesn't match response type " + "${response.runtimeType}."); + } + + completer.complete(response); + } + /// Sends [message] to the host. void _send(OutboundMessage message) => _channel.sink.add(message.writeToBuffer()); @@ -103,21 +176,40 @@ class Dispatcher { ..type = ProtocolError_ErrorType.PARSE ..message = message; - /// Returns the id for [message] if it it's a request or response, or `null` + /// Returns the id for [message] if it it's a request, or `null` /// otherwise. - int _messageId(InboundMessage message) { + int _inboundId(InboundMessage message) { if (message == null) return null; switch (message.whichMessage()) { case InboundMessage_Message.compileRequest: - return message.ensureCompileRequest().id; - case InboundMessage_Message.canonicalizeResponse: - return message.ensureCanonicalizeResponse().id; - case InboundMessage_Message.importResponse: - return message.ensureImportResponse().id; + return message.compileRequest.id; case InboundMessage_Message.functionCallRequest: - return message.ensureFunctionCallRequest().id; - case InboundMessage_Message.functionCallResponse: - return message.ensureFunctionCallResponse().id; + return message.functionCallRequest.id; + default: + return null; + } + } + + /// Sets the id for [message] to [id]. + /// + /// Throws an [ArgumentError] if [message] doesn't have an id field. + void _setOutboundId(OutboundMessage message, int id) { + switch (message.whichMessage()) { + case OutboundMessage_Message.compileResponse: + message.compileResponse.id = id; + break; + case OutboundMessage_Message.canonicalizeRequest: + message.canonicalizeRequest.id = id; + break; + case OutboundMessage_Message.importRequest: + message.importRequest.id = id; + break; + case OutboundMessage_Message.functionCallRequest: + message.functionCallRequest.id = id; + break; + case OutboundMessage_Message.functionCallResponse: + message.functionCallResponse.id = id; + break; default: return null; } diff --git a/lib/src/importer.dart b/lib/src/importer.dart new file mode 100644 index 000000000..e259b83eb --- /dev/null +++ b/lib/src/importer.dart @@ -0,0 +1,109 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:cli'; + +import 'package:meta/meta.dart'; +import 'package:sass/sass.dart' as sass; + +import 'dispatcher.dart'; +import 'embedded_sass.pb.dart' hide SourceSpan; +import 'utils.dart'; + +/// An importer that asks the host to resolve imports. +class Importer extends sass.Importer { + /// The [Dispatcher] to which to send requests. + final Dispatcher _dispatcher; + + /// The ID of the compilation in which this importer is used. + final int _compilationId; + + /// The host-provided ID of the importer to invoke. + final int _importerId; + + Importer(this._dispatcher, this._compilationId, this._importerId); + + Uri canonicalize(Uri url) { + return waitFor(() async { + var response = await _dispatcher + .sendCanonicalizeRequest(OutboundMessage_CanonicalizeRequest() + ..compilationId = _compilationId + ..importerId = _importerId + ..url = url.toString()); + + switch (response.whichResult()) { + case InboundMessage_CanonicalizeResponse_Result.url: + return _parseAbsoluteUrl("CanonicalizeResponse.url", response.url); + + case InboundMessage_CanonicalizeResponse_Result.file: + throw "CanonicalizeResponse.file is not yet supported"; + + case InboundMessage_CanonicalizeResponse_Result.error: + throw response.error; + + case InboundMessage_CanonicalizeResponse_Result.notSet: + return null; + + default: + throw "Unknown CanonicalizeResponse.result $response."; + } + }()); + } + + sass.ImporterResult load(Uri url) { + return waitFor(() async { + var response = + await _dispatcher.sendImportRequest(OutboundMessage_ImportRequest() + ..compilationId = _compilationId + ..importerId = _importerId + ..url = url.toString()); + + switch (response.whichResult()) { + case InboundMessage_ImportResponse_Result.success: + return sass.ImporterResult(response.success.contents, + sourceMapUrl: response.success.sourceMapUrl.isEmpty + ? null + : _parseAbsoluteUrl("ImportResponse.success.source_map_url", + response.success.sourceMapUrl), + syntax: syntaxToSyntax(response.success.syntax)); + + case InboundMessage_ImportResponse_Result.error: + throw response.error; + + case InboundMessage_ImportResponse_Result.notSet: + _sendAndThrow(mandatoryError("ImportResponse.result")); + break; // dart-lang/sdk#34048 + + default: + throw "Unknown ImporterResponse.result $response."; + } + }()); + } + + /// Parses [url] as a [Uri] and throws an error if it's invalid or relative + /// (including root-relative). + /// + /// The [field] name is used in the error message if one is thrown. + Uri _parseAbsoluteUrl(String field, String url) { + Uri parsedUrl; + try { + parsedUrl = Uri.parse(url); + } on FormatException catch (error) { + _sendAndThrow(paramsError("$field is invalid: $error")); + } + + if (parsedUrl.scheme.isNotEmpty) return parsedUrl; + _sendAndThrow(paramsError('$field must be absolute, was "$parsedUrl"')); + } + + /// Sends [error] to the remote endpoint, and also throws it so that the Sass + /// compilation fails. + @alwaysThrows + void _sendAndThrow(ProtocolError error) { + _dispatcher.sendError(error); + throw "Protocol error: ${error.message}"; + } + + String toString() => "HostImporter"; +} diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 073fa8ffa..8d34bd226 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,16 +2,26 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:sass/sass.dart' as sass; import 'package:source_span/source_span.dart'; import 'embedded_sass.pb.dart' as proto; import 'embedded_sass.pb.dart' hide SourceSpan; -/// Returns a [ProtocolError] indicating that a mandatory field with the givne +/// Returns a [ProtocolError] indicating that a mandatory field with the given /// [fieldName] was missing. -ProtocolError mandatoryError(String fieldName) => ProtocolError() +ProtocolError mandatoryError(String fieldName) => + paramsError("Missing mandatory field $fieldName"); + +/// Returns a [ProtocolError] indicating that the parameters for an inbound +/// message were invalid. +ProtocolError paramsError(String message) => ProtocolError() + // Set the ID to -1 by default, because that's the required value for errors + // that aren't associated with a specific inbound request ID. This will be + // overwritten by the dispatcher if a request ID is available. + ..id = -1 ..type = ProtocolError_ErrorType.PARAMS - ..message = "Missing mandatory field $fieldName"; + ..message = message; /// Converts a Dart source span to a protocol buffer source span. proto.SourceSpan protofySpan(SourceSpan span) { @@ -30,3 +40,17 @@ SourceSpan_SourceLocation _protofyLocation(SourceLocation location) => ..offset = location.offset ..line = location.line ..column = location.column; + +/// Converts a protocol buffer syntax enum into a Sass API syntax enum. +sass.Syntax syntaxToSyntax(InboundMessage_Syntax syntax) { + switch (syntax) { + case InboundMessage_Syntax.SCSS: + return sass.Syntax.scss; + case InboundMessage_Syntax.INDENTED: + return sass.Syntax.sass; + case InboundMessage_Syntax.CSS: + return sass.Syntax.css; + default: + throw "Unknown syntax $syntax."; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index a167ef48f..43e05d6c7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,6 +12,7 @@ executables: dependencies: async: ">=1.13.0 <3.0.0" + meta: ^1.1.0 protobuf: ^1.0.0 sass: ^1.21.0 source_maps: ^0.10.5 diff --git a/test/importer_test.dart b/test/importer_test.dart new file mode 100644 index 000000000..c69aac7e7 --- /dev/null +++ b/test/importer_test.dart @@ -0,0 +1,499 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:source_maps/source_maps.dart' as source_maps; +import 'package:test/test.dart'; +import 'package:test_descriptor/test_descriptor.dart' as d; + +import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +import 'embedded_process.dart'; +import 'utils.dart'; + +void main() { + ensureExecutableUpToDate(); + + EmbeddedProcess process; + setUp(() async { + process = await EmbeddedProcess.start(); + }); + + group("emits a protocol error", () { + test("for a response without a corresponding request ID", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = + (InboundMessage_CanonicalizeResponse()..id = request.id + 1)); + + await expectParamsError( + process, + -1, + "Response ID ${request.id + 1} doesn't match any outstanding " + "requests."); + await process.kill(); + }); + + test("for a response that doesn't match the request type", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse()..id = request.id)); + + await expectParamsError( + process, + -1, + "Request ID ${request.id} doesn't match response type " + "InboundMessage_ImportResponse."); + await process.kill(); + }); + + test("for an unset importer", () async { + process.inbound.add(compileString("a {b: c}", + importers: [InboundMessage_CompileRequest_Importer()])); + await expectParamsError( + process, 0, "Missing mandatory field Importer.importer"); + await process.kill(); + }); + }); + + group("canonicalization", () { + group("emits a protocol error", () { + test("for a canonicalize response with an empty URL", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = request.id + ..url = "")); + + await _expectImportParamsError( + process, 'CanonicalizeResponse.url must be absolute, was ""'); + await process.kill(); + }); + + test("for a canonicalize response with a relative URL", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = request.id + ..url = "relative")); + + await _expectImportParamsError(process, + 'CanonicalizeResponse.url must be absolute, was "relative"'); + await process.kill(); + }); + }); + + group("includes in CanonicalizeRequest", () { + var compilationId = 1234; + var importerId = 5679; + OutboundMessage_CanonicalizeRequest request; + setUp(() async { + process.inbound.add(compileString("@import 'other'", + id: compilationId, + importers: [ + InboundMessage_CompileRequest_Importer()..importerId = importerId + ])); + request = getCanonicalizeRequest(await process.outbound.next); + }); + + test("the same compilationId as the compilation", () async { + expect(request.compilationId, equals(compilationId)); + await process.kill(); + }); + + test("a known importerId", () async { + expect(request.importerId, equals(importerId)); + await process.kill(); + }); + + test("the imported URL", () async { + expect(request.url, equals("other")); + await process.kill(); + }); + }); + + test("errors cause compilation to fail", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = request.id + ..error = "oh no")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals('oh no')); + expect(failure.span.text, equals("'other'")); + expect(failure.stackTrace, equals('- 1:9 root stylesheet\n')); + await process.kill(); + }); + + test("null results count as not found", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = + (InboundMessage_CanonicalizeResponse()..id = request.id)); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals("Can't find stylesheet to import.")); + expect(failure.span.text, equals("'other'")); + await process.kill(); + }); + + test("attempts importers in order", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + for (var i = 0; i < 10; i++) + InboundMessage_CompileRequest_Importer()..importerId = i + ])); + + for (var i = 0; i < 10; i++) { + var request = getCanonicalizeRequest(await process.outbound.next); + expect(request.importerId, equals(i)); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = + (InboundMessage_CanonicalizeResponse()..id = request.id)); + } + + await process.kill(); + }); + + test("tries resolved URL using the original importer first", () async { + process.inbound.add(compileString("@import 'midstream'", importers: [ + for (var i = 0; i < 10; i++) + InboundMessage_CompileRequest_Importer()..importerId = i + ])); + + for (var i = 0; i < 5; i++) { + var request = getCanonicalizeRequest(await process.outbound.next); + expect(request.url, equals("midstream")); + expect(request.importerId, equals(i)); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = + (InboundMessage_CanonicalizeResponse()..id = request.id)); + } + + var canonicalize = getCanonicalizeRequest(await process.outbound.next); + expect(canonicalize.importerId, equals(5)); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = canonicalize.id + ..url = "custom:foo/bar")); + + var import = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = import.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "@import 'upstream'"))); + + canonicalize = getCanonicalizeRequest(await process.outbound.next); + expect(canonicalize.importerId, equals(5)); + expect(canonicalize.url, equals("custom:foo/upstream")); + + await process.kill(); + }); + }); + + group("importing", () { + group("emits a protocol error", () { + test("for an unset import result", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var import = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse()..id = import.id)); + + await _expectImportParamsError( + process, "Missing mandatory field ImportResponse.result"); + await process.kill(); + }); + + test("for an import result with a relative sourceMapUrl", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var import = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = import.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..sourceMapUrl = "relative"))); + + await _expectImportParamsError( + process, + 'ImportResponse.success.source_map_url must be absolute, was ' + '"relative"'); + await process.kill(); + }); + }); + + group("includes in ImportRequest", () { + var compilationId = 1234; + var importerId = 5678; + OutboundMessage_ImportRequest request; + setUp(() async { + process.inbound.add(compileString("@import 'other'", + id: compilationId, + importers: [ + InboundMessage_CompileRequest_Importer()..importerId = importerId + ])); + + var canonicalize = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = canonicalize.id + ..url = "custom:foo")); + + request = getImportRequest(await process.outbound.next); + }); + + test("the same compilationId as the compilation", () async { + expect(request.compilationId, equals(compilationId)); + await process.kill(); + }); + + test("a known importerId", () async { + expect(request.importerId, equals(importerId)); + await process.kill(); + }); + + test("the canonical URL", () async { + expect(request.url, equals("custom:foo")); + await process.kill(); + }); + }); + + test("errors cause compilation to fail", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..error = "oh no")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals('oh no')); + expect(failure.span.text, equals("'other'")); + expect(failure.stackTrace, equals('- 1:9 root stylesheet\n')); + await process.kill(); + }); + + test("can return an SCSS file", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "a {b: 1px + 2px}"))); + + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + + test("can return an indented syntax file", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "a\n b: 1px + 2px" + ..syntax = InboundMessage_Syntax.INDENTED))); + + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + + test("can return a plain CSS file", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "a {b: c}" + ..syntax = InboundMessage_Syntax.CSS))); + + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + + test("uses a data: URL rather than an empty source map URL", () async { + process.inbound.add(compileString("@import 'other'", + sourceMap: true, + importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "a {b: c}" + ..sourceMapUrl = ""))); + + await expectLater( + process.outbound, + emits(isSuccess("a { b: c; }", sourceMap: (String map) { + var mapping = source_maps.parse(map) as source_maps.SingleMapping; + expect(mapping.urls, [startsWith("data:")]); + }))); + await process.kill(); + }); + + test("uses a non-empty source map URL", () async { + process.inbound.add(compileString("@import 'other'", + sourceMap: true, + importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "a {b: c}" + ..sourceMapUrl = "file:///asdf"))); + + await expectLater( + process.outbound, + emits(isSuccess("a { b: c; }", sourceMap: (String map) { + var mapping = source_maps.parse(map) as source_maps.SingleMapping; + expect(mapping.urls, equals(["file:///asdf"])); + }))); + await process.kill(); + }); + }); + + group("load paths", () { + test("are used to load imports", () async { + await d.dir("dir", [d.file("other.scss", "a {b: c}")]).create(); + + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..path = d.path("dir") + ])); + + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + + test("are accessed in order", () async { + for (var i = 0; i < 3; i++) { + await d.dir("dir$i", [d.file("other$i.scss", "a {b: $i}")]).create(); + } + + process.inbound.add(compileString("@import 'other2'", importers: [ + for (var i = 0; i < 3; i++) + InboundMessage_CompileRequest_Importer()..path = d.path("dir$i") + ])); + + await expectLater(process.outbound, emits(isSuccess("a { b: 2; }"))); + await process.kill(); + }); + + test("take precedence over later importers", () async { + await d.dir("dir", [d.file("other.scss", "a {b: c}")]).create(); + + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..path = d.path("dir"), + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + + test("yield precedence to earlier importers", () async { + await d.dir("dir", [d.file("other.scss", "a {b: c}")]).create(); + + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1, + InboundMessage_CompileRequest_Importer()..path = d.path("dir") + ])); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "x {y: z}"))); + + await expectLater(process.outbound, emits(isSuccess("x { y: z; }"))); + await process.kill(); + }); + }); +} + +/// Handles a `CanonicalizeRequest` and returns a response with a generic +/// canonical URL. +/// +/// This is used when testing import requests, to avoid duplicating a bunch of +/// generic code for canonicalization. It shouldn't be used for testing +/// canonicalization itself. +Future _canonicalize(EmbeddedProcess process) async { + var request = getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = request.id + ..url = "custom:other")); +} + +/// Asserts that [process] emits a [ProtocolError] params error with the given +/// [message] on its protobuf stream and causes the compilation to fail. +Future _expectImportParamsError(EmbeddedProcess process, message) async { + await expectLater(process.outbound, + emits(isProtocolError(-1, ProtocolError_ErrorType.PARAMS, message))); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals('Protocol error: $message')); + expect(failure.span.text, equals("'other'")); +} diff --git a/test/protocol_test.dart b/test/protocol_test.dart index ab72aef6b..b72d79a7f 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -144,14 +144,14 @@ void main() { process.inbound.add(compileString("a {b: 1px + 2px}", sourceMap: true)); await expectLater( process.outbound, - emits(isSuccess("a { b: 3px; }", sourceMap: predicate((map) { + emits(isSuccess("a { b: 3px; }", sourceMap: (map) { var mapping = source_maps.parse(map); var span = mapping.spanFor(2, 5); expect(span.start.line, equals(0)); expect(span.start.column, equals(3)); expect(span.end, equals(span.start)); return true; - })))); + }))); await process.kill(); }); diff --git a/test/utils.dart b/test/utils.dart index 6b7aaa6fa..c5adc9304 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -94,13 +94,15 @@ InboundMessage compileString(String css, InboundMessage_Syntax syntax, InboundMessage_CompileRequest_OutputStyle style, String url, - bool sourceMap}) { + bool sourceMap, + Iterable importers}) { var input = InboundMessage_CompileRequest_StringInput()..source = css; if (syntax != null) input.syntax = syntax; if (url != null) input.url = url; var request = InboundMessage_CompileRequest()..string = input; if (id != null) request.id = id; + if (importers != null) request.importers.addAll(importers); if (style != null) request.style = style; if (sourceMap != null) request.sourceMap = sourceMap; @@ -115,6 +117,17 @@ Future expectParseError(EmbeddedProcess process, message) async { await expectLater(process.stderr, emits("Host caused parse error: $message")); } +/// Asserts that [process] emits a [ProtocolError] params error with the given +/// [message] on its protobuf stream and prints a notice on stderr. +Future expectParamsError(EmbeddedProcess process, int id, message) async { + await expectLater(process.outbound, + emits(isProtocolError(id, ProtocolError_ErrorType.PARAMS, message))); + await expectLater( + process.stderr, + emits("Host caused params error${id == -1 ? '' : " with request $id"}: " + "$message")); +} + /// Asserts that an [OutboundMessage] is a [ProtocolError] with the given [id], /// [type], and optionally [message]. Matcher isProtocolError(int id, ProtocolError_ErrorType type, [message]) => @@ -122,13 +135,33 @@ Matcher isProtocolError(int id, ProtocolError_ErrorType type, [message]) => expect(value, isA()); var outboundMessage = value as OutboundMessage; expect(outboundMessage.hasError(), isTrue, - reason: "Expected $message to be a ProtocolError"); + reason: "Expected $outboundMessage to be a ProtocolError"); expect(outboundMessage.error.id, equals(id)); expect(outboundMessage.error.type, equals(type)); if (message != null) expect(outboundMessage.error.message, message); return true; }); +/// Asserts that [message] is an [OutboundMessage] with a +/// `CanonicalizeRequest` and returns it. +OutboundMessage_CanonicalizeRequest getCanonicalizeRequest(value) { + expect(value, isA()); + var message = value as OutboundMessage; + expect(message.hasCanonicalizeRequest(), isTrue, + reason: "Expected $message to have a CanonicalizeRequest"); + return message.canonicalizeRequest; +} + +/// Asserts that [message] is an [OutboundMessage] with a `ImportRequest` and +/// returns it. +OutboundMessage_ImportRequest getImportRequest(value) { + expect(value, isA()); + var message = value as OutboundMessage; + expect(message.hasImportRequest(), isTrue, + reason: "Expected $message to have a ImportRequest"); + return message.importRequest; +} + /// Asserts that [message] is an [OutboundMessage] with a /// `CompileResponse.Failure` and returns it. OutboundMessage_CompileResponse_CompileFailure getCompileFailure(value) { @@ -163,13 +196,20 @@ OutboundMessage_LogEvent getLogEvent(value) { /// /// If [css] is a [String], this automatically wraps it in /// [equalsIgnoringWhitespace]. +/// +/// If [sourceMap] is a function, `response.success.sourceMap` is passed to it. +/// Otherwise, it's treated as a matcher for `response.success.sourceMap`. Matcher isSuccess(css, {sourceMap}) => predicate((value) { var response = getCompileResponse(value); expect(response.hasSuccess(), isTrue, reason: "Expected $response to be successful"); expect(response.success.css, css is String ? equalsIgnoringWhitespace(css) : css); - if (sourceMap != null) expect(response.success.sourceMap, sourceMap); + if (sourceMap is void Function(String)) { + sourceMap(response.success.sourceMap); + } else if (sourceMap != null) { + expect(response.success.sourceMap, sourceMap); + } return true; }); From 6b34ffd7f3093b0a39d72e69f2dd39037f4b459b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 8 Nov 2019 15:25:42 -0800 Subject: [PATCH 014/162] Add the ability to invoke functions (#9) This doesn't yet support first-class function values. --- bin/dart_sass_embedded.dart | 69 +- lib/src/dispatcher.dart | 16 + lib/src/importer.dart | 12 +- lib/src/value.dart | 180 ++++++ test/function_test.dart | 1195 +++++++++++++++++++++++++++++++++++ test/utils.dart | 50 +- 6 files changed, 1502 insertions(+), 20 deletions(-) create mode 100644 lib/src/value.dart create mode 100644 test/function_test.dart diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 66cbeff6e..7065893d3 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. import 'dart:io'; +import 'dart:cli'; import 'dart:convert'; import 'package:sass/sass.dart' as sass; @@ -15,6 +16,7 @@ import 'package:sass_embedded/src/importer.dart'; import 'package:sass_embedded/src/logger.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; import 'package:sass_embedded/src/utils.dart'; +import 'package:sass_embedded/src/value.dart'; void main(List args) { if (args.isNotEmpty) { @@ -60,18 +62,22 @@ void main(List args) { case InboundMessage_CompileRequest_Importer_Importer.notSet: throw mandatoryError("Importer.importer"); - - default: - throw "Unknown Importer.importer $importer."; } + + // dart-lang/sdk#38790 + throw "Unknown Importer.importer $importer."; }); + var functions = request.globalFunctions + .map((signature) => _hostCallable(dispatcher, request.id, signature)); + switch (request.whichInput()) { case InboundMessage_CompileRequest_Input.string: var input = request.string; result = sass.compileString(input.source, logger: logger, importers: importers, + functions: functions, syntax: syntaxToSyntax(input.syntax), style: style, url: input.url.isEmpty ? null : input.url, @@ -83,6 +89,7 @@ void main(List args) { result = sass.compile(request.path, logger: logger, importers: importers, + functions: functions, style: style, sourceMap: sourceMapCallback); } on FileSystemException catch (error) { @@ -113,3 +120,59 @@ void main(List args) { } }); } + +/// Returns a Sass callable that invokes a function defined on the host with the +/// given [signature]. +/// +/// Throws a [ProtocolError] if [signature] is invalid. +sass.Callable _hostCallable( + Dispatcher dispatcher, int compilationId, String signature) { + var openParen = signature.indexOf('('); + if (openParen == -1) { + throw paramsError( + 'CompileRequest.global_functions: "$signature" is missing "("'); + } + + if (!signature.endsWith(")")) { + throw paramsError( + 'CompileRequest.global_functions: "$signature" doesn\'t end with ' + '")"'); + } + + var name = signature.substring(0, openParen); + try { + return sass.Callable( + name, signature.substring(openParen + 1, signature.length - 1), + (arguments) { + var request = OutboundMessage_FunctionCallRequest() + ..compilationId = compilationId + ..name = name + ..arguments.addAll(arguments.map(protofyValue)); + + var response = waitFor(dispatcher.sendFunctionCallRequest(request)); + try { + switch (response.whichResult()) { + case InboundMessage_FunctionCallResponse_Result.success: + return deprotofyValue(response.success); + + case InboundMessage_FunctionCallResponse_Result.error: + throw response.error; + + case InboundMessage_FunctionCallResponse_Result.notSet: + throw mandatoryError('FunctionCallResponse.result'); + } + + // dart-lang/sdk#38790 + throw "Unknown FunctionCallResponse.result $response."; + } on ProtocolError catch (error) { + error.id = -1; + stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " + "${error.message}"); + dispatcher.sendError(error); + throw error.message; + } + }); + } on sass.SassException catch (error) { + throw paramsError('CompileRequest.global_functions: $error'); + } +} diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 299f6d9b0..1279cbcbb 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -41,6 +41,12 @@ class Dispatcher { FutureOr callback( InboundMessage_CompileRequest request)) { _channel.stream.listen((binaryMessage) async { + // Wait a single microtask tick so that we're running in a separate + // microtask from the initial request dispatch. Otherwise, [waitFor] will + // deadlock the event loop fiber that would otherwise be checking stdin + // for new input. + await Future.value(); + InboundMessage message; try { try { @@ -78,6 +84,11 @@ class Dispatcher { _dispatchResponse(response.id, response); break; + case InboundMessage_Message.functionCallResponse: + var response = message.functionCallResponse; + _dispatchResponse(response.id, response); + break; + case InboundMessage_Message.notSet: // PROTOCOL error from https://bit.ly/2poTt90 exitCode = 76; @@ -125,6 +136,11 @@ class Dispatcher { _sendRequest( OutboundMessage()..importRequest = request); + Future sendFunctionCallRequest( + OutboundMessage_FunctionCallRequest request) => + _sendRequest( + OutboundMessage()..functionCallRequest = request); + /// Sends [request] to the host and returns the message sent in response. Future _sendRequest( OutboundMessage request) async { diff --git a/lib/src/importer.dart b/lib/src/importer.dart index e259b83eb..83263eb4e 100644 --- a/lib/src/importer.dart +++ b/lib/src/importer.dart @@ -44,10 +44,10 @@ class Importer extends sass.Importer { case InboundMessage_CanonicalizeResponse_Result.notSet: return null; - - default: - throw "Unknown CanonicalizeResponse.result $response."; } + + // dart-lang/sdk#38790 + throw "Unknown CanonicalizeResponse.result $response."; }()); } @@ -74,10 +74,10 @@ class Importer extends sass.Importer { case InboundMessage_ImportResponse_Result.notSet: _sendAndThrow(mandatoryError("ImportResponse.result")); break; // dart-lang/sdk#34048 - - default: - throw "Unknown ImporterResponse.result $response."; } + + // dart-lang/sdk#38790 + throw "Unknown ImporterResponse.result $response."; }()); } diff --git a/lib/src/value.dart b/lib/src/value.dart new file mode 100644 index 000000000..218dcf12c --- /dev/null +++ b/lib/src/value.dart @@ -0,0 +1,180 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:sass/sass.dart' as sass; +import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +import 'utils.dart'; + +/// Converts [value] to its protocol buffer representation. +Value protofyValue(sass.Value value) { + var result = Value(); + if (value is sass.SassString) { + result.string = Value_String() + ..text = value.text + ..quoted = value.hasQuotes; + } else if (value is sass.SassNumber) { + var number = Value_Number()..value = value.value * 1.0; + number.numerators.addAll(value.numeratorUnits); + number.denominators.addAll(value.denominatorUnits); + result.number = number; + } else if (value is sass.SassColor) { + // TODO(nweiz): If the color is represented as HSL internally, this coerces + // it to RGB. Is it worth providing some visibility into its internal + // representation so we can serialize without converting? + result.rgbColor = Value_RgbColor() + ..red = value.red + ..green = value.green + ..blue = value.blue + ..alpha = value.alpha * 1.0; + } else if (value is sass.SassList) { + var list = Value_List() + ..separator = _protofySeparator(value.separator) + ..hasBrackets = value.hasBrackets; + list.contents.addAll(value.asList.map(protofyValue)); + result.list = list; + } else if (value is sass.SassMap) { + var map = Value_Map(); + value.contents.forEach((key, value) { + map.entries.add(Value_Map_Entry() + ..key = protofyValue(key) + ..value = protofyValue(value)); + }); + result.map = map; + } else if (value == sass.sassTrue) { + result.singleton = Value_Singleton.TRUE; + } else if (value == sass.sassFalse) { + result.singleton = Value_Singleton.FALSE; + } else if (value == sass.sassNull) { + result.singleton = Value_Singleton.NULL; + } else { + throw "Unknown Value $value"; + } + return result; +} + +/// Converts [separator] to its protocol buffer representation. +Value_List_Separator _protofySeparator(sass.ListSeparator separator) { + switch (separator) { + case sass.ListSeparator.comma: + return Value_List_Separator.COMMA; + case sass.ListSeparator.space: + return Value_List_Separator.SPACE; + case sass.ListSeparator.undecided: + return Value_List_Separator.UNDECIDED; + default: + throw "Unknown ListSeparator $separator"; + } +} + +/// Converts [value] to its Sass representation. +sass.Value deprotofyValue(Value value) { + switch (value.whichValue()) { + case Value_Value.string: + return value.string.text.isEmpty + ? sass.SassString.empty(quotes: value.string.quoted) + : sass.SassString(value.string.text, quotes: value.string.quoted); + + case Value_Value.number: + return sass.SassNumber.withUnits(value.number.value, + numeratorUnits: value.number.numerators, + denominatorUnits: value.number.denominators); + + case Value_Value.rgbColor: + return sass.SassColor.rgb( + _checkInRange('RgbColor.red', value.rgbColor.red, 0, 255), + _checkInRange('RgbColor.green', value.rgbColor.green, 0, 255), + _checkInRange('RgbColor.blue', value.rgbColor.blue, 0, 255), + _checkInRange('RgbColor.alpha', value.rgbColor.alpha, 0, 1)); + + case Value_Value.hslColor: + return sass.SassColor.hsl( + value.hslColor.hue, + _checkInRange( + 'HslColor.saturation', value.hslColor.saturation, 0, 100), + _checkInRange('HslColor.lightness', value.hslColor.lightness, 0, 100), + _checkInRange('HslColor.alpha', value.hslColor.alpha, 0, 1)); + + case Value_Value.list: + var separator = _deprotofySeparator(value.list.separator); + if (value.list.contents.isEmpty) { + return sass.SassList.empty( + separator: separator, brackets: value.list.hasBrackets); + } + + var length = value.list.contents.length; + if (separator == sass.ListSeparator.undecided && length > 1) { + throw paramsError( + "List $value can't have an undecided separator because it has " + "$length elements"); + } + + return sass.SassList(value.list.contents.map(deprotofyValue), separator, + brackets: value.list.hasBrackets); + + case Value_Value.map: + return value.map.entries.isEmpty + ? const sass.SassMap.empty() + : sass.SassMap({ + for (var entry in value.map.entries) + deprotofyValue(entry.key): deprotofyValue(entry.value) + }); + + case Value_Value.compilerFunction: + throw "CompilerFunctions are not yet supported."; + + case Value_Value.hostFunction: + throw "HostFunctions not yet supported."; + + case Value_Value.singleton: + switch (value.singleton) { + case Value_Singleton.TRUE: + return sass.sassTrue; + case Value_Singleton.FALSE: + return sass.sassFalse; + case Value_Singleton.NULL: + return sass.sassNull; + default: + throw "Unknown Value.singleton ${value.singleton}"; + } + // dart-lang/sdk#39304 + throw "Unreachable"; // ignore: dead_code + + case Value_Value.notSet: + throw mandatoryError("Value.value"); + } + + // dart-lang/sdk#38790 + throw "Unknown Value.value $value."; +} + +/// Converts [separator] to its Sass representation. +sass.ListSeparator _deprotofySeparator(Value_List_Separator separator) { + switch (separator) { + case Value_List_Separator.COMMA: + return sass.ListSeparator.comma; + case Value_List_Separator.SPACE: + return sass.ListSeparator.space; + case Value_List_Separator.UNDECIDED: + return sass.ListSeparator.undecided; + default: + throw "Unknown separator $separator"; + } +} + +/// Throws a parameter error if [value] isn't between [lower] and [upper], both +/// inclusive. +/// +/// Returns [value] if it is within the range. +T _checkInRange(String field, T value, num lower, num upper) { + if (value < lower) { + throw paramsError( + '$field must be greater than or equal to $lower, was $value'); + } else if (value > upper) { + throw paramsError( + '$field must be less than or equal to $upper, was $value'); + } else { + return value; + } +} diff --git a/test/function_test.dart b/test/function_test.dart new file mode 100644 index 000000000..a70b41f90 --- /dev/null +++ b/test/function_test.dart @@ -0,0 +1,1195 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:test/test.dart'; + +import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +import 'embedded_process.dart'; +import 'utils.dart'; + +final _true = Value()..singleton = Value_Singleton.TRUE; +final _false = Value()..singleton = Value_Singleton.FALSE; +final _null = Value()..singleton = Value_Singleton.NULL; + +EmbeddedProcess _process; + +void main() { + ensureExecutableUpToDate(); + + setUp(() async { + _process = await EmbeddedProcess.start(); + }); + + group("emits a protocol error", () { + test("for an empty signature", () async { + _process.inbound.add(compileString("a {b: c}", functions: [r""])); + await expectParamsError( + _process, 0, 'CompileRequest.global_functions: "" is missing "("'); + await _process.kill(); + }); + + test("for a signature with just a name", () async { + _process.inbound.add(compileString("a {b: c}", functions: [r"foo"])); + await expectParamsError( + _process, 0, 'CompileRequest.global_functions: "foo" is missing "("'); + await _process.kill(); + }); + + test("for a signature without a closing paren", () async { + _process.inbound.add(compileString("a {b: c}", functions: [r"foo($bar"])); + await expectParamsError(_process, 0, + 'CompileRequest.global_functions: "foo(\$bar" doesn\'t end with ")"'); + await _process.kill(); + }); + + test("for a signature with text after the closing paren", () async { + _process.inbound.add(compileString("a {b: c}", functions: [r"foo() "])); + await expectParamsError(_process, 0, + 'CompileRequest.global_functions: "foo() " doesn\'t end with ")"'); + await _process.kill(); + }); + + test("for a signature with invalid arguments", () async { + _process.inbound.add(compileString("a {b: c}", functions: [r"foo($)"])); + await expectParamsError( + _process, + 0, + 'CompileRequest.global_functions: Error: Expected identifier.\n' + ' ╷\n' + '1 │ (\$)\n' + ' │ ^\n' + ' ╵\n' + ' - 1:3 root stylesheet'); + await _process.kill(); + }); + }); + + group("includes in FunctionCallRequest", () { + var compilationId = 1234; + OutboundMessage_FunctionCallRequest request; + setUp(() async { + _process.inbound.add(compileString("a {b: foo()}", + id: compilationId, functions: ["foo()"])); + request = getFunctionCallRequest(await _process.outbound.next); + }); + + test("the same compilationId as the compilation", () async { + expect(request.compilationId, equals(compilationId)); + await _process.kill(); + }); + + test("the function name", () async { + expect(request.name, equals("foo")); + await _process.kill(); + }); + + group("arguments", () { + test("that are empty", () async { + _process.inbound + .add(compileString("a {b: foo()}", functions: ["foo()"])); + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, isEmpty); + await _process.kill(); + }); + + test("by position", () async { + _process.inbound.add(compileString("a {b: foo(true, null, false)}", + functions: [r"foo($arg1, $arg2, $arg3)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, equals([_true, _null, _false])); + await _process.kill(); + }); + + test("by name", () async { + _process.inbound.add(compileString( + r"a {b: foo($arg3: true, $arg1: null, $arg2: false)}", + functions: [r"foo($arg1, $arg2, $arg3)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, equals([_null, _false, _true])); + await _process.kill(); + }); + + test("by position and name", () async { + _process.inbound.add(compileString( + r"a {b: foo(true, $arg3: null, $arg2: false)}", + functions: [r"foo($arg1, $arg2, $arg3)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, equals([_true, _false, _null])); + await _process.kill(); + }); + + test("from defaults", () async { + _process.inbound.add(compileString(r"a {b: foo(1, $arg3: 2)}", + functions: [r"foo($arg1: null, $arg2: true, $arg3: false)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + expect( + request.arguments, + equals([ + Value()..number = (Value_Number()..value = 1.0), + _true, + Value()..number = (Value_Number()..value = 2.0) + ])); + await _process.kill(); + }); + + test("from argument lists", () async { + _process.inbound.add(compileString("a {b: foo(true, false, null)}", + functions: [r"foo($arg, $args...)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + + expect( + request.arguments, + equals([ + _true, + Value() + ..list = (Value_List() + ..separator = Value_List_Separator.COMMA + ..hasBrackets = false + ..contents.addAll([_false, _null])) + ])); + await _process.kill(); + }); + }); + }); + + test("returns the result as a SassScript value", () async { + _process.inbound + .add(compileString("a {b: foo() + 2px}", functions: [r"foo()"])); + var request = getFunctionCallRequest(await _process.outbound.next); + + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = (Value() + ..number = (Value_Number() + ..value = 1 + ..numerators.add("px"))))); + + await expectLater( + _process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); + await _process.kill(); + }); + + group("serializes to protocol buffers", () { + group("a string that's", () { + group("quoted", () { + test("and empty", () async { + var value = (await _protofy('""')).string; + expect(value.text, isEmpty); + expect(value.quoted, isTrue); + }); + + test("and non-empty", () async { + var value = (await _protofy('"foo bar"')).string; + expect(value.text, equals("foo bar")); + expect(value.quoted, isTrue); + }); + }); + + group("unquoted", () { + test("and empty", () async { + var value = (await _protofy('unquote("")')).string; + expect(value.text, isEmpty); + expect(value.quoted, isFalse); + }); + + test("and non-empty", () async { + var value = (await _protofy('"foo bar"')).string; + expect(value.text, equals("foo bar")); + expect(value.quoted, isTrue); + }); + }); + }); + + group("a number", () { + group("that's unitless", () { + test("and an integer", () async { + var value = (await _protofy('1')).number; + expect(value.value, equals(1.0)); + expect(value.numerators, isEmpty); + expect(value.denominators, isEmpty); + }); + + test("and a float", () async { + var value = (await _protofy('1.5')).number; + expect(value.value, equals(1.5)); + expect(value.numerators, isEmpty); + expect(value.denominators, isEmpty); + }); + }); + + test("with one numerator", () async { + var value = (await _protofy('1em')).number; + expect(value.value, equals(1.0)); + expect(value.numerators, ["em"]); + expect(value.denominators, isEmpty); + }); + + test("with multiple numerators", () async { + var value = (await _protofy('1em * 1px * 1foo')).number; + expect(value.value, equals(1.0)); + expect(value.numerators, unorderedEquals(["em", "px", "foo"])); + expect(value.denominators, isEmpty); + }); + + test("with one denominator", () async { + var value = (await _protofy('1/1em')).number; + expect(value.value, equals(1.0)); + expect(value.numerators, isEmpty); + expect(value.denominators, ["em"]); + }); + + test("with multiple denominators", () async { + var value = (await _protofy('1/1em/1px/1foo')).number; + expect(value.value, equals(1.0)); + expect(value.numerators, isEmpty); + expect(value.denominators, unorderedEquals(["em", "px", "foo"])); + }); + + test("with numerators and denominators", () async { + var value = (await _protofy('1em * 1px/1s/1foo')).number; + expect(value.value, equals(1.0)); + expect(value.numerators, unorderedEquals(["em", "px"])); + expect(value.denominators, unorderedEquals(["s", "foo"])); + }); + }); + + group("a color that's", () { + group("rgb", () { + group("without alpha:", () { + test("black", () async { + expect(await _protofy('#000'), _rgb(0, 0, 0, 1.0)); + }); + + test("white", () async { + expect(await _protofy('#fff'), equals(_rgb(255, 255, 255, 1.0))); + }); + + test("in the middle", () async { + expect(await _protofy('#abc'), equals(_rgb(0xaa, 0xbb, 0xcc, 1.0))); + }); + }); + + group("with alpha", () { + test("0", () async { + expect(await _protofy('rgb(10, 20, 30, 0)'), + equals(_rgb(10, 20, 30, 0.0))); + }); + + test("1", () async { + expect(await _protofy('rgb(10, 20, 30, 1)'), + equals(_rgb(10, 20, 30, 1.0))); + }); + + test("between 0 and 1", () async { + expect(await _protofy('rgb(10, 20, 30, 0.123)'), + equals(_rgb(10, 20, 30, 0.123))); + }); + }); + }); + + group("hsl", () { + group("without alpha:", () { + group("hue", () { + test("0", () async { + expect(await _protofy('hsl(0, 50, 50)'), _rgb(191, 64, 64, 1.0)); + }); + + test("360", () async { + expect( + await _protofy('hsl(360, 50, 50)'), _rgb(191, 64, 64, 1.0)); + }); + + test("below 0", () async { + expect( + await _protofy('hsl(-100, 50, 50)'), _rgb(106, 64, 191, 1.0)); + }); + + test("between 0 and 360", () async { + expect( + await _protofy('hsl(100, 50, 50)'), _rgb(106, 191, 64, 1.0)); + }); + + test("above 360", () async { + expect( + await _protofy('hsl(560, 50, 50)'), _rgb(64, 149, 191, 1.0)); + }); + }); + + group("saturation", () { + test("0", () async { + expect(await _protofy('hsl(0, 0, 50)'), _rgb(128, 128, 128, 1.0)); + }); + + test("100", () async { + expect(await _protofy('hsl(0, 100, 50)'), _rgb(255, 0, 0, 1.0)); + }); + + test("in the middle", () async { + expect(await _protofy('hsl(0, 42, 50)'), _rgb(181, 74, 74, 1.0)); + }); + }); + + group("lightness", () { + test("0", () async { + expect(await _protofy('hsl(0, 50, 0)'), _rgb(0, 0, 0, 1.0)); + }); + + test("100", () async { + expect( + await _protofy('hsl(0, 50, 100)'), _rgb(255, 255, 255, 1.0)); + }); + + test("in the middle", () async { + expect(await _protofy('hsl(0, 50, 42)'), _rgb(161, 54, 54, 1.0)); + }); + }); + }); + + group("with alpha", () { + test("0", () async { + expect(await _protofy('hsl(10, 20, 30, 0)'), + equals(_rgb(92, 66, 61, 0.0))); + }); + + test("1", () async { + expect(await _protofy('hsl(10, 20, 30, 1)'), + equals(_rgb(92, 66, 61, 1.0))); + }); + + test("between 0 and 1", () async { + expect(await _protofy('hsl(10, 20, 30, 0.123)'), + equals(_rgb(92, 66, 61, 0.123))); + }); + }); + }); + }); + + group("a list", () { + group("with no elements", () { + group("with brackets", () { + test("with unknown separator", () async { + var list = (await _protofy("[]")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.UNDECIDED)); + }); + + test("with a comma separator", () async { + var list = + (await _protofy(r"list.join([], [], $separator: comma)")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.COMMA)); + }); + + test("with a space separator", () async { + var list = + (await _protofy(r"list.join([], [], $separator: space)")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.SPACE)); + }); + }); + + group("without brackets", () { + test("with unknown separator", () async { + var list = (await _protofy("()")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.UNDECIDED)); + }); + + test("with a comma separator", () async { + var list = + (await _protofy(r"list.join((), (), $separator: comma)")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.COMMA)); + }); + + test("with a space separator", () async { + var list = + (await _protofy(r"list.join((), (), $separator: space)")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.SPACE)); + }); + }); + }); + + group("with one element", () { + group("with brackets", () { + test("with unknown separator", () async { + var list = (await _protofy("[true]")).list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.UNDECIDED)); + }); + + test("with a comma separator", () async { + var list = (await _protofy(r"[true,]")).list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.COMMA)); + }); + + test("with a space separator", () async { + var list = + (await _protofy(r"list.join([true], [], $separator: space)")) + .list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.SPACE)); + }); + }); + + group("without brackets", () { + test("with a comma separator", () async { + var list = (await _protofy(r"(true,)")).list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.COMMA)); + }); + + test("with a space separator", () async { + var list = + (await _protofy(r"list.join(true, (), $separator: space)")) + .list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.SPACE)); + }); + }); + }); + + group("with multiple elements", () { + group("with brackets", () { + test("with a comma separator", () async { + var list = (await _protofy(r"[true, null, false]")).list; + expect(list.contents, equals([_true, _null, _false])); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.COMMA)); + }); + + test("with a space separator", () async { + var list = (await _protofy(r"[true null false]")).list; + expect(list.contents, equals([_true, _null, _false])); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(Value_List_Separator.SPACE)); + }); + }); + + group("without brackets", () { + test("with a comma separator", () async { + var list = (await _protofy(r"true, null, false")).list; + expect(list.contents, equals([_true, _null, _false])); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.COMMA)); + }); + + test("with a space separator", () async { + var list = (await _protofy(r"true null false")).list; + expect(list.contents, equals([_true, _null, _false])); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(Value_List_Separator.SPACE)); + }); + }); + }); + }); + + group("a map", () { + test("with no elements", () async { + expect((await _protofy("map.remove((1: 2), 1)")).map.entries, isEmpty); + }); + + test("with one element", () async { + expect( + (await _protofy("(true: false)")).map.entries, + equals([ + Value_Map_Entry() + ..key = _true + ..value = _false + ])); + }); + + test("with multiple elements", () async { + expect( + (await _protofy("(true: false, 1: 2, a: b)")).map.entries, + equals([ + Value_Map_Entry() + ..key = _true + ..value = _false, + Value_Map_Entry() + ..key = (Value()..number = (Value_Number()..value = 1.0)) + ..value = (Value()..number = (Value_Number()..value = 2.0)), + Value_Map_Entry() + ..key = (Value() + ..string = (Value_String() + ..text = "a" + ..quoted = false)) + ..value = (Value() + ..string = (Value_String() + ..text = "b" + ..quoted = false)) + ])); + }); + }); + + test("true", () async { + expect((await _protofy("true")), equals(_true)); + }); + + test("false", () async { + expect((await _protofy("false")), equals(_false)); + }); + + test("true", () async { + expect((await _protofy("null")), equals(_null)); + }); + }); + + group("deserializes from protocol buffer", () { + group("a string that's", () { + group("quoted", () { + test("and empty", () async { + expect( + await _deprotofy(Value() + ..string = (Value_String() + ..text = "" + ..quoted = true)), + '""'); + }); + + test("and non-empty", () async { + expect( + await _deprotofy(Value() + ..string = (Value_String() + ..text = "foo bar" + ..quoted = true)), + '"foo bar"'); + }); + }); + + group("unquoted", () { + test("and empty", () async { + // We can't use [_deprotofy] here because a property with an empty + // value won't render at all. + await _assertRoundTrips(Value() + ..string = (Value_String() + ..text = "" + ..quoted = false)); + }); + + test("and non-empty", () async { + expect( + await _deprotofy(Value() + ..string = (Value_String() + ..text = "foo bar" + ..quoted = false)), + "foo bar"); + }); + }); + }); + + group("a number", () { + group("that's unitless", () { + test("and an integer", () async { + expect( + await _deprotofy(Value()..number = (Value_Number()..value = 1.0)), + "1"); + }); + + test("and a float", () async { + expect( + await _deprotofy(Value()..number = (Value_Number()..value = 1.5)), + "1.5"); + }); + }); + + test("with one numerator", () async { + expect( + await _deprotofy(Value() + ..number = (Value_Number() + ..value = 1 + ..numerators.add("em"))), + "1em"); + }); + + test("with multiple numerators", () async { + expect( + await _deprotofy( + Value() + ..number = (Value_Number() + ..value = 1 + ..numerators.addAll(["em", "px", "foo"])), + inspect: true), + "1em*px*foo"); + }); + + test("with one denominator", () async { + expect( + await _deprotofy( + Value() + ..number = (Value_Number() + ..value = 1 + ..denominators.add("em")), + inspect: true), + "1em^-1"); + }); + + test("with multiple denominators", () async { + expect( + await _deprotofy( + Value() + ..number = (Value_Number() + ..value = 1 + ..denominators.addAll(["em", "px", "foo"])), + inspect: true), + "1(em*px*foo)^-1"); + }); + + test("with numerators and denominators", () async { + expect( + await _deprotofy( + Value() + ..number = (Value_Number() + ..value = 1 + ..numerators.addAll(["em", "px"]) + ..denominators.addAll(["s", "foo"])), + inspect: true), + "1em*px/s*foo"); + }); + }); + + group("a color that's", () { + group("rgb", () { + group("without alpha:", () { + test("black", () async { + expect(await _deprotofy(_rgb(0, 0, 0, 1.0)), equals('black')); + }); + + test("white", () async { + expect(await _deprotofy(_rgb(255, 255, 255, 1.0)), equals('white')); + }); + + test("in the middle", () async { + expect(await _deprotofy(_rgb(0xaa, 0xbb, 0xcc, 1.0)), + equals('#aabbcc')); + }); + }); + + group("with alpha", () { + test("0", () async { + expect(await _deprotofy(_rgb(10, 20, 30, 0.0)), + equals('rgba(10, 20, 30, 0)')); + }); + + test("between 0 and 1", () async { + expect(await _deprotofy(_rgb(10, 20, 30, 0.123)), + equals('rgba(10, 20, 30, 0.123)')); + }); + }); + }); + + group("hsl", () { + group("without alpha:", () { + group("hue", () { + test("0", () async { + expect(await _deprotofy(_hsl(0, 50, 50, 1.0)), "#bf4040"); + }); + + test("360", () async { + expect(await _deprotofy(_hsl(360, 50, 50, 1.0)), "#bf4040"); + }); + + test("below 0", () async { + expect(await _deprotofy(_hsl(-100, 50, 50, 1.0)), "#6a40bf"); + }); + + test("between 0 and 360", () async { + expect(await _deprotofy(_hsl(100, 50, 50, 1.0)), "#6abf40"); + }); + + test("above 360", () async { + expect(await _deprotofy(_hsl(560, 50, 50, 1.0)), "#4095bf"); + }); + }); + + group("saturation", () { + test("0", () async { + expect(await _deprotofy(_hsl(0, 0, 50, 1.0)), "gray"); + }); + + test("100", () async { + expect(await _deprotofy(_hsl(0, 100, 50, 1.0)), "red"); + }); + + test("in the middle", () async { + expect(await _deprotofy(_hsl(0, 42, 50, 1.0)), "#b54a4a"); + }); + }); + + group("lightness", () { + test("0", () async { + expect(await _deprotofy(_hsl(0, 50, 0, 1.0)), "black"); + }); + + test("100", () async { + expect(await _deprotofy(_hsl(0, 50, 100, 1.0)), "white"); + }); + + test("in the middle", () async { + expect(await _deprotofy(_hsl(0, 50, 42, 1.0)), "#a13636"); + }); + }); + }); + + group("with alpha", () { + test("0", () async { + expect( + await _deprotofy(_hsl(10, 20, 30, 0.0)), "rgba(92, 66, 61, 0)"); + }); + + test("between 0 and 1", () async { + expect(await _deprotofy(_hsl(10, 20, 30, 0.123)), + "rgba(92, 66, 61, 0.123)"); + }); + }); + }); + }); + + group("a list", () { + group("with no elements", () { + group("with brackets", () { + group("with unknown separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = true + ..separator = Value_List_Separator.UNDECIDED), + "[]"); + }); + + group("with a comma separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = true + ..separator = Value_List_Separator.COMMA), + "[]"); + }); + + group("with a space separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = true + ..separator = Value_List_Separator.SPACE), + "[]"); + }); + }); + + group("without brackets", () { + group("with unknown separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = false + ..separator = Value_List_Separator.UNDECIDED), + "()", + inspect: true); + }); + + group("with a comma separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = false + ..separator = Value_List_Separator.COMMA), + "()", + inspect: true); + }); + + group("with a space separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = false + ..separator = Value_List_Separator.SPACE), + "()", + inspect: true); + }); + }); + }); + + group("with one element", () { + group("with brackets", () { + group("with unknown separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = true + ..separator = Value_List_Separator.UNDECIDED), + "[true]"); + }); + + test("with a comma separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = true + ..separator = Value_List_Separator.COMMA), + inspect: true), + "[true,]"); + }); + + group("with a space separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = true + ..separator = Value_List_Separator.SPACE), + "[true]"); + }); + }); + + group("without brackets", () { + group("with unknown separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = false + ..separator = Value_List_Separator.UNDECIDED), + "true"); + }); + + test("with a comma separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = false + ..separator = Value_List_Separator.COMMA), + inspect: true), + "(true,)"); + }); + + group("with a space separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = false + ..separator = Value_List_Separator.SPACE), + "true"); + }); + }); + }); + + group("with multiple elements", () { + group("with brackets", () { + test("with a comma separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _null, _false]) + ..hasBrackets = true + ..separator = Value_List_Separator.COMMA), + inspect: true), + "[true, null, false]"); + }); + + test("with a space separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _null, _false]) + ..hasBrackets = true + ..separator = Value_List_Separator.SPACE), + inspect: true), + "[true null false]"); + }); + }); + + group("without brackets", () { + test("with a comma separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _null, _false]) + ..hasBrackets = false + ..separator = Value_List_Separator.COMMA), + inspect: true), + "true, null, false"); + }); + + test("with a space separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _null, _false]) + ..hasBrackets = false + ..separator = Value_List_Separator.SPACE), + inspect: true), + "true null false"); + }); + }); + }); + }); + + group("a map", () { + group("with no elements", () { + _testSerializationAndRoundTrip(Value()..map = Value_Map(), "()", + inspect: true); + }); + + test("with one element", () async { + expect( + await _deprotofy( + Value() + ..map = (Value_Map() + ..entries.add(Value_Map_Entry() + ..key = _true + ..value = _false)), + inspect: true), + "(true: false)"); + }); + + test("with multiple elements", () async { + expect( + await _deprotofy( + Value() + ..map = (Value_Map() + ..entries.addAll([ + Value_Map_Entry() + ..key = _true + ..value = _false, + Value_Map_Entry() + ..key = + (Value()..number = (Value_Number()..value = 1.0)) + ..value = + (Value()..number = (Value_Number()..value = 2.0)), + Value_Map_Entry() + ..key = (Value() + ..string = (Value_String() + ..text = "a" + ..quoted = false)) + ..value = (Value() + ..string = (Value_String() + ..text = "b" + ..quoted = false)) + ])), + inspect: true), + "(true: false, 1: 2, a: b)"); + }); + }); + + test("true", () async { + expect(await _deprotofy(_true), equals("true")); + }); + + test("false", () async { + expect(await _deprotofy(_false), equals("false")); + }); + + test("null", () async { + expect(await _deprotofy(_null, inspect: true), equals("null")); + }); + + group("and rejects", () { + group("a color", () { + test("with red above 255", () async { + await _expectDeprotofyError(_rgb(256, 0, 0, 1.0), + "RgbColor.red must be less than or equal to 255, was 256"); + }); + + test("with green above 255", () async { + await _expectDeprotofyError(_rgb(0, 256, 0, 1.0), + "RgbColor.green must be less than or equal to 255, was 256"); + }); + + test("with blue above 255", () async { + await _expectDeprotofyError(_rgb(0, 0, 256, 1.0), + "RgbColor.blue must be less than or equal to 255, was 256"); + }); + + test("with RGB alpha below 0", () async { + await _expectDeprotofyError(_rgb(0, 0, 0, -0.1), + "RgbColor.alpha must be greater than or equal to 0, was -0.1"); + }); + + test("with RGB alpha above 1", () async { + await _expectDeprotofyError(_rgb(0, 0, 0, 1.1), + "RgbColor.alpha must be less than or equal to 1, was 1.1"); + }); + + test("with saturation below 0", () async { + await _expectDeprotofyError(_hsl(0, -0.1, 0, 1.0), + "HslColor.saturation must be greater than or equal to 0, was -0.1"); + }); + + test("with saturation above 100", () async { + await _expectDeprotofyError( + _hsl(0, 100.1, 0, 1.0), + "HslColor.saturation must be less than or equal to 100, was " + "100.1"); + }); + + test("with lightness below 0", () async { + await _expectDeprotofyError(_hsl(0, 0, -0.1, 1.0), + "HslColor.lightness must be greater than or equal to 0, was -0.1"); + }); + + test("with lightness above 100", () async { + await _expectDeprotofyError( + _hsl(0, 0, 100.1, 1.0), + "HslColor.lightness must be less than or equal to 100, was " + "100.1"); + }); + + test("with HSL alpha below 0", () async { + await _expectDeprotofyError(_hsl(0, 0, 0, -0.1), + "HslColor.alpha must be greater than or equal to 0, was -0.1"); + }); + + test("with HSL alpha above 1", () async { + await _expectDeprotofyError(_hsl(0, 0, 0, 1.1), + "HslColor.alpha must be less than or equal to 1, was 1.1"); + }); + }); + + test("a list with multiple elements and an unknown separator", () async { + await _expectDeprotofyError( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _false]) + ..separator = Value_List_Separator.UNDECIDED), + endsWith("can't have an undecided separator because it has 2 " + "elements")); + }); + }); + }); +} + +/// Evaluates [sassScript] in the compiler, passes it to a custom function, and +/// returns the protocol buffer result. +Future _protofy(String sassScript) async { + _process.inbound.add(compileString(""" +@use 'sass:list'; +@use 'sass:map'; + +\$_: foo(($sassScript)); +""", functions: [r"foo($arg)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + expect(_process.kill(), completes); + return request.arguments.single; +} + +/// Defines two tests: one that asserts that [value] is serialized to the CSS +/// value [expected], and one that asserts that it survives a round trip in the +/// same protocol buffer format. +/// +/// This is necessary for values that can be serialized but also have metadata +/// that's not visible in the serialized form. +void _testSerializationAndRoundTrip(Value value, String expected, + {bool inspect = false}) { + test("is serialized correctly", + () async => expect(await _deprotofy(value, inspect: inspect), expected)); + + test("preserves metadata", () => _assertRoundTrips(value)); +} + +/// Sends [value] to the compiler and returns its string serialization. +/// +/// If [inspect] is true, this returns the value as serialized by the +/// `meta.inspect()` function. +Future _deprotofy(Value value, {bool inspect = false}) async { + _process.inbound.add(compileString( + inspect ? "a {b: inspect(foo())}" : "a {b: foo()}", + functions: [r"foo()"])); + + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, isEmpty); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = value)); + + var success = await getCompileSuccess(await _process.outbound.next); + expect(_process.kill(), completes); + return RegExp(r" b: (.*);").firstMatch(success.css)[1]; +} + +/// Asserts that [value] causes a parameter error with a message matching +/// [message] when deserializing it from a protocol buffer. +Future _expectDeprotofyError(Value value, message) async { + _process.inbound.add(compileString("a {b: foo()}", functions: [r"foo()"])); + + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, isEmpty); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = value)); + + await expectParamsError(_process, -1, message); + await _process.kill(); +} + +/// Sends [value] to the compiler to convert to a native Sass value, then sends +/// it back out to the host as a protocol buffer and asserts the two buffers are +/// identical. +/// +/// Generally [_deprotofy] should be used instead unless there are details about +/// the internal structure of the value that won't show up in its string +/// representation. +Future _assertRoundTrips(Value value) async => + expect(await _roundTrip(value), equals(value)); + +/// Sends [value] to the compiler to convert to a native Sass value, then sends +/// it back out to the host as a protocol buffer and returns the result. +Future _roundTrip(Value value) async { + _process.inbound.add(compileString(""" +\$_: outbound(inbound()); +""", functions: ["inbound()", r"outbound($arg)"])); + + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, isEmpty); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = value)); + + request = getFunctionCallRequest(await _process.outbound.next); + expect(_process.kill(), completes); + return request.arguments.single; +} + +/// Returns a [Value] that's an RGB color with the given fields. +Value _rgb(int red, int green, int blue, double alpha) => Value() + ..rgbColor = (Value_RgbColor() + ..red = red + ..green = green + ..blue = blue + ..alpha = alpha); + +/// Returns a [Value] that's an HSL color with the given fields. +Value _hsl(num hue, num saturation, num lightness, double alpha) => Value() + ..hslColor = (Value_HslColor() + ..hue = hue * 1.0 + ..saturation = saturation * 1.0 + ..lightness = lightness * 1.0 + ..alpha = alpha); diff --git a/test/utils.dart b/test/utils.dart index c5adc9304..f3137135f 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -95,7 +95,8 @@ InboundMessage compileString(String css, InboundMessage_CompileRequest_OutputStyle style, String url, bool sourceMap, - Iterable importers}) { + Iterable importers, + Iterable functions}) { var input = InboundMessage_CompileRequest_StringInput()..source = css; if (syntax != null) input.syntax = syntax; if (url != null) input.url = url; @@ -105,6 +106,7 @@ InboundMessage compileString(String css, if (importers != null) request.importers.addAll(importers); if (style != null) request.style = style; if (sourceMap != null) request.sourceMap = sourceMap; + if (functions != null) request.globalFunctions.addAll(functions); return InboundMessage()..compileRequest = request; } @@ -114,7 +116,13 @@ InboundMessage compileString(String css, Future expectParseError(EmbeddedProcess process, message) async { await expectLater(process.outbound, emits(isProtocolError(-1, ProtocolError_ErrorType.PARSE, message))); - await expectLater(process.stderr, emits("Host caused parse error: $message")); + + var stderrPrefix = "Host caused parse error: "; + await expectLater( + process.stderr, + message is String + ? emitsInOrder("$stderrPrefix$message".split("\n")) + : emits(startsWith(stderrPrefix))); } /// Asserts that [process] emits a [ProtocolError] params error with the given @@ -122,10 +130,14 @@ Future expectParseError(EmbeddedProcess process, message) async { Future expectParamsError(EmbeddedProcess process, int id, message) async { await expectLater(process.outbound, emits(isProtocolError(id, ProtocolError_ErrorType.PARAMS, message))); + + var stderrPrefix = "Host caused params error" + "${id == -1 ? '' : " with request $id"}: "; await expectLater( process.stderr, - emits("Host caused params error${id == -1 ? '' : " with request $id"}: " - "$message")); + message is String + ? emitsInOrder("$stderrPrefix$message".split("\n")) + : emits(startsWith(stderrPrefix))); } /// Asserts that an [OutboundMessage] is a [ProtocolError] with the given [id], @@ -162,6 +174,16 @@ OutboundMessage_ImportRequest getImportRequest(value) { return message.importRequest; } +/// Asserts that [message] is an [OutboundMessage] with a +/// `FunctionCallRequest` and returns it. +OutboundMessage_FunctionCallRequest getFunctionCallRequest(value) { + expect(value, isA()); + var message = value as OutboundMessage; + expect(message.hasFunctionCallRequest(), isTrue, + reason: "Expected $message to have a FunctionCallRequest"); + return message.functionCallRequest; +} + /// Asserts that [message] is an [OutboundMessage] with a /// `CompileResponse.Failure` and returns it. OutboundMessage_CompileResponse_CompileFailure getCompileFailure(value) { @@ -171,6 +193,15 @@ OutboundMessage_CompileResponse_CompileFailure getCompileFailure(value) { return response.failure; } +/// Asserts that [message] is an [OutboundMessage] with a +/// `CompileResponse.Success` and returns it. +OutboundMessage_CompileResponse_CompileSuccess getCompileSuccess(value) { + var response = getCompileResponse(value); + expect(response.hasSuccess(), isTrue, + reason: "Expected $response to be a success"); + return response.success; +} + /// Asserts that [message] is an [OutboundMessage] with a `CompileResponse` and /// returns it. OutboundMessage_CompileResponse getCompileResponse(value) { @@ -200,15 +231,12 @@ OutboundMessage_LogEvent getLogEvent(value) { /// If [sourceMap] is a function, `response.success.sourceMap` is passed to it. /// Otherwise, it's treated as a matcher for `response.success.sourceMap`. Matcher isSuccess(css, {sourceMap}) => predicate((value) { - var response = getCompileResponse(value); - expect(response.hasSuccess(), isTrue, - reason: "Expected $response to be successful"); - expect(response.success.css, - css is String ? equalsIgnoringWhitespace(css) : css); + var success = getCompileSuccess(value); + expect(success.css, css is String ? equalsIgnoringWhitespace(css) : css); if (sourceMap is void Function(String)) { - sourceMap(response.success.sourceMap); + sourceMap(success.sourceMap); } else if (sourceMap != null) { - expect(response.success.sourceMap, sourceMap); + expect(success.sourceMap, sourceMap); } return true; }); From 03805ce1ce8572dca67d815e7ab046e5a9c5db4b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 11 Nov 2019 13:36:13 -0800 Subject: [PATCH 015/162] Add support for first-class function value types (#10) --- bin/dart_sass_embedded.dart | 74 +++---------------------- lib/src/function_registry.dart | 33 ++++++++++++ lib/src/host_callable.dart | 83 ++++++++++++++++++++++++++++ lib/src/value.dart | 50 +++++++++++++---- test/function_test.dart | 99 ++++++++++++++++++++++++++++++++++ 5 files changed, 261 insertions(+), 78 deletions(-) create mode 100644 lib/src/function_registry.dart create mode 100644 lib/src/host_callable.dart diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 7065893d3..c64466b5e 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -3,7 +3,6 @@ // https://opensource.org/licenses/MIT. import 'dart:io'; -import 'dart:cli'; import 'dart:convert'; import 'package:sass/sass.dart' as sass; @@ -12,11 +11,12 @@ import 'package:stream_channel/stream_channel.dart'; import 'package:sass_embedded/src/dispatcher.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/function_registry.dart'; +import 'package:sass_embedded/src/host_callable.dart'; import 'package:sass_embedded/src/importer.dart'; import 'package:sass_embedded/src/logger.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; import 'package:sass_embedded/src/utils.dart'; -import 'package:sass_embedded/src/value.dart'; void main(List args) { if (args.isNotEmpty) { @@ -33,11 +33,7 @@ void main(List args) { .transform(lengthDelimited)); dispatcher.listen((request) async { - // Wait a single microtask tick so that we're running in a separate - // microtask from the initial request dispatch. Otherwise, [waitFor] will - // deadlock the event loop fiber that would otherwise be checking stdin for - // new input. - await Future.value(); + var functions = FunctionRegistry(); var style = request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED @@ -68,8 +64,8 @@ void main(List args) { throw "Unknown Importer.importer $importer."; }); - var functions = request.globalFunctions - .map((signature) => _hostCallable(dispatcher, request.id, signature)); + var globalFunctions = request.globalFunctions.map((signature) => + hostCallable(dispatcher, functions, request.id, signature)); switch (request.whichInput()) { case InboundMessage_CompileRequest_Input.string: @@ -77,7 +73,7 @@ void main(List args) { result = sass.compileString(input.source, logger: logger, importers: importers, - functions: functions, + functions: globalFunctions, syntax: syntaxToSyntax(input.syntax), style: style, url: input.url.isEmpty ? null : input.url, @@ -89,7 +85,7 @@ void main(List args) { result = sass.compile(request.path, logger: logger, importers: importers, - functions: functions, + functions: globalFunctions, style: style, sourceMap: sourceMapCallback); } on FileSystemException catch (error) { @@ -120,59 +116,3 @@ void main(List args) { } }); } - -/// Returns a Sass callable that invokes a function defined on the host with the -/// given [signature]. -/// -/// Throws a [ProtocolError] if [signature] is invalid. -sass.Callable _hostCallable( - Dispatcher dispatcher, int compilationId, String signature) { - var openParen = signature.indexOf('('); - if (openParen == -1) { - throw paramsError( - 'CompileRequest.global_functions: "$signature" is missing "("'); - } - - if (!signature.endsWith(")")) { - throw paramsError( - 'CompileRequest.global_functions: "$signature" doesn\'t end with ' - '")"'); - } - - var name = signature.substring(0, openParen); - try { - return sass.Callable( - name, signature.substring(openParen + 1, signature.length - 1), - (arguments) { - var request = OutboundMessage_FunctionCallRequest() - ..compilationId = compilationId - ..name = name - ..arguments.addAll(arguments.map(protofyValue)); - - var response = waitFor(dispatcher.sendFunctionCallRequest(request)); - try { - switch (response.whichResult()) { - case InboundMessage_FunctionCallResponse_Result.success: - return deprotofyValue(response.success); - - case InboundMessage_FunctionCallResponse_Result.error: - throw response.error; - - case InboundMessage_FunctionCallResponse_Result.notSet: - throw mandatoryError('FunctionCallResponse.result'); - } - - // dart-lang/sdk#38790 - throw "Unknown FunctionCallResponse.result $response."; - } on ProtocolError catch (error) { - error.id = -1; - stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " - "${error.message}"); - dispatcher.sendError(error); - throw error.message; - } - }); - } on sass.SassException catch (error) { - throw paramsError('CompileRequest.global_functions: $error'); - } -} diff --git a/lib/src/function_registry.dart b/lib/src/function_registry.dart new file mode 100644 index 000000000..79b0cacce --- /dev/null +++ b/lib/src/function_registry.dart @@ -0,0 +1,33 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:sass/sass.dart' as sass; +import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +/// A registry of [SassFunction]s indexed by ID so that the host can invoke +/// them. +class FunctionRegistry { + /// First-class functions that have been sent to the host. + /// + /// The functions are located at indexes in the list matching their IDs. + final _functionsById = []; + + /// A reverse map from functions to their indexes in [_functionsById]. + final _idsByFunction = {}; + + /// Converts [function] to a protocol buffer to send to the host. + Value_CompilerFunction protofy(sass.SassFunction function) { + var id = _idsByFunction.putIfAbsent(function, () { + _functionsById.add(function); + return _functionsById.length - 1; + }); + + return Value_CompilerFunction()..id = id; + } + + /// Returns the compiler-side function associated with [id]. + /// + /// If no such function exists, returns `null`. + sass.SassFunction operator [](int id) => _functionsById[id]; +} diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart new file mode 100644 index 000000000..87cd2ddc7 --- /dev/null +++ b/lib/src/host_callable.dart @@ -0,0 +1,83 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:cli'; +import 'dart:io'; + +import 'package:sass/sass.dart' as sass; + +import 'dispatcher.dart'; +import 'embedded_sass.pb.dart'; +import 'function_registry.dart'; +import 'utils.dart'; +import 'value.dart'; + +/// Returns a Sass callable that invokes a function defined on the host with the +/// given [signature]. +/// +/// If [id] is passed, the function will be called by ID (which is necessary for +/// anonymous functions defined on the host). Otherwise, it will be called using +/// the name defined in the [signature]. +/// +/// Throws a [ProtocolError] if [signature] is invalid. +sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, + int compilationId, String signature, + {int id}) { + var openParen = signature.indexOf('('); + if (openParen == -1) { + throw paramsError( + 'CompileRequest.global_functions: "$signature" is missing "("'); + } + + if (!signature.endsWith(")")) { + throw paramsError( + 'CompileRequest.global_functions: "$signature" doesn\'t end with ' + '")"'); + } + + var name = signature.substring(0, openParen); + try { + return sass.Callable( + name, signature.substring(openParen + 1, signature.length - 1), + (arguments) { + var request = OutboundMessage_FunctionCallRequest() + ..compilationId = compilationId + ..arguments.addAll([ + for (var argument in arguments) protofyValue(functions, argument) + ]); + + if (id != null) { + request.functionId = id; + } else { + request.name = name; + } + + var response = waitFor(dispatcher.sendFunctionCallRequest(request)); + try { + switch (response.whichResult()) { + case InboundMessage_FunctionCallResponse_Result.success: + return deprotofyValue( + dispatcher, functions, compilationId, response.success); + + case InboundMessage_FunctionCallResponse_Result.error: + throw response.error; + + case InboundMessage_FunctionCallResponse_Result.notSet: + throw mandatoryError('FunctionCallResponse.result'); + } + + // dart-lang/sdk#38790 + throw "Unknown FunctionCallResponse.result $response."; + } on ProtocolError catch (error) { + error.id = -1; + stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " + "${error.message}"); + dispatcher.sendError(error); + throw error.message; + } + }); + } on sass.SassException catch (error) { + throw paramsError('CompileRequest.global_functions: $error'); + } +} diff --git a/lib/src/value.dart b/lib/src/value.dart index 218dcf12c..065a2fcb8 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -5,10 +5,16 @@ import 'package:sass/sass.dart' as sass; import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'dispatcher.dart'; +import 'function_registry.dart'; +import 'host_callable.dart'; import 'utils.dart'; /// Converts [value] to its protocol buffer representation. -Value protofyValue(sass.Value value) { +/// +/// The [functions] tracks the IDs of first-class functions so that the host can +/// pass them back to the compiler. +Value protofyValue(FunctionRegistry functions, sass.Value value) { var result = Value(); if (value is sass.SassString) { result.string = Value_String() @@ -31,17 +37,20 @@ Value protofyValue(sass.Value value) { } else if (value is sass.SassList) { var list = Value_List() ..separator = _protofySeparator(value.separator) - ..hasBrackets = value.hasBrackets; - list.contents.addAll(value.asList.map(protofyValue)); + ..hasBrackets = value.hasBrackets + ..contents.addAll( + [for (var element in value.asList) protofyValue(functions, element)]); result.list = list; } else if (value is sass.SassMap) { var map = Value_Map(); value.contents.forEach((key, value) { map.entries.add(Value_Map_Entry() - ..key = protofyValue(key) - ..value = protofyValue(value)); + ..key = protofyValue(functions, key) + ..value = protofyValue(functions, value)); }); result.map = map; + } else if (value is sass.SassFunction) { + result.compilerFunction = functions.protofy(value); } else if (value == sass.sassTrue) { result.singleton = Value_Singleton.TRUE; } else if (value == sass.sassFalse) { @@ -69,7 +78,16 @@ Value_List_Separator _protofySeparator(sass.ListSeparator separator) { } /// Converts [value] to its Sass representation. -sass.Value deprotofyValue(Value value) { +/// +/// The [functions] tracks the IDs of first-class functions so that they can be +/// deserialized to their original references. +sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, + int compilationId, Value value) { + // Curry recursive calls to this function so we don't have to keep repeating + // ourselves. + var deprotofy = (Value value) => + deprotofyValue(dispatcher, functions, compilationId, value); + switch (value.whichValue()) { case Value_Value.string: return value.string.text.isEmpty @@ -110,22 +128,32 @@ sass.Value deprotofyValue(Value value) { "$length elements"); } - return sass.SassList(value.list.contents.map(deprotofyValue), separator, - brackets: value.list.hasBrackets); + return sass.SassList([ + for (var element in value.list.contents) deprotofy(element) + ], separator, brackets: value.list.hasBrackets); case Value_Value.map: return value.map.entries.isEmpty ? const sass.SassMap.empty() : sass.SassMap({ for (var entry in value.map.entries) - deprotofyValue(entry.key): deprotofyValue(entry.value) + deprotofy(entry.key): deprotofy(entry.value) }); case Value_Value.compilerFunction: - throw "CompilerFunctions are not yet supported."; + var id = value.compilerFunction.id; + var function = functions[id]; + if (function == null) { + throw paramsError( + "CompilerFunction.id $id doesn't match any known functions"); + } + + return function; case Value_Value.hostFunction: - throw "HostFunctions not yet supported."; + return sass.SassFunction(hostCallable( + dispatcher, functions, compilationId, value.hostFunction.signature, + id: value.hostFunction.id)); case Value_Value.singleton: switch (value.singleton) { diff --git a/test/function_test.dart b/test/function_test.dart index a70b41f90..848bb505b 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -172,6 +172,105 @@ void main() { await _process.kill(); }); + group("calls a first-class function", () { + test("defined in the compiler and passed to and from the host", () async { + _process.inbound.add(compileString(r""" + @use "sass:math"; + @use "sass:meta"; + + a {b: call(foo(meta.get-function("abs", $module: "math")), -1)} + """, functions: [r"foo($arg)"])); + + var request = getFunctionCallRequest(await _process.outbound.next); + var value = request.arguments.single; + expect(value.hasCompilerFunction(), isTrue); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = value)); + + await expectLater( + _process.outbound, emits(isSuccess(equals("a {\n b: 1;\n}")))); + await _process.kill(); + }); + + test("defined in the host", () async { + var compilationId = 1234; + _process.inbound.add(compileString("a {b: call(foo(), true)}", + id: compilationId, functions: [r"foo()"])); + + var hostFunctionId = 5678; + var request = getFunctionCallRequest(await _process.outbound.next); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = (Value() + ..hostFunction = (Value_HostFunction() + ..id = hostFunctionId + ..signature = r"bar($arg)")))); + + request = getFunctionCallRequest(await _process.outbound.next); + expect(request.compilationId, equals(compilationId)); + expect(request.functionId, equals(hostFunctionId)); + expect(request.arguments, equals([_true])); + + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = _false)); + + await expectLater( + _process.outbound, emits(isSuccess(equals("a {\n b: false;\n}")))); + await _process.kill(); + }); + + test("defined in the host and passed to and from the host", () async { + var compilationId = 1234; + _process.inbound.add(compileString( + r""" + $function: get-host-function(); + $function: round-trip($function); + a {b: call($function, true)} + """, + id: compilationId, + functions: [r"get-host-function()", r"round-trip($function)"])); + + var hostFunctionId = 5678; + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.name, equals("get-host-function")); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = (Value() + ..hostFunction = (Value_HostFunction() + ..id = hostFunctionId + ..signature = r"bar($arg)")))); + + request = getFunctionCallRequest(await _process.outbound.next); + expect(request.name, equals("round-trip")); + var value = request.arguments.single; + expect(value.hasCompilerFunction(), isTrue); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = value)); + + request = getFunctionCallRequest(await _process.outbound.next); + expect(request.compilationId, equals(compilationId)); + expect(request.functionId, equals(hostFunctionId)); + expect(request.arguments, equals([_true])); + + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = _false)); + + await expectLater( + _process.outbound, emits(isSuccess(equals("a {\n b: false;\n}")))); + await _process.kill(); + }); + }); + group("serializes to protocol buffers", () { group("a string that's", () { group("quoted", () { From 0cddc095b9fd0045be08e18c9a8ee764edddc196 Mon Sep 17 00:00:00 2001 From: Awjin Ahn Date: Mon, 23 Dec 2019 15:43:16 -0800 Subject: [PATCH 016/162] Support latest protocol updates (#11) * Remove support for InboundMessage.FunctionCallRequest Context: https://github.com/sass/embedded-protocol/issues/28 * Remove support for CanonicalizeResponse.file Context: https://github.com/sass/embedded-protocol/issues/25 * Stub CompileRequest.Importer.fileImporterId support --- bin/dart_sass_embedded.dart | 3 +++ lib/src/dispatcher.dart | 5 ----- lib/src/importer.dart | 3 --- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index c64466b5e..e334ff0cd 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -56,6 +56,9 @@ void main(List args) { case InboundMessage_CompileRequest_Importer_Importer.importerId: return Importer(dispatcher, request.id, importer.importerId); + case InboundMessage_CompileRequest_Importer_Importer.fileImporterId: + throw "CompileRequest.Importer.fileImporterId is not yet supported"; + case InboundMessage_CompileRequest_Importer_Importer.notSet: throw mandatoryError("Importer.importer"); } diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 1279cbcbb..dd192a15d 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -199,8 +199,6 @@ class Dispatcher { switch (message.whichMessage()) { case InboundMessage_Message.compileRequest: return message.compileRequest.id; - case InboundMessage_Message.functionCallRequest: - return message.functionCallRequest.id; default: return null; } @@ -223,9 +221,6 @@ class Dispatcher { case OutboundMessage_Message.functionCallRequest: message.functionCallRequest.id = id; break; - case OutboundMessage_Message.functionCallResponse: - message.functionCallResponse.id = id; - break; default: return null; } diff --git a/lib/src/importer.dart b/lib/src/importer.dart index 83263eb4e..4b6d9d4ec 100644 --- a/lib/src/importer.dart +++ b/lib/src/importer.dart @@ -36,9 +36,6 @@ class Importer extends sass.Importer { case InboundMessage_CanonicalizeResponse_Result.url: return _parseAbsoluteUrl("CanonicalizeResponse.url", response.url); - case InboundMessage_CanonicalizeResponse_Result.file: - throw "CanonicalizeResponse.file is not yet supported"; - case InboundMessage_CanonicalizeResponse_Result.error: throw response.error; From c1f1226db0526c76e56b421b8fbae311d2fb169f Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 17 Jul 2020 14:44:43 -0700 Subject: [PATCH 017/162] Release a beta version --- pubspec.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 43e05d6c7..06d91aa24 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.0.0-beta.1 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded @@ -27,6 +27,3 @@ dev_dependencies: path: ^1.6.0 test: ^1.0.0 test_descriptor: ^1.0.0 - -dependency_overrides: - cli_pkg: {git: git://github.com/google/dart_cli_pkg} From 8b1eedab421677724fcbd7cc6cc204420d664229 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 20 Jul 2020 13:34:14 -0700 Subject: [PATCH 018/162] Depend on cli_pkg-beta.8 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 06d91aa24..d8d8f4d35 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: stream_channel: ">=1.6.0 <3.0.0" dev_dependencies: - cli_pkg: ^1.0.0 + cli_pkg: ^1.0.0-beta.8 grinder: ^0.8.0 protoc_plugin: ^19.0.0 path: ^1.6.0 From 5b99160a15fff1fff6fa79d315401f109e0945e3 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 20 Jul 2020 19:19:44 -0700 Subject: [PATCH 019/162] Fix an outdated test --- test/function_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/function_test.dart b/test/function_test.dart index 848bb505b..290685f1f 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -58,10 +58,10 @@ void main() { 0, 'CompileRequest.global_functions: Error: Expected identifier.\n' ' ╷\n' - '1 │ (\$)\n' - ' │ ^\n' + '1 │ @function foo(\$) {\n' + ' │ ^\n' ' ╵\n' - ' - 1:3 root stylesheet'); + ' - 1:16 root stylesheet'); await _process.kill(); }); }); From 5c7a642f4733d6695110eb1a2c6cc77e56089c9f Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 21 Jul 2020 13:22:20 -0700 Subject: [PATCH 020/162] Stop testing on Dart dev to work around dart-lang/pub#2545 --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62fa423b2..f6f71f0e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,9 @@ jobs: # Testing - dart: stable dart_task: test - - dart: dev - dart_task: test + # TODO(nweiz): Enable this when dart-lang/pub#2545 is fixed. + # - dart: dev + # dart_task: test - dart: stable os: windows dart_task: test From b046b97c9e844a5102b5d408156cdbc4d85292be Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 21 Jul 2020 16:21:24 -0700 Subject: [PATCH 021/162] Use cli_pkg's testing infrastructure --- .travis.yml | 8 +--- test/embedded_process.dart | 12 ++---- test/function_test.dart | 2 - test/importer_test.dart | 2 - test/protocol_test.dart | 2 - test/utils.dart | 78 -------------------------------------- 6 files changed, 4 insertions(+), 100 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6f71f0e5..5c1e58c45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,13 +26,7 @@ before_script: - pub run grinder protobuf # Format the generated code or else the formatter task will get upset. - dartfmt -w --fix lib/src/embedded_sass.pb* - -# TODO(nweiz): always compile native when we're running on Dart 2.7. -- if [[ "$TRAVIS_OS_NAME" = windows ]]; then - pub run grinder pkg-compile-snapshot; - else - pub run grinder pkg-compile-native; - fi +- pub run grinder pkg-standalone-dev jobs: include: diff --git a/test/embedded_process.dart b/test/embedded_process.dart index bb3a8d294..9919992e7 100644 --- a/test/embedded_process.dart +++ b/test/embedded_process.dart @@ -7,15 +7,12 @@ import 'dart:convert'; import 'dart:io'; import 'package:async/async.dart'; -import 'package:grinder/grinder.dart'; -import 'package:path/path.dart' as p; +import 'package:cli_pkg/testing.dart' as pkg; import 'package:test/test.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; -import 'utils.dart'; - /// A wrapper for [Process] that provides a convenient API for testing the /// embedded Sass process. /// @@ -81,12 +78,9 @@ class EmbeddedProcess { bool includeParentEnvironment = true, bool runInShell = false, bool forwardOutput = false}) async { - var scriptOrSnapshot = executablePath; var process = await Process.start( - executablePath.endsWith(".native") - ? p.join(sdkDir.path, "bin", "dartaotruntime") - : Platform.executable, - [scriptOrSnapshot], + pkg.executableRunner("dart-sass-embedded"), + pkg.executableArgs("dart-sass-embedded"), workingDirectory: workingDirectory, environment: environment, includeParentEnvironment: includeParentEnvironment, diff --git a/test/function_test.dart b/test/function_test.dart index 290685f1f..3c12563e8 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -16,8 +16,6 @@ final _null = Value()..singleton = Value_Singleton.NULL; EmbeddedProcess _process; void main() { - ensureExecutableUpToDate(); - setUp(() async { _process = await EmbeddedProcess.start(); }); diff --git a/test/importer_test.dart b/test/importer_test.dart index c69aac7e7..1bb8677f0 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -12,8 +12,6 @@ import 'embedded_process.dart'; import 'utils.dart'; void main() { - ensureExecutableUpToDate(); - EmbeddedProcess process; setUp(() async { process = await EmbeddedProcess.start(); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index b72d79a7f..697e8a589 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -13,8 +13,6 @@ import 'embedded_process.dart'; import 'utils.dart'; void main() { - ensureExecutableUpToDate(); - EmbeddedProcess process; setUp(() async { process = await EmbeddedProcess.start(); diff --git a/test/utils.dart b/test/utils.dart index f3137135f..e5b7a8fa9 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -2,8 +2,6 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'dart:io'; - import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -11,82 +9,6 @@ import 'package:sass_embedded/src/embedded_sass.pb.dart'; import 'embedded_process.dart'; -/// Whether [ensureExecutableUpToDate] has been called. -var _ensuredExecutableUpToDate = false; - -/// Returns the path to the executable to execute. -/// -/// This may be a raw Dart executable, a script snapshot that ends in -/// `.snapshot`, or a native-code snapshot that ends in `.native`. -final String executablePath = () { - expect(_ensuredExecutableUpToDate, isTrue, - reason: - "ensureExecutableUpToDate() must be called at top of the test file."); - - var nativeSnapshot = "build/dart_sass_embedded.dart.native"; - if (File(nativeSnapshot).existsSync()) return nativeSnapshot; - - var bytecodeSnapshot = "build/dart_sass_embedded.dart.snapshot"; - if (File(bytecodeSnapshot).existsSync()) return bytecodeSnapshot; - - return "bin/dart_sass_embedded.dart"; -}(); - -/// Creates a [setUpAll] that verifies that the compiled form of the migrator -/// executable is up-to-date, if necessary. -/// -/// This should always be called before [runMigrator]. -void ensureExecutableUpToDate() { - setUpAll(() { - _ensuredExecutableUpToDate = true; - - if (!executablePath.endsWith(".dart")) { - _ensureUpToDate( - executablePath, - "pub run grinder protobuf " - "pkg-compile-${Platform.isWindows ? 'snapshot' : 'native'}"); - } - }); -} - -/// Ensures that [path] (usually a compilation artifact) has been modified more -/// recently than all this package's source files. -/// -/// If [path] isn't up-to-date, this throws an error encouraging the user to run -/// [commandToRun]. -void _ensureUpToDate(String path, String commandToRun) { - // Ensure path is relative so the error messages are more readable. - path = p.relative(path); - if (!File(path).existsSync()) { - throw "$path does not exist. Run $commandToRun."; - } - - var lastModified = File(path).lastModifiedSync(); - var entriesToCheck = Directory("lib").listSync(recursive: true).toList(); - - // If we have a dependency override, "pub run" will touch the lockfile to mark - // it as newer than the pubspec, which makes it unsuitable to use for - // freshness checking. - if (File("pubspec.yaml") - .readAsStringSync() - .contains("dependency_overrides")) { - entriesToCheck.add(File("pubspec.yaml")); - } else { - entriesToCheck.add(File("pubspec.lock")); - } - - for (var entry in entriesToCheck) { - if (entry is File) { - var entryLastModified = entry.lastModifiedSync(); - if (lastModified.isBefore(entryLastModified)) { - throw "${entry.path} was modified after ${p.prettyUri(p.toUri(path))} " - "was generated.\n" - "Run $commandToRun."; - } - } - } -} - /// Returns a [InboundMessage] that compiles the given plain CSS /// string. InboundMessage compileString(String css, From 43b9d8a0f9154ba2ccd4f4a5c4d07e047ec3665a Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 21 Jul 2020 16:27:32 -0700 Subject: [PATCH 022/162] Use cli_pkg to deploy binaries to GitHub releases --- .travis.yml | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5c1e58c45..3e29764b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,8 @@ before_script: jobs: include: - # Testing + ## Testing + - dart: stable dart_task: test # TODO(nweiz): Enable this when dart-lang/pub#2545 is fixed. @@ -47,3 +48,61 @@ jobs: # Static checks - dart_task: {dartanalyzer: --fatal-warnings ./} - dart_task: dartfmt + + ## Deploying + + # Deploy Linux releases to GitHub. Mac OS and Windows releases are deployed in + # a later stage so that we can build native snapshots on bots with the same + # operating system. + - stage: deploy 1 + name: "GitHub: Linux" + if: &deploy-if + (type IN (push, api)) AND (repo = sass/dart-sass-embedded) AND tag =~ ^\d+\.\d+\.\d+([+-].*)?$ + env: &github-env + - GITHUB_USER=sassbot + # GITHUB_TOKEN="..." + # + # Note that this overrides the read-only auth token that's set for all + # builds. + - secure: "l3q6m5Khk+E/UrzZzk2htn9YC6TuUJ3hDR6Ug28zeIf7+bV3/BbjgsOMP556H9p9q+9E3N4mKMeTApdaU5y1TjJZYLaYJETqHiYZDXJ0f1/2IzPOh+5OIqVF3pFhdc6GvmDG/d6b4bBCh9njvKIvWS51ej9VuizRfQI3BMRuApgmjBVkV2MM13HEhQ3dbe5856Gf00LvP6UF9o+bnIRo/udhmpYGQsEHLdrq2JgawiRylyLzW+hIfhS7wJm/JS32wV8sLJo70NCD5W74ZPmDv0zOKkX2VFbFv7y2qBmgUX8f8d8KqNVOzYEu8UTd3kIQASdOenZfg76S74EjW7o7QbLfJB8h0/BVMEhA/yaVuye2vu76ihGELAunSNvx7zlU16Z4TT7z+YSwCni7jvzWJajTiLoQXygHxJLEEjbBN/qF6gyre07g+zbBTXPIBvwm8lMqtyekbbq7sosL7/ctU4sX7qbuYaxhRvMhaZtkzS2clZajp2SFagTZvitbMNT5HE9YJTrNMgoEP7aiELAfmc02xUzNfaZ15x9G3n3RisTmkrwdLD6We2L0aPa+2LiyiBNbxH3QqyfcIMyXbDnymuphkYXq+fL3W7x0G9ZmtjWBB9tUcNe2VlD5hBhPShYbDwZKbKn9EgXHOnmZ/04ARyJbnQGUYKlZR5U2HGon7HU=" + script: skip # Don't run tests + deploy: + provider: script + script: pub run grinder pkg-github-release pkg-github-linux + skip_cleanup: true # Don't clean up the Dart SDK. + + # This causes the deploy to only be build when a tag is pushed. This + # is because the `tag` attribute in `if:` statements has a different + # understanding of the "current tag" than this, which uses the + # `TRAVIS_TAG` environment variable. `if:` statements check whether a + # tag exists that refers to the current commit, whereas `TRAVIS_TAG` + # checks whether the current build was caused by a tag. + # + # We check `if:` because it avoids unnecessary build steps, and + # `on: {tags: true}` ensures that we only deploy on the build caused + # by pushing a tag, not the build caused by pushing master. + on: {tags: true} + + # Deploy to Bazel. This is in a separate deploy stage because it needs to + # install the npm package. + - stage: deploy 2 + name: "GitHub: Mac OS" + if: *deploy-if + env: *github-env + script: skip + os: osx + deploy: + provider: script + script: pub run grinder pkg-github-macos + skip_cleanup: true + on: {tags: true} + + - name: "GitHub: Windows" + if: *deploy-if + env: *github-env + script: skip + deploy: + provider: script + script: pub run grinder pkg-github-windows + skip_cleanup: true + on: {tags: true} From 25a8184a15b01f17df9a5ced4c76f825ce600ee1 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 21 Jul 2020 16:27:57 -0700 Subject: [PATCH 023/162] Bump the version to 1.0.0-beta.2 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d8d8f4d35..67d2e9be8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.1 +version: 1.0.0-beta.2 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 2d2ad922db12e31243ee9c63f86323197207e825 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 22 Jul 2020 16:16:56 -0700 Subject: [PATCH 024/162] Regenerate the GitHub token (#14) The previous token didn't seem to be recognized. See https://travis-ci.com/github/sass/dart-sass-embedded/jobs/364028782. It's unclear why it didn'twork, but I'm hoping regenerating fixes it. --- .travis.yml | 5 +---- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3e29764b4..8803741cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,10 +61,7 @@ jobs: env: &github-env - GITHUB_USER=sassbot # GITHUB_TOKEN="..." - # - # Note that this overrides the read-only auth token that's set for all - # builds. - - secure: "l3q6m5Khk+E/UrzZzk2htn9YC6TuUJ3hDR6Ug28zeIf7+bV3/BbjgsOMP556H9p9q+9E3N4mKMeTApdaU5y1TjJZYLaYJETqHiYZDXJ0f1/2IzPOh+5OIqVF3pFhdc6GvmDG/d6b4bBCh9njvKIvWS51ej9VuizRfQI3BMRuApgmjBVkV2MM13HEhQ3dbe5856Gf00LvP6UF9o+bnIRo/udhmpYGQsEHLdrq2JgawiRylyLzW+hIfhS7wJm/JS32wV8sLJo70NCD5W74ZPmDv0zOKkX2VFbFv7y2qBmgUX8f8d8KqNVOzYEu8UTd3kIQASdOenZfg76S74EjW7o7QbLfJB8h0/BVMEhA/yaVuye2vu76ihGELAunSNvx7zlU16Z4TT7z+YSwCni7jvzWJajTiLoQXygHxJLEEjbBN/qF6gyre07g+zbBTXPIBvwm8lMqtyekbbq7sosL7/ctU4sX7qbuYaxhRvMhaZtkzS2clZajp2SFagTZvitbMNT5HE9YJTrNMgoEP7aiELAfmc02xUzNfaZ15x9G3n3RisTmkrwdLD6We2L0aPa+2LiyiBNbxH3QqyfcIMyXbDnymuphkYXq+fL3W7x0G9ZmtjWBB9tUcNe2VlD5hBhPShYbDwZKbKn9EgXHOnmZ/04ARyJbnQGUYKlZR5U2HGon7HU=" + - secure: "KNW6oMV6PNJx4NKeMfmp1uPZkf7OY5NIP6UQVDXPwt2eInWpbIqZGCpxWnKs72FkfLIDEyM3CV9ltgfPqQUuWMZyU0z2052tMFy4F/00sGqPAw0uUriffrMTrIFgDlo8rqcC7fQfkL0ZPaGa+48O61vW9FdwUio5agBEcdWzqFBmJceyrK/sOf9VcLP6cDz+y+TPxl5X+yCgqY+vARju9zWcf7uGv2BBfUBbg48wUjcCRSGxdy6FCcKn11LLLofBmomfbxXDZGXi8GYKPFLUD/sigBQM0lCqqM9kyqWCW4//y0RblWMLJ17qFa/acXuZHxC3ZBP235gk594mHw8+NcUk51xfCHIYWYtBKLmbQtddBH/yicyA3lJJ3zDxdH6cV3rn610fYZcMGnk+FO9DrwLrZSdeheOaB09i0JX5OhaJBSp84KOHm+IHWGUB27eGGD36vS08Ms1svbiIB+hiRo4HasgHJQlyN7adlNCOYQFbzEn+a/Qxol5k+TMuOaRAX0sSl3WSkrGUO2CZtaBEjmC7PzSdJN+mKu5l6TVd8dVb/cVHI/OgKFf2L02Fhh5arR773W6vXxX56SWv67SYB4akhEeji8HaY5YWG0ie4PD3GJKi4WaE31rcmJg0aZZSDw1G1Gxci6VgK21CsSBU+wOYzyztzEXyM+iG35sWffA=" script: skip # Don't run tests deploy: provider: script diff --git a/pubspec.yaml b/pubspec.yaml index 67d2e9be8..7137ab1ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.2 +version: 1.0.0-beta.3 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From d37ef98a76021aa7ce9a296f86f246d67d0dfed7 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 22 Jul 2020 16:39:34 -0700 Subject: [PATCH 025/162] Regenerate the GitHub token again (#15) I realized the problem: this repo uses travis-ci.com, not travis-ci.org, but the Travis CLI defaults to encrypting using .com credentials. This time I regenerated the token using --pro, which should work. --- .travis.yml | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8803741cd..fe96a11fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,7 @@ jobs: env: &github-env - GITHUB_USER=sassbot # GITHUB_TOKEN="..." - - secure: "KNW6oMV6PNJx4NKeMfmp1uPZkf7OY5NIP6UQVDXPwt2eInWpbIqZGCpxWnKs72FkfLIDEyM3CV9ltgfPqQUuWMZyU0z2052tMFy4F/00sGqPAw0uUriffrMTrIFgDlo8rqcC7fQfkL0ZPaGa+48O61vW9FdwUio5agBEcdWzqFBmJceyrK/sOf9VcLP6cDz+y+TPxl5X+yCgqY+vARju9zWcf7uGv2BBfUBbg48wUjcCRSGxdy6FCcKn11LLLofBmomfbxXDZGXi8GYKPFLUD/sigBQM0lCqqM9kyqWCW4//y0RblWMLJ17qFa/acXuZHxC3ZBP235gk594mHw8+NcUk51xfCHIYWYtBKLmbQtddBH/yicyA3lJJ3zDxdH6cV3rn610fYZcMGnk+FO9DrwLrZSdeheOaB09i0JX5OhaJBSp84KOHm+IHWGUB27eGGD36vS08Ms1svbiIB+hiRo4HasgHJQlyN7adlNCOYQFbzEn+a/Qxol5k+TMuOaRAX0sSl3WSkrGUO2CZtaBEjmC7PzSdJN+mKu5l6TVd8dVb/cVHI/OgKFf2L02Fhh5arR773W6vXxX56SWv67SYB4akhEeji8HaY5YWG0ie4PD3GJKi4WaE31rcmJg0aZZSDw1G1Gxci6VgK21CsSBU+wOYzyztzEXyM+iG35sWffA=" + - secure: "Z77zxJXwfCdwD1E/jsUi7U/G3O9fak/7C9VESoNyHYm0QBRXA/Soy4+Iydg8nGz/NZSbWrx1MA4OlAfndqSzrKqosjezZguOEWrLLN6y1ac4Ba0yfp1askxXMAs6qjQTW6j+/TsFH8b9N9eQAvHDu6cVnRjHHvEJ8elQtsUmWw80/+kaLZ7xgLqOGKnaADQice0T6Z/GtjQGQMD4SEN1im6AH21LE4ebk66SOuuy1eQ/gwRoESOZSXO2p3CP+5nQcqmZG1h9ygK9VQiderMLtI39OLq6VWIe49Bq5NECxblVlvU2ABcBxHSSYr9snCgxQtuZSs3BFIqNE+/mJV/udwcD1ITgF6Y2p6uCY9YH/Rfqz5ajJWRByVJ7aj2dJI01l9w0z7OrLNSHVLFQfunJ6I0TjI/vMyEptvEgbtcGJHloKLHBlMKqKB4JhT3o/eitirULII6h2wI1uyFZkiSSoH/y2CGm03HzOimAZFOOesE2dY8fusTbi8/8OgFYFYg0Kn9Ru2e3BKfDZiOd+kptGlgWhqJvMuNpQiB4QI2AT9BoL0hU1FGAYatiGRHPoD+U0rdq3ypY92uxE8CSmaxXMlgBHErmqu4UD+bFpCJ9PMVUkdy9DMy/8HhxaDDp22mE+gcI8L2ynk7sWCEKOKaL/uguPMFOlWZtvL0rLV8kp0g=" script: skip # Don't run tests deploy: provider: script diff --git a/pubspec.yaml b/pubspec.yaml index 7137ab1ce..38d809fec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.3 +version: 1.0.0-beta.4 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 2217c6cebaa02b7bb39a4003510ee01192a04ccb Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 23 Jul 2020 17:31:00 -0700 Subject: [PATCH 026/162] Try building Windows releases on Windows (#16) --- .travis.yml | 1 + pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fe96a11fa..109e72108 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,6 +98,7 @@ jobs: if: *deploy-if env: *github-env script: skip + os: windows deploy: provider: script script: pub run grinder pkg-github-windows diff --git a/pubspec.yaml b/pubspec.yaml index 38d809fec..301983e49 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.4 +version: 1.0.0-beta.5 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 99859cbace26a946ab72f9d3e6f9ef6d9b25d2e4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 13 Aug 2020 11:58:04 -0700 Subject: [PATCH 027/162] Work around Travis errors caused by dart-lang/pub#2545 (#17) --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 109e72108..c075d2cb0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,10 @@ branches: # Semantic version tags and legacy branches of the form "1.2.x". - "/^\\d+\\.\\d+\\.(\\d+([+-].*)?|x)$/" +# TODO(nweiz): Make this stable when Dart 2.10.0 launches with a fix for +# dart-lang/pub#2545. +dart: 2.8.1 + cache: directories: - $HOME/.pub-cache @@ -33,16 +37,12 @@ jobs: ## Testing - - dart: stable + - dart_task: test + - dart: dev dart_task: test - # TODO(nweiz): Enable this when dart-lang/pub#2545 is fixed. - # - dart: dev - # dart_task: test - - dart: stable - os: windows + - os: windows dart_task: test - - dart: stable - os: osx + - os: osx dart_task: test # Static checks From e302719e154553d87296291b46b97963e2d18b22 Mon Sep 17 00:00:00 2001 From: Awjin Ahn Date: Wed, 26 Aug 2020 14:10:13 -0700 Subject: [PATCH 028/162] Update error handling to be asymmetric. (#18) (As per the protocol spec) --- lib/src/dispatcher.dart | 18 +++--------------- test/protocol_test.dart | 15 +++------------ 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index dd192a15d..ded7787b1 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -56,17 +56,6 @@ class Dispatcher { } switch (message.whichMessage()) { - case InboundMessage_Message.error: - var error = message.error; - stderr - .write("Host reported ${error.type.name.toLowerCase()} error"); - if (error.id != -1) stderr.write(" with request ${error.id}"); - stderr.writeln(": ${error.message}"); - // SOFTWARE error from https://bit.ly/2poTt90 - exitCode = 70; - _channel.sink.close(); - break; - case InboundMessage_Message.compileRequest: var request = message.compileRequest; var response = await callback(request); @@ -90,13 +79,9 @@ class Dispatcher { break; case InboundMessage_Message.notSet: - // PROTOCOL error from https://bit.ly/2poTt90 - exitCode = 76; throw _parseError("InboundMessage.message is not set."); default: - // PROTOCOL error from https://bit.ly/2poTt90 - exitCode = 76; throw _parseError( "Unknown message type: ${message.toDebugString()}"); } @@ -106,6 +91,9 @@ class Dispatcher { if (error.id != -1) stderr.write(" with request ${error.id}"); stderr.writeln(": ${error.message}"); sendError(error); + // PROTOCOL error from https://bit.ly/2poTt90 + exitCode = 76; + _channel.sink.close(); } catch (error, stackTrace) { var errorMessage = "$error\n${Chain.forTrace(stackTrace)}"; stderr.write("Internal compiler error: $errorMessage"); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 697e8a589..8060b98ee 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -18,27 +18,18 @@ void main() { process = await EmbeddedProcess.start(); }); - group("gracefully handles a protocol error", () { + group("exits upon protocol error", () { test("caused by an empty message", () async { process.inbound.add(InboundMessage()); await expectParseError(process, "InboundMessage.message is not set."); - await process.kill(); + expect(await process.exitCode, 76); }); test("caused by an invalid message", () async { process.stdin.add([1, 0, 0, 0, 0]); await expectParseError( process, "Protocol message contained an invalid tag (zero)."); - await process.kill(); - }); - - test("without shutting down the compiler", () async { - process.inbound.add(InboundMessage()); - await expectParseError(process, "InboundMessage.message is not set."); - - process.inbound.add(compileString("a {b: c}")); - await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); - await process.kill(); + expect(await process.exitCode, 76); }); }); From 0aa346cf7dd53d10c706f9a4afdd9f37eb052619 Mon Sep 17 00:00:00 2001 From: Awjin Ahn Date: Wed, 18 Nov 2020 14:47:24 -0600 Subject: [PATCH 029/162] Temporarily disable dartfmt. (#19) --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c075d2cb0..075a6c3f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,8 @@ before_install: before_script: - pub run grinder protobuf # Format the generated code or else the formatter task will get upset. -- dartfmt -w --fix lib/src/embedded_sass.pb* +# TODO(awjin): Re-enable this once dart-lang/sdk#42989 is fixed. +# - dartfmt -w --fix lib/src/embedded_sass.pb* - pub run grinder pkg-standalone-dev jobs: @@ -47,7 +48,8 @@ jobs: # Static checks - dart_task: {dartanalyzer: --fatal-warnings ./} - - dart_task: dartfmt + # TODO(awjin): Re-enable this once dart-lang/sdk#42989 is fixed. + # - dart_task: dartfmt ## Deploying From 313088866173a775342f0c237440cf698c4aa600 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 22 Dec 2020 16:06:16 -0800 Subject: [PATCH 030/162] Delimit messages using varints, as per sass/embedded-protocol#38 (#23) See sass/embedded-protocol#37 --- .../util/length_delimited_transformer.dart | 107 ++++++++++-------- pubspec.yaml | 3 +- test/length_delimited_test.dart | 59 ++++------ test/protocol_test.dart | 2 +- 4 files changed, 87 insertions(+), 84 deletions(-) diff --git a/lib/src/util/length_delimited_transformer.dart b/lib/src/util/length_delimited_transformer.dart index c516fb5fb..aba63ab7f 100644 --- a/lib/src/util/length_delimited_transformer.dart +++ b/lib/src/util/length_delimited_transformer.dart @@ -8,6 +8,7 @@ import 'dart:typed_data'; import 'package:async/async.dart'; import 'package:stream_channel/stream_channel.dart'; +import 'package:typed_data/typed_data.dart'; /// A [StreamChannelTransformer] that converts a channel that sends and receives /// arbitrarily-chunked binary data to one that sends and receives packets of @@ -21,17 +22,16 @@ final StreamChannelTransformer> lengthDelimited = /// into a stream of packet contents. final lengthDelimitedDecoder = StreamTransformer, Uint8List>.fromBind((stream) { - // The buffer into which the four-byte little-endian length of the next packet - // will be written. - var lengthBuffer = Uint8List(4); + // The number of bits we've consumed so far to fill out [nextMessageLength]. + int nextMessageLengthBits = 0; - // The index of the next byte to write to [lengthBuffer]. Once this is equal - // to [lengthBuffer.length], the full length is available. - var lengthBufferIndex = 0; - - // The length of the next message, in bytes, read from [lengthBuffer] once - // it's full. - int nextMessageLength; + // The length of the next message, in bytes. + // + // This is built up from a [varint]. Once it's fully consumed, [buffer] is + // initialized. + // + // [varint]: https://developers.google.com/protocol-buffers/docs/encoding#varints + int nextMessageLength = 0; // The buffer into which the packet data itself is written. Initialized once // [nextMessageLength] is known. @@ -53,47 +53,51 @@ final lengthDelimitedDecoder = // multiple messages. var i = 0; - // Adds bytes from [chunk] to [destination] at [destinationIndex] without - // overflowing the bounds of [destination], and increments [i] for each byte - // written. - // - // Returns the number of bytes written. - int writeFromChunk(Uint8List destination, int destinationIndex) { - var bytesToWrite = - math.min(destination.length - destinationIndex, chunk.length - i); - destination.setRange( - destinationIndex, destinationIndex + bytesToWrite, chunk, i); - i += bytesToWrite; - return bytesToWrite; - } - while (i < chunk.length) { // We can be in one of two states here: // - // * Both [nextMessageLength] and [buffer] are `null`, in which case we're - // waiting until we have four bytes in [lengthBuffer] to know how big of - // a buffer to allocate. + // * [buffer] is `null`, in which case we're adding data to + // [nextMessageLength] until we reach a byte with its most significant + // bit set to 0. // - // * Neither [nextMessageLength] nor [buffer] are `null`, in which case - // we're waiting for [buffer] to have [nextMessageLength] in it before - // we send it to [queue.local.sink] and start waiting for the next - // message. - if (nextMessageLength == null) { - lengthBufferIndex += writeFromChunk(lengthBuffer, lengthBufferIndex); - if (lengthBufferIndex < 4) return; - - nextMessageLength = - ByteData.view(lengthBuffer.buffer).getUint32(0, Endian.little); + // * [buffer] is not `null`, in which case we're waiting for [buffer] to + // have [nextMessageLength] bytes in it before we send it to + // [queue.local.sink] and start waiting for the next message. + if (buffer == null) { + var byte = chunk[i]; + + // Varints encode data in the 7 lower bits of each byte, which we access + // by masking with 0x7f = 0b01111111. + nextMessageLength += (byte & 0x7f) << nextMessageLengthBits; + nextMessageLengthBits += 7; + i++; + + // If the byte is higher than 0x7f = 0b01111111, that means its high bit + // is set which and so there are more bytes to consume before we know + // the full message length. + if (byte > 0x7f) continue; + + // Otherwise, [nextMessageLength] is now finalized and we can allocate + // the data buffer. buffer = Uint8List(nextMessageLength); bufferIndex = 0; } - bufferIndex += writeFromChunk(buffer, bufferIndex); + // Copy as many bytes as we can from [chunk] to [buffer], making sure not + // to try to copy more than the buffer can hold (if the chunk has another + // message after the current one) or more than the chunk has available (if + // the current message is split across multiple chunks). + var bytesToWrite = + math.min(buffer.length - bufferIndex, chunk.length - i); + buffer.setRange(bufferIndex, bufferIndex + bytesToWrite, chunk, i); + i += bytesToWrite; + bufferIndex += bytesToWrite; if (bufferIndex < nextMessageLength) return; - sink.add(Uint8List.view(buffer.buffer, 0, nextMessageLength)); - lengthBufferIndex = 0; - nextMessageLength = null; + // Once we've filled the buffer, emit it and reset our state. + sink.add(buffer); + nextMessageLength = 0; + nextMessageLengthBits = 0; buffer = null; bufferIndex = null; } @@ -106,9 +110,22 @@ final lengthDelimitedDecoder = final lengthDelimitedEncoder = StreamTransformer>.fromHandlers( handleData: (message, sink) { - var messageLength = Uint8List(4); - ByteData.view(messageLength.buffer) - .setUint32(0, message.length, Endian.little); - sink.add(messageLength); + var length = message.length; + if (length == 0) { + sink.add([0]); + return; + } + + // Write the length in varint format, 7 bits at a time from least to most + // significant. + var lengthBuffer = Uint8Buffer(); + while (length > 0) { + // The highest-order bit indicates whether more bytes are necessary to fully + // express the number. The lower 7 bits indicate the number's value. + lengthBuffer.add((length > 0x7f ? 0x80 : 0) | (length & 0x7f)); + length >>= 7; + } + + sink.add(Uint8List.view(lengthBuffer.buffer, 0, lengthBuffer.length)); sink.add(message); }); diff --git a/pubspec.yaml b/pubspec.yaml index 301983e49..4901ad99e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.5 +version: 1.0.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded @@ -19,6 +19,7 @@ dependencies: source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" + typed_data: ^1.1.0 dev_dependencies: cli_pkg: ^1.0.0-beta.8 diff --git a/test/length_delimited_test.dart b/test/length_delimited_test.dart index c0cd1ce2e..1fc831821 100644 --- a/test/length_delimited_test.dart +++ b/test/length_delimited_test.dart @@ -25,20 +25,20 @@ void main() { test("encodes an empty message", () { sink.add([]); sink.close(); - expect(collectBytes(stream), completion(equals([0, 0, 0, 0]))); + expect(collectBytes(stream), completion(equals([0]))); }); test("encodes a message of length 1", () { sink.add([123]); sink.close(); - expect(collectBytes(stream), completion(equals([1, 0, 0, 0, 123]))); + expect(collectBytes(stream), completion(equals([1, 123]))); }); test("encodes a message of length greater than 256", () { sink.add(List.filled(300, 1)); sink.close(); expect(collectBytes(stream), - completion(equals([44, 1, 0, 0, ...List.filled(300, 1)]))); + completion(equals([172, 2, ...List.filled(300, 1)]))); }); test("encodes multiple messages", () { @@ -46,10 +46,8 @@ void main() { sink.add([20, 30]); sink.add([40, 50, 60]); sink.close(); - expect( - collectBytes(stream), - completion(equals( - [1, 0, 0, 0, 10, 2, 0, 0, 0, 20, 30, 3, 0, 0, 0, 40, 50, 60]))); + expect(collectBytes(stream), + completion(equals([1, 10, 2, 20, 30, 3, 40, 50, 60]))); }); }); @@ -64,75 +62,62 @@ void main() { group("decodes an empty message", () { test("from a single chunk", () { - sink.add([0, 0, 0, 0]); - expect(queue, emits(isEmpty)); - }); - - test("from multiple chunks", () { - sink.add([0, 0]); - sink.add([0, 0]); - expect(queue, emits(isEmpty)); - }); - - test("from one chunk per byte", () { - sink..add([0])..add([0])..add([0])..add([0]); + sink.add([0]); expect(queue, emits(isEmpty)); }); test("from a chunk that contains more data", () { - sink.add([0, 0, 0, 0, 1, 0, 0, 0, 100]); + sink.add([0, 1, 100]); expect(queue, emits(isEmpty)); }); }); group("decodes a longer message", () { test("from a single chunk", () { - sink.add([4, 0, 0, 0, 1, 2, 3, 4]); - expect(queue, emits([1, 2, 3, 4])); + sink.add([172, 2, ...List.filled(300, 1)]); + expect(queue, emits(List.filled(300, 1))); }); test("from multiple chunks", () { - sink..add([4, 0])..add([0, 0, 1, 2])..add([3, 4]); - expect(queue, emits([1, 2, 3, 4])); + sink..add([172])..add([2, 1])..add(List.filled(299, 1)); + expect(queue, emits(List.filled(300, 1))); }); test("from one chunk per byte", () { - for (var byte in [4, 0, 0, 0, 1, 2, 3, 4]) { + for (var byte in [172, 2, ...List.filled(300, 1)]) { sink.add([byte]); } - expect(queue, emits([1, 2, 3, 4])); + expect(queue, emits(List.filled(300, 1))); }); test("from a chunk that contains more data", () { - sink.add([4, 0, 0, 0, 1, 2, 3, 4, 1, 0, 0, 0]); - expect(queue, emits([1, 2, 3, 4])); - }); - - test("of length greater than 256", () { - sink.add([44, 1, 0, 0, ...List.filled(300, 1)]); + sink.add([172, 2, ...List.filled(300, 1), 1, 10]); expect(queue, emits(List.filled(300, 1))); }); }); group("decodes multiple messages", () { test("from single chunk", () { - sink.add([4, 0, 0, 0, 1, 2, 3, 4, 2, 0, 0, 0, 101, 102]); + sink.add([4, 1, 2, 3, 4, 2, 101, 102]); expect(queue, emits([1, 2, 3, 4])); expect(queue, emits([101, 102])); }); test("from multiple chunks", () { - sink..add([4, 0])..add([0, 0, 1, 2, 3, 4, 2, 0])..add([0, 0, 101, 102]); + sink + ..add([4]) + ..add([1, 2, 3, 4, 172]) + ..add([2, ...List.filled(300, 1)]); expect(queue, emits([1, 2, 3, 4])); - expect(queue, emits([101, 102])); + expect(queue, emits(List.filled(300, 1))); }); test("from one chunk per byte", () { - for (var byte in [4, 0, 0, 0, 1, 2, 3, 4, 2, 0, 0, 0, 101, 102]) { + for (var byte in [4, 1, 2, 3, 4, 172, 2, ...List.filled(300, 1)]) { sink.add([byte]); } expect(queue, emits([1, 2, 3, 4])); - expect(queue, emits([101, 102])); + expect(queue, emits(List.filled(300, 1))); }); }); }); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 8060b98ee..61e8e1f33 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -26,7 +26,7 @@ void main() { }); test("caused by an invalid message", () async { - process.stdin.add([1, 0, 0, 0, 0]); + process.stdin.add([1, 0]); await expectParseError( process, "Protocol message contained an invalid tag (zero)."); expect(await process.exitCode, 76); From fa0376619904e51ed46a5ffe237baf70614d65f4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 23 Dec 2020 14:47:19 -0800 Subject: [PATCH 031/162] Document where releases can be found (#21) --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 228642276..aa839b7a4 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,13 @@ and importers. [Dart Sass]: https://sass-lang.com/dart-sass [Embedded Sass protocol]: https://github.com/sass/sass-embedded-protocol/blob/master/README.md#readme +### Releases + +Binary releases are available from the [GitHub release page]. We recommend that +embedded hosts embed these release binaries in their packages, or use a +post-install script to install a specific version of the embedded compiler to +avoid version skew. + +[GitHub release page]: https://github.com/sass/dart-sass-embedded/releases + Disclaimer: this is not an official Google product. From 2f4fb065d48014c5124b834f56a159d544c45dec Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 23 Dec 2020 14:49:33 -0800 Subject: [PATCH 032/162] Handle CompileRequest.StringInput.importer (#22) Partially addresses sass/embedded_protocol#37 --- bin/dart_sass_embedded.dart | 45 ++++++++++++++++++++++--------------- test/importer_test.dart | 16 +++++++++++++ test/utils.dart | 2 ++ 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index e334ff0cd..dd8380c23 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -48,24 +48,9 @@ void main(List args) { ? (source_maps.SingleMapping map) => sourceMap = map : null; - var importers = request.importers.map((importer) { - switch (importer.whichImporter()) { - case InboundMessage_CompileRequest_Importer_Importer.path: - return sass.FilesystemImporter(importer.path); - - case InboundMessage_CompileRequest_Importer_Importer.importerId: - return Importer(dispatcher, request.id, importer.importerId); - - case InboundMessage_CompileRequest_Importer_Importer.fileImporterId: - throw "CompileRequest.Importer.fileImporterId is not yet supported"; - - case InboundMessage_CompileRequest_Importer_Importer.notSet: - throw mandatoryError("Importer.importer"); - } - - // dart-lang/sdk#38790 - throw "Unknown Importer.importer $importer."; - }); + var importers = request.importers.map((importer) => + _decodeImporter(dispatcher, request, importer) ?? + (throw mandatoryError("Importer.importer"))); var globalFunctions = request.globalFunctions.map((signature) => hostCallable(dispatcher, functions, request.id, signature)); @@ -76,6 +61,7 @@ void main(List args) { result = sass.compileString(input.source, logger: logger, importers: importers, + importer: _decodeImporter(dispatcher, request, input.importer), functions: globalFunctions, syntax: syntaxToSyntax(input.syntax), style: style, @@ -119,3 +105,26 @@ void main(List args) { } }); } + +/// Converts [importer] into an [Importer]. +sass.Importer _decodeImporter( + Dispatcher dispatcher, + InboundMessage_CompileRequest request, + InboundMessage_CompileRequest_Importer importer) { + switch (importer.whichImporter()) { + case InboundMessage_CompileRequest_Importer_Importer.path: + return sass.FilesystemImporter(importer.path); + + case InboundMessage_CompileRequest_Importer_Importer.importerId: + return Importer(dispatcher, request.id, importer.importerId); + + case InboundMessage_CompileRequest_Importer_Importer.fileImporterId: + throw "CompileRequest.Importer.fileImporterId is not yet supported"; + + case InboundMessage_CompileRequest_Importer_Importer.notSet: + return null; + } + + // dart-lang/sdk#38790 + throw "Unknown Importer.importer $importer."; +} diff --git a/test/importer_test.dart b/test/importer_test.dart index 1bb8677f0..b5b0171c1 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -411,6 +411,22 @@ void main() { }); }); + test("handles an importer for a string compile request", () async { + process.inbound.add(compileString("@import 'other'", + importer: InboundMessage_CompileRequest_Importer()..importerId = 1)); + await _canonicalize(process); + + var request = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = (InboundMessage_ImportResponse() + ..id = request.id + ..success = (InboundMessage_ImportResponse_ImportSuccess() + ..contents = "a {b: 1px + 2px}"))); + + await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); + await process.kill(); + }); + group("load paths", () { test("are used to load imports", () async { await d.dir("dir", [d.file("other.scss", "a {b: c}")]).create(); diff --git a/test/utils.dart b/test/utils.dart index e5b7a8fa9..a934af895 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -18,10 +18,12 @@ InboundMessage compileString(String css, String url, bool sourceMap, Iterable importers, + InboundMessage_CompileRequest_Importer importer, Iterable functions}) { var input = InboundMessage_CompileRequest_StringInput()..source = css; if (syntax != null) input.syntax = syntax; if (url != null) input.url = url; + if (importer != null) input.importer = importer; var request = InboundMessage_CompileRequest()..string = input; if (id != null) request.id = id; From 8a559fbe50f2d244f16aedfc16323d00303afd52 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 5 Jan 2021 15:36:24 -0800 Subject: [PATCH 033/162] Update tests for the latest Sass version (#25) --- test/function_test.dart | 28 ++++++++++++++-------------- test/protocol_test.dart | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/function_test.dart b/test/function_test.dart index 3c12563e8..a6d3c3b0b 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -391,73 +391,73 @@ void main() { group("without alpha:", () { group("hue", () { test("0", () async { - expect(await _protofy('hsl(0, 50, 50)'), _rgb(191, 64, 64, 1.0)); + expect(await _protofy('hsl(0, 50%, 50%)'), _rgb(191, 64, 64, 1.0)); }); test("360", () async { expect( - await _protofy('hsl(360, 50, 50)'), _rgb(191, 64, 64, 1.0)); + await _protofy('hsl(360, 50%, 50%)'), _rgb(191, 64, 64, 1.0)); }); test("below 0", () async { expect( - await _protofy('hsl(-100, 50, 50)'), _rgb(106, 64, 191, 1.0)); + await _protofy('hsl(-100, 50%, 50%)'), _rgb(106, 64, 191, 1.0)); }); test("between 0 and 360", () async { expect( - await _protofy('hsl(100, 50, 50)'), _rgb(106, 191, 64, 1.0)); + await _protofy('hsl(100, 50%, 50%)'), _rgb(106, 191, 64, 1.0)); }); test("above 360", () async { expect( - await _protofy('hsl(560, 50, 50)'), _rgb(64, 149, 191, 1.0)); + await _protofy('hsl(560, 50%, 50%)'), _rgb(64, 149, 191, 1.0)); }); }); group("saturation", () { test("0", () async { - expect(await _protofy('hsl(0, 0, 50)'), _rgb(128, 128, 128, 1.0)); + expect(await _protofy('hsl(0, 0%, 50%)'), _rgb(128, 128, 128, 1.0)); }); test("100", () async { - expect(await _protofy('hsl(0, 100, 50)'), _rgb(255, 0, 0, 1.0)); + expect(await _protofy('hsl(0, 100%, 50%)'), _rgb(255, 0, 0, 1.0)); }); test("in the middle", () async { - expect(await _protofy('hsl(0, 42, 50)'), _rgb(181, 74, 74, 1.0)); + expect(await _protofy('hsl(0, 42%, 50%)'), _rgb(181, 74, 74, 1.0)); }); }); group("lightness", () { test("0", () async { - expect(await _protofy('hsl(0, 50, 0)'), _rgb(0, 0, 0, 1.0)); + expect(await _protofy('hsl(0, 50%, 0%)'), _rgb(0, 0, 0, 1.0)); }); test("100", () async { expect( - await _protofy('hsl(0, 50, 100)'), _rgb(255, 255, 255, 1.0)); + await _protofy('hsl(0, 50%, 100%)'), _rgb(255, 255, 255, 1.0)); }); test("in the middle", () async { - expect(await _protofy('hsl(0, 50, 42)'), _rgb(161, 54, 54, 1.0)); + expect(await _protofy('hsl(0, 50%, 42%)'), _rgb(161, 54, 54, 1.0)); }); }); }); group("with alpha", () { test("0", () async { - expect(await _protofy('hsl(10, 20, 30, 0)'), + expect(await _protofy('hsl(10, 20%, 30%, 0)'), equals(_rgb(92, 66, 61, 0.0))); }); test("1", () async { - expect(await _protofy('hsl(10, 20, 30, 1)'), + expect(await _protofy('hsl(10, 20%, 30%, 1)'), equals(_rgb(92, 66, 61, 1.0))); }); test("between 0 and 1", () async { - expect(await _protofy('hsl(10, 20, 30, 0.123)'), + expect(await _protofy('hsl(10, 20%, 30%, 0.123)'), equals(_rgb(92, 66, 61, 0.123))); }); }); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 61e8e1f33..679bf5e12 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -242,7 +242,7 @@ void main() { process.inbound.add(compileString("a {b: 1px + 1em}")); var failure = getCompileFailure(await process.outbound.next); - expect(failure.message, equals("Incompatible units em and px.")); + expect(failure.message, equals("1px and 1em have incompatible units.")); expect(failure.span.text, "1px + 1em"); expect(failure.span.start, equals(location(6, 0, 6))); expect(failure.span.end, equals(location(15, 0, 15))); From 5f20d0a4310d2ac15542cab0269d9a7f3314a38e Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 6 Jan 2021 13:54:16 -0800 Subject: [PATCH 034/162] Release 1.0.0-beta.6 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 4901ad99e..36cfd4e57 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.0.0-beta.6 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From d37212b3bbf92e9bff8278e8269c794bef5e09ca Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 6 Jan 2021 15:56:18 -0800 Subject: [PATCH 035/162] Use 0xffffffff as the fallback error ID See sass/embedded-protocol#45 --- lib/src/dispatcher.dart | 6 +++--- lib/src/host_callable.dart | 2 +- lib/src/utils.dart | 11 +++++++---- test/function_test.dart | 31 ++++++++++++++++++------------- test/importer_test.dart | 7 ++++--- test/utils.dart | 5 +++-- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index ded7787b1..fcbd814bb 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -86,9 +86,9 @@ class Dispatcher { "Unknown message type: ${message.toDebugString()}"); } } on ProtocolError catch (error) { - error.id = _inboundId(message) ?? -1; + error.id = _inboundId(message) ?? errorId; stderr.write("Host caused ${error.type.name.toLowerCase()} error"); - if (error.id != -1) stderr.write(" with request ${error.id}"); + if (error.id != errorId) stderr.write(" with request ${error.id}"); stderr.writeln(": ${error.message}"); sendError(error); // PROTOCOL error from https://bit.ly/2poTt90 @@ -99,7 +99,7 @@ class Dispatcher { stderr.write("Internal compiler error: $errorMessage"); sendError(ProtocolError() ..type = ProtocolError_ErrorType.INTERNAL - ..id = _inboundId(message) ?? -1 + ..id = _inboundId(message) ?? errorId ..message = errorMessage); _channel.sink.close(); } diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index 87cd2ddc7..e3990aaf7 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -70,7 +70,7 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, // dart-lang/sdk#38790 throw "Unknown FunctionCallResponse.result $response."; } on ProtocolError catch (error) { - error.id = -1; + error.id = errorId; stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " "${error.message}"); dispatcher.sendError(error); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 8d34bd226..d89c27d08 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -8,6 +8,10 @@ import 'package:source_span/source_span.dart'; import 'embedded_sass.pb.dart' as proto; import 'embedded_sass.pb.dart' hide SourceSpan; +/// The special ID that indicates an error that's not associated with a specific +/// inbound request ID. +const errorId = 0xffffffff; + /// Returns a [ProtocolError] indicating that a mandatory field with the given /// [fieldName] was missing. ProtocolError mandatoryError(String fieldName) => @@ -16,10 +20,9 @@ ProtocolError mandatoryError(String fieldName) => /// Returns a [ProtocolError] indicating that the parameters for an inbound /// message were invalid. ProtocolError paramsError(String message) => ProtocolError() - // Set the ID to -1 by default, because that's the required value for errors - // that aren't associated with a specific inbound request ID. This will be - // overwritten by the dispatcher if a request ID is available. - ..id = -1 + // Set the ID to [errorId] by default. This will be overwritten by the + // dispatcher if a request ID is available. + ..id = errorId ..type = ProtocolError_ErrorType.PARAMS ..message = message; diff --git a/test/function_test.dart b/test/function_test.dart index a6d3c3b0b..fd5e3dd97 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -5,6 +5,7 @@ import 'package:test/test.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/utils.dart'; import 'embedded_process.dart'; import 'utils.dart'; @@ -391,7 +392,8 @@ void main() { group("without alpha:", () { group("hue", () { test("0", () async { - expect(await _protofy('hsl(0, 50%, 50%)'), _rgb(191, 64, 64, 1.0)); + expect( + await _protofy('hsl(0, 50%, 50%)'), _rgb(191, 64, 64, 1.0)); }); test("360", () async { @@ -400,24 +402,25 @@ void main() { }); test("below 0", () async { - expect( - await _protofy('hsl(-100, 50%, 50%)'), _rgb(106, 64, 191, 1.0)); + expect(await _protofy('hsl(-100, 50%, 50%)'), + _rgb(106, 64, 191, 1.0)); }); test("between 0 and 360", () async { - expect( - await _protofy('hsl(100, 50%, 50%)'), _rgb(106, 191, 64, 1.0)); + expect(await _protofy('hsl(100, 50%, 50%)'), + _rgb(106, 191, 64, 1.0)); }); test("above 360", () async { - expect( - await _protofy('hsl(560, 50%, 50%)'), _rgb(64, 149, 191, 1.0)); + expect(await _protofy('hsl(560, 50%, 50%)'), + _rgb(64, 149, 191, 1.0)); }); }); group("saturation", () { test("0", () async { - expect(await _protofy('hsl(0, 0%, 50%)'), _rgb(128, 128, 128, 1.0)); + expect( + await _protofy('hsl(0, 0%, 50%)'), _rgb(128, 128, 128, 1.0)); }); test("100", () async { @@ -425,7 +428,8 @@ void main() { }); test("in the middle", () async { - expect(await _protofy('hsl(0, 42%, 50%)'), _rgb(181, 74, 74, 1.0)); + expect( + await _protofy('hsl(0, 42%, 50%)'), _rgb(181, 74, 74, 1.0)); }); }); @@ -435,12 +439,13 @@ void main() { }); test("100", () async { - expect( - await _protofy('hsl(0, 50%, 100%)'), _rgb(255, 255, 255, 1.0)); + expect(await _protofy('hsl(0, 50%, 100%)'), + _rgb(255, 255, 255, 1.0)); }); test("in the middle", () async { - expect(await _protofy('hsl(0, 50%, 42%)'), _rgb(161, 54, 54, 1.0)); + expect( + await _protofy('hsl(0, 50%, 42%)'), _rgb(161, 54, 54, 1.0)); }); }); }); @@ -1242,7 +1247,7 @@ Future _expectDeprotofyError(Value value, message) async { ..id = request.id ..success = value)); - await expectParamsError(_process, -1, message); + await expectParamsError(_process, errorId, message); await _process.kill(); } diff --git a/test/importer_test.dart b/test/importer_test.dart index b5b0171c1..f60c7607b 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/utils.dart'; import 'embedded_process.dart'; import 'utils.dart'; @@ -30,7 +31,7 @@ void main() { await expectParamsError( process, - -1, + errorId, "Response ID ${request.id + 1} doesn't match any outstanding " "requests."); await process.kill(); @@ -47,7 +48,7 @@ void main() { await expectParamsError( process, - -1, + errorId, "Request ID ${request.id} doesn't match response type " "InboundMessage_ImportResponse."); await process.kill(); @@ -505,7 +506,7 @@ Future _canonicalize(EmbeddedProcess process) async { /// [message] on its protobuf stream and causes the compilation to fail. Future _expectImportParamsError(EmbeddedProcess process, message) async { await expectLater(process.outbound, - emits(isProtocolError(-1, ProtocolError_ErrorType.PARAMS, message))); + emits(isProtocolError(errorId, ProtocolError_ErrorType.PARAMS, message))); var failure = getCompileFailure(await process.outbound.next); expect(failure.message, equals('Protocol error: $message')); diff --git a/test/utils.dart b/test/utils.dart index a934af895..d915266a3 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -6,6 +6,7 @@ import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/utils.dart'; import 'embedded_process.dart'; @@ -39,7 +40,7 @@ InboundMessage compileString(String css, /// [message] on its protobuf stream and prints a notice on stderr. Future expectParseError(EmbeddedProcess process, message) async { await expectLater(process.outbound, - emits(isProtocolError(-1, ProtocolError_ErrorType.PARSE, message))); + emits(isProtocolError(errorId, ProtocolError_ErrorType.PARSE, message))); var stderrPrefix = "Host caused parse error: "; await expectLater( @@ -56,7 +57,7 @@ Future expectParamsError(EmbeddedProcess process, int id, message) async { emits(isProtocolError(id, ProtocolError_ErrorType.PARAMS, message))); var stderrPrefix = "Host caused params error" - "${id == -1 ? '' : " with request $id"}: "; + "${id == errorId ? '' : " with request $id"}: "; await expectLater( process.stderr, message is String From 8128431b1869ea3678c95256f6dcdece2f17a0f4 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 13 Jan 2021 22:44:41 +0100 Subject: [PATCH 036/162] Use the dart cli in tasks (#27) --- .travis.yml | 4 +--- pubspec.yaml | 2 +- tool/grind.dart | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 075a6c3f2..803e29e73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,7 @@ branches: # Semantic version tags and legacy branches of the form "1.2.x". - "/^\\d+\\.\\d+\\.(\\d+([+-].*)?|x)$/" -# TODO(nweiz): Make this stable when Dart 2.10.0 launches with a fix for -# dart-lang/pub#2545. -dart: 2.8.1 +dart: stable cache: directories: diff --git a/pubspec.yaml b/pubspec.yaml index 36cfd4e57..84cef86da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ author: Sass Team homepage: https://github.com/sass/dart-sass-embedded environment: - sdk: '>=2.4.0 <3.0.0' + sdk: '>=2.10.0 <3.0.0' executables: dart-sass-embedded: dart_sass_embedded diff --git a/tool/grind.dart b/tool/grind.dart index 8da27d842..c80b33faa 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -24,11 +24,11 @@ protobuf() async { if (Platform.isWindows) { File('build/protoc-gen-dart.bat').writeAsStringSync(''' @echo off -pub run protoc_plugin %* +dart pub run protoc_plugin %* '''); } else { File('build/protoc-gen-dart') - .writeAsStringSync('pub run protoc_plugin "\$@"'); + .writeAsStringSync('dart pub run protoc_plugin "\$@"'); run('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); } From d18aa4dbbe8cf4388e434d3900de5aa8cee9c545 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 20 Jan 2021 22:21:05 +0100 Subject: [PATCH 037/162] Migrate CI to github actions (#28) --- .github/workflows/ci.yml | 105 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 106 --------------------------------------- test/protocol_test.dart | 2 +- 3 files changed, 106 insertions(+), 107 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..4d5e45489 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,105 @@ +name: CI + +env: + protoc_version: '3.x' + +on: + push: + branches: [master, feature.*] + tags: ['**'] + pull_request: + +jobs: + dart_tests: + name: "Dart tests | Dart ${{ matrix.dart_channel }} | ${{ matrix.os }}" + runs-on: "${{ matrix.os }}" + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + dart_channel: [stable] + include: [{os: ubuntu-latest, dart_channel: dev}] + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: cedx/setup-dart@v2 + with: {release-channel: "${{ matrix.dart_channel }}"} + - run: dart pub get + - run: dart pub run grinder protobuf + - run: dart pub run grinder pkg-standalone-dev + - name: Run tests + run: dart pub run test -r expanded + + static_analysis: + name: Static analysis + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: cedx/setup-dart@v2 + - run: dart pub get + - run: dart pub run grinder protobuf + - name: Analyze dart + run: dartanalyzer --fatal-warnings ./ + + deploy_github_linux: + name: "Deploy Github: Linux" + runs-on: ubuntu-latest + needs: [dart_tests, static_analysis] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: cedx/setup-dart@v2 + - run: dart pub get + - run: dart pub run grinder protobuf + - name: Deploy + run: dart pub run grinder pkg-github-release pkg-github-linux + env: + GH_TOKEN: "${{ secrets.GH_TOKEN }}" + GH_USER: sassbot + + deploy_github_macos: + name: "Deploy Github: Mac OS" + runs-on: macos-latest + needs: [deploy_github_linux] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: cedx/setup-dart@v2 + - run: dart pub get + - run: dart pub run grinder protobuf + - name: Deploy + run: dart pub run grinder pkg-github-macos + env: + GH_TOKEN: "${{ secrets.GH_TOKEN }}" + GH_USER: sassbot + + deploy_github_windows: + name: "Deploy Github: Windows" + runs-on: windows-latest + needs: [deploy_github_linux] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: cedx/setup-dart@v2 + - run: dart pub get + - run: dart pub run grinder protobuf + - name: Deploy + run: dart pub run grinder pkg-github-windows + env: + GH_TOKEN: "${{ secrets.GH_TOKEN }}" + GH_USER: sassbot diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 803e29e73..000000000 --- a/.travis.yml +++ /dev/null @@ -1,106 +0,0 @@ -language: dart -branches: - only: - - master - # Semantic version tags and legacy branches of the form "1.2.x". - - "/^\\d+\\.\\d+\\.(\\d+([+-].*)?|x)$/" - -dart: stable - -cache: - directories: - - $HOME/.pub-cache - -env: - global: - - PROTOBUF_VERSION=3.10.1 - - PATH="$HOME/protoc/bin:$PATH" - -before_install: -- if [[ "$TRAVIS_OS_NAME" = windows ]]; then - curl -Lo protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-win64.zip; - else - curl -Lo protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-${TRAVIS_OS_NAME}-x86_64.zip; - fi -- unzip -d "$HOME/protoc" protoc.zip - -before_script: -- pub run grinder protobuf -# Format the generated code or else the formatter task will get upset. -# TODO(awjin): Re-enable this once dart-lang/sdk#42989 is fixed. -# - dartfmt -w --fix lib/src/embedded_sass.pb* -- pub run grinder pkg-standalone-dev - -jobs: - include: - - ## Testing - - - dart_task: test - - dart: dev - dart_task: test - - os: windows - dart_task: test - - os: osx - dart_task: test - - # Static checks - - dart_task: {dartanalyzer: --fatal-warnings ./} - # TODO(awjin): Re-enable this once dart-lang/sdk#42989 is fixed. - # - dart_task: dartfmt - - ## Deploying - - # Deploy Linux releases to GitHub. Mac OS and Windows releases are deployed in - # a later stage so that we can build native snapshots on bots with the same - # operating system. - - stage: deploy 1 - name: "GitHub: Linux" - if: &deploy-if - (type IN (push, api)) AND (repo = sass/dart-sass-embedded) AND tag =~ ^\d+\.\d+\.\d+([+-].*)?$ - env: &github-env - - GITHUB_USER=sassbot - # GITHUB_TOKEN="..." - - secure: "Z77zxJXwfCdwD1E/jsUi7U/G3O9fak/7C9VESoNyHYm0QBRXA/Soy4+Iydg8nGz/NZSbWrx1MA4OlAfndqSzrKqosjezZguOEWrLLN6y1ac4Ba0yfp1askxXMAs6qjQTW6j+/TsFH8b9N9eQAvHDu6cVnRjHHvEJ8elQtsUmWw80/+kaLZ7xgLqOGKnaADQice0T6Z/GtjQGQMD4SEN1im6AH21LE4ebk66SOuuy1eQ/gwRoESOZSXO2p3CP+5nQcqmZG1h9ygK9VQiderMLtI39OLq6VWIe49Bq5NECxblVlvU2ABcBxHSSYr9snCgxQtuZSs3BFIqNE+/mJV/udwcD1ITgF6Y2p6uCY9YH/Rfqz5ajJWRByVJ7aj2dJI01l9w0z7OrLNSHVLFQfunJ6I0TjI/vMyEptvEgbtcGJHloKLHBlMKqKB4JhT3o/eitirULII6h2wI1uyFZkiSSoH/y2CGm03HzOimAZFOOesE2dY8fusTbi8/8OgFYFYg0Kn9Ru2e3BKfDZiOd+kptGlgWhqJvMuNpQiB4QI2AT9BoL0hU1FGAYatiGRHPoD+U0rdq3ypY92uxE8CSmaxXMlgBHErmqu4UD+bFpCJ9PMVUkdy9DMy/8HhxaDDp22mE+gcI8L2ynk7sWCEKOKaL/uguPMFOlWZtvL0rLV8kp0g=" - script: skip # Don't run tests - deploy: - provider: script - script: pub run grinder pkg-github-release pkg-github-linux - skip_cleanup: true # Don't clean up the Dart SDK. - - # This causes the deploy to only be build when a tag is pushed. This - # is because the `tag` attribute in `if:` statements has a different - # understanding of the "current tag" than this, which uses the - # `TRAVIS_TAG` environment variable. `if:` statements check whether a - # tag exists that refers to the current commit, whereas `TRAVIS_TAG` - # checks whether the current build was caused by a tag. - # - # We check `if:` because it avoids unnecessary build steps, and - # `on: {tags: true}` ensures that we only deploy on the build caused - # by pushing a tag, not the build caused by pushing master. - on: {tags: true} - - # Deploy to Bazel. This is in a separate deploy stage because it needs to - # install the npm package. - - stage: deploy 2 - name: "GitHub: Mac OS" - if: *deploy-if - env: *github-env - script: skip - os: osx - deploy: - provider: script - script: pub run grinder pkg-github-macos - skip_cleanup: true - on: {tags: true} - - - name: "GitHub: Windows" - if: *deploy-if - env: *github-env - script: skip - os: windows - deploy: - provider: script - script: pub run grinder pkg-github-windows - skip_cleanup: true - on: {tags: true} diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 679bf5e12..f517c1a5a 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -259,7 +259,7 @@ void main() { var failure = getCompileFailure(await process.outbound.next); expect(failure.message, startsWith("Cannot open file: ")); - expect(failure.message.split(":").last.trim(), + expect(failure.message.replaceFirst("Cannot open file: ", "").trim(), equalsPath(d.path('test.scss'))); expect(failure.span, equals(SourceSpan())); expect(failure.stackTrace, isEmpty); From b0680836d4b71622950b8be1e0c773ba2ec223e4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 20 Jan 2021 16:32:18 -0800 Subject: [PATCH 038/162] Use GitHub Actions' bearer: token rather than a basic auth token (#30) --- .github/workflows/ci.yml | 12 +++--------- pubspec.yaml | 2 +- tool/grind.dart | 2 ++ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d5e45489..54633c866 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,9 +62,7 @@ jobs: - run: dart pub run grinder protobuf - name: Deploy run: dart pub run grinder pkg-github-release pkg-github-linux - env: - GH_TOKEN: "${{ secrets.GH_TOKEN }}" - GH_USER: sassbot + env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_macos: name: "Deploy Github: Mac OS" @@ -81,9 +79,7 @@ jobs: - run: dart pub run grinder protobuf - name: Deploy run: dart pub run grinder pkg-github-macos - env: - GH_TOKEN: "${{ secrets.GH_TOKEN }}" - GH_USER: sassbot + env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_windows: name: "Deploy Github: Windows" @@ -100,6 +96,4 @@ jobs: - run: dart pub run grinder protobuf - name: Deploy run: dart pub run grinder pkg-github-windows - env: - GH_TOKEN: "${{ secrets.GH_TOKEN }}" - GH_USER: sassbot + env: {GH_BEARER_TOKEN: "${{ github.token }}"} diff --git a/pubspec.yaml b/pubspec.yaml index 84cef86da..e97511ba0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: typed_data: ^1.1.0 dev_dependencies: - cli_pkg: ^1.0.0-beta.8 + cli_pkg: ^1.2.0 grinder: ^0.8.0 protoc_plugin: ^19.0.0 path: ^1.6.0 diff --git a/tool/grind.dart b/tool/grind.dart index c80b33faa..4cb59a20f 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -10,6 +10,8 @@ import 'package:grinder/grinder.dart'; import 'utils.dart'; main(List args) { + pkg.githubBearerToken.value = Platform.environment["GH_BEARER_TOKEN"]; + pkg.addGithubTasks(); grind(args); } From 831e5e903ef6f163bde27e2f20d741bf257542ed Mon Sep 17 00:00:00 2001 From: Awjin Ahn Date: Wed, 3 Feb 2021 20:31:27 -0600 Subject: [PATCH 039/162] Formatted alerts (#35) --- bin/dart_sass_embedded.dart | 11 ++- lib/src/logger.dart | 48 +++++++++++- lib/src/utils.dart | 16 ++++ test/protocol_test.dart | 150 +++++++++++++++++++++++++++--------- test/utils.dart | 4 + 5 files changed, 187 insertions(+), 42 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index dd8380c23..d431ac14a 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -39,7 +39,9 @@ void main(List args) { request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED ? sass.OutputStyle.compressed : sass.OutputStyle.expanded; - var logger = Logger(dispatcher, request.id); + var color = request.alertColor ?? false; + var ascii = request.alertAscii ?? false; + var logger = Logger(dispatcher, request.id, color: color, ascii: ascii); try { String result; @@ -59,6 +61,7 @@ void main(List args) { case InboundMessage_CompileRequest_Input.string: var input = request.string; result = sass.compileString(input.source, + color: color, logger: logger, importers: importers, importer: _decodeImporter(dispatcher, request, input.importer), @@ -72,6 +75,7 @@ void main(List args) { case InboundMessage_CompileRequest_Input.path: try { result = sass.compile(request.path, + color: color, logger: logger, importers: importers, functions: globalFunctions, @@ -97,11 +101,14 @@ void main(List args) { } return OutboundMessage_CompileResponse()..success = success; } on sass.SassException catch (error) { + var formatted = withGlyphs(() => error.toString(color: color), + ascii: request.alertAscii); return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() ..message = error.message ..span = protofySpan(error.span) - ..stackTrace = error.trace.toString()); + ..stackTrace = error.trace.toString() + ..formatted = formatted); } }); } diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 09bea878f..06b82fb3f 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -2,6 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:path/path.dart' as p; import 'package:sass/sass.dart' as sass; import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; @@ -18,24 +19,65 @@ class Logger implements sass.Logger { /// The ID of the compilation to which this logger is passed. final int _compilationId; - Logger(this._dispatcher, this._compilationId); + /// Whether the formatted message should contain terminal colors. + final bool _color; + + /// Whether the formatted message should use ASCII encoding. + final bool _ascii; + + Logger(this._dispatcher, this._compilationId, + {bool color = false, bool ascii = false}) + : _color = color, + _ascii = ascii; void debug(String message, SourceSpan span) { + var url = + span.start.sourceUrl == null ? '-' : p.prettyUri(span.start.sourceUrl); + var buffer = StringBuffer() + ..write('$url:${span.start.line + 1} ') + ..write(_color ? '\u001b[1mDebug\u001b[0m' : 'DEBUG') + ..writeln(': $message'); + _dispatcher.sendLog(OutboundMessage_LogEvent() ..compilationId = _compilationId ..type = OutboundMessage_LogEvent_Type.DEBUG ..message = message - ..span = protofySpan(span)); + ..span = protofySpan(span) + ..formatted = buffer.toString()); } void warn(String message, {FileSpan span, Trace trace, bool deprecation = false}) { + var formatted = withGlyphs(() { + var buffer = new StringBuffer(); + if (_color) { + buffer.write('\u001b[33m\u001b[1m'); + if (deprecation) buffer.write('Deprecation '); + buffer.write('Warning\u001b[0m'); + } else { + if (deprecation) buffer.write('DEPRECATION '); + buffer.write('WARNING'); + } + if (span == null) { + buffer.writeln(': $message'); + } else if (trace != null) { + buffer.writeln(': $message\n\n${span.highlight(color: _color)}'); + } else { + buffer.writeln(' on ${span.message("\n" + message, color: _color)}'); + } + if (trace != null) { + buffer.writeln(indent(trace.toString().trimRight(), 4)); + } + return buffer.toString(); + }, ascii: _ascii); + var event = OutboundMessage_LogEvent() ..compilationId = _compilationId ..type = deprecation ? OutboundMessage_LogEvent_Type.DEPRECATION_WARNING : OutboundMessage_LogEvent_Type.WARNING - ..message = message; + ..message = message + ..formatted = formatted; if (span != null) event.span = protofySpan(span); if (trace != null) event.stackTrace = trace.toString(); _dispatcher.sendLog(event); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index d89c27d08..a74e19a9c 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,8 +2,10 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:meta/meta.dart'; import 'package:sass/sass.dart' as sass; import 'package:source_span/source_span.dart'; +import 'package:term_glyph/term_glyph.dart' as term_glyph; import 'embedded_sass.pb.dart' as proto; import 'embedded_sass.pb.dart' hide SourceSpan; @@ -57,3 +59,17 @@ sass.Syntax syntaxToSyntax(InboundMessage_Syntax syntax) { throw "Unknown syntax $syntax."; } } + +/// Returns [string] with every line indented [indentation] spaces. +String indent(String string, int indentation) => + string.split("\n").map((line) => (" " * indentation) + line).join("\n"); + +/// Returns the result of running [callback] with the global ASCII config set +/// to [ascii]. +T withGlyphs(T callback(), {@required bool ascii}) { + var currentConfig = term_glyph.ascii; + term_glyph.ascii = ascii; + var result = callback(); + term_glyph.ascii = currentConfig; + return result; +} diff --git a/test/protocol_test.dart b/test/protocol_test.dart index f517c1a5a..dd839b573 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -97,22 +97,6 @@ void main() { await expectLater(process.outbound, emits(isSuccess(equals("a{b:3px}")))); await process.kill(); }); - - test("expanded mode when nested mode is passed", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - style: InboundMessage_CompileRequest_OutputStyle.NESTED)); - await expectLater( - process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); - await process.kill(); - }); - - test("expanded mode when compact mode is passed", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - style: InboundMessage_CompileRequest_OutputStyle.COMPACT)); - await expectLater( - process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); - await process.kill(); - }); }); test("doesn't include a source map by default", () async { @@ -145,31 +129,74 @@ void main() { }); group("emits a log event", () { - test("for a @debug rule", () async { - process.inbound.add(compileString("a {@debug hello}")); + group("for a @debug rule", () { + test("with correct fields", () async { + process.inbound.add(compileString("a {@debug hello}")); + + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(0)); + expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.DEBUG)); + expect(logEvent.message, equals("hello")); + expect(logEvent.span.text, equals("@debug hello")); + expect(logEvent.span.start, equals(location(3, 0, 3))); + expect(logEvent.span.end, equals(location(15, 0, 15))); + expect(logEvent.span.context, equals("a {@debug hello}")); + expect(logEvent.stackTrace, isEmpty); + expect(logEvent.formatted, equals('-:1 DEBUG: hello\n')); + await process.kill(); + }); - var logEvent = getLogEvent(await process.outbound.next); - expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.DEBUG)); - expect(logEvent.message, equals("hello")); - expect(logEvent.span.text, equals("@debug hello")); - expect(logEvent.span.start, equals(location(3, 0, 3))); - expect(logEvent.span.end, equals(location(15, 0, 15))); - expect(logEvent.span.context, equals("a {@debug hello}")); - expect(logEvent.stackTrace, isEmpty); - await process.kill(); + test("formatted with terminal colors", () async { + process.inbound + .add(compileString("a {@debug hello}", alertColor: true)); + var logEvent = getLogEvent(await process.outbound.next); + expect( + logEvent.formatted, equals('-:1 \u001b[1mDebug\u001b[0m: hello\n')); + await process.kill(); + }); }); - test("for a @warn rule", () async { - process.inbound.add(compileString("a {@warn hello}")); + group("for a @warn rule", () { + test("with correct fields", () async { + process.inbound.add(compileString("a {@warn hello}")); - var logEvent = getLogEvent(await process.outbound.next); - expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.WARNING)); - expect(logEvent.message, equals("hello")); - expect(logEvent.span, equals(SourceSpan())); - expect(logEvent.stackTrace, equals("- 1:4 root stylesheet\n")); - await process.kill(); + var logEvent = getLogEvent(await process.outbound.next); + expect(logEvent.compilationId, equals(0)); + expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.WARNING)); + expect(logEvent.message, equals("hello")); + expect(logEvent.span, equals(SourceSpan())); + expect(logEvent.stackTrace, equals("- 1:4 root stylesheet\n")); + expect( + logEvent.formatted, + equals('WARNING: hello\n' + ' - 1:4 root stylesheet\n')); + await process.kill(); + }); + + test("formatted with terminal colors", () async { + process.inbound.add(compileString("a {@warn hello}", alertColor: true)); + var logEvent = getLogEvent(await process.outbound.next); + expect( + logEvent.formatted, + equals('\x1B[33m\x1B[1mWarning\x1B[0m: hello\n' + ' - 1:4 root stylesheet\n')); + await process.kill(); + }); + + test("encoded in ASCII", () async { + process.inbound + .add(compileString("a {@debug a && b}", alertAscii: true)); + var logEvent = getLogEvent(await process.outbound.next); + expect( + logEvent.formatted, + equals('WARNING on line 1, column 13: \n' + 'In Sass, "&&" means two copies of the parent selector. You probably want to use "and" instead.\n' + ' ,\n' + '1 | a {@debug a && b}\n' + ' | ^^\n' + ' \'\n')); + await process.kill(); + }); }); test("for a parse-time deprecation warning", () async { @@ -343,5 +370,54 @@ a { expect(failure.stackTrace, equals("- 1:11 root stylesheet\n")); await process.kill(); }); + + group("and provides a formatted", () { + test("message", () async { + process.inbound.add(compileString("a {b: 1px + 1em}")); + + var failure = getCompileFailure(await process.outbound.next); + expect( + failure.formatted, + equals('Error: 1px and 1em have incompatible units.\n' + ' ╷\n' + '1 │ a {b: 1px + 1em}\n' + ' │ ^^^^^^^^^\n' + ' ╵\n' + ' - 1:7 root stylesheet')); + await process.kill(); + }); + + test("message with terminal colors", () async { + process.inbound + .add(compileString("a {b: 1px + 1em}", alertColor: true)); + + var failure = getCompileFailure(await process.outbound.next); + expect( + failure.formatted, + equals('Error: 1px and 1em have incompatible units.\n' + '\x1B[34m ╷\x1B[0m\n' + '\x1B[34m1 │\x1B[0m a {b: \x1B[31m1px + 1em\x1B[0m}\n' + '\x1B[34m │\x1B[0m \x1B[31m ^^^^^^^^^\x1B[0m\n' + '\x1B[34m ╵\x1B[0m\n' + ' - 1:7 root stylesheet')); + await process.kill(); + }); + + test("message with ASCII encoding", () async { + process.inbound + .add(compileString("a {b: 1px + 1em}", alertAscii: true)); + + var failure = getCompileFailure(await process.outbound.next); + expect( + failure.formatted, + equals('Error: 1px and 1em have incompatible units.\n' + ' ,\n' + '1 | a {b: 1px + 1em}\n' + ' | ^^^^^^^^^\n' + ' \'\n' + ' - 1:7 root stylesheet')); + await process.kill(); + }); + }); }); } diff --git a/test/utils.dart b/test/utils.dart index d915266a3..6a2823248 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -14,6 +14,8 @@ import 'embedded_process.dart'; /// string. InboundMessage compileString(String css, {int id, + bool alertColor, + bool alertAscii, InboundMessage_Syntax syntax, InboundMessage_CompileRequest_OutputStyle style, String url, @@ -32,6 +34,8 @@ InboundMessage compileString(String css, if (style != null) request.style = style; if (sourceMap != null) request.sourceMap = sourceMap; if (functions != null) request.globalFunctions.addAll(functions); + if (alertColor != null) request.alertColor = alertColor; + if (alertAscii != null) request.alertAscii = alertAscii; return InboundMessage()..compileRequest = request; } From 84eff0a8eaf9ecf72e250b30c6d1bceb63bf7ba0 Mon Sep 17 00:00:00 2001 From: Awjin Ahn Date: Wed, 24 Feb 2021 16:36:26 -0600 Subject: [PATCH 040/162] Release 1.0.0-beta.7 (#36) --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e97511ba0..7202a2605 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.6 +version: 1.0.0-beta.7 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 54d067e26757726a2678070f25e761a1bf670323 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 3 Mar 2021 19:25:28 +0100 Subject: [PATCH 041/162] Use the official setup-dart action (#37) --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54633c866..811a405b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,8 @@ jobs: - uses: actions/checkout@v2 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: cedx/setup-dart@v2 - with: {release-channel: "${{ matrix.dart_channel }}"} + - uses: dart-lang/setup-dart@v1 + with: {sdk: "${{ matrix.dart_channel }}"} - run: dart pub get - run: dart pub run grinder protobuf - run: dart pub run grinder pkg-standalone-dev @@ -41,7 +41,7 @@ jobs: - uses: actions/checkout@v2 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: cedx/setup-dart@v2 + - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart pub run grinder protobuf - name: Analyze dart @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v2 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: cedx/setup-dart@v2 + - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart pub run grinder protobuf - name: Deploy @@ -74,7 +74,7 @@ jobs: - uses: actions/checkout@v2 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: cedx/setup-dart@v2 + - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart pub run grinder protobuf - name: Deploy @@ -91,7 +91,7 @@ jobs: - uses: actions/checkout@v2 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: cedx/setup-dart@v2 + - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart pub run grinder protobuf - name: Deploy From 93bc86f97a47c3ae521dd555a8f9b09647e6f471 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 17 May 2021 20:57:37 -0700 Subject: [PATCH 042/162] Support non-nullability (#40) --- CHANGELOG.md | 3 +++ bin/dart_sass_embedded.dart | 22 +++++++++---------- lib/src/dispatcher.dart | 8 +++---- lib/src/function_registry.dart | 2 +- lib/src/host_callable.dart | 7 ++---- lib/src/importer.dart | 13 ++--------- lib/src/logger.dart | 4 ++-- .../util/length_delimited_transformer.dart | 21 +++++++++--------- lib/src/utils.dart | 3 +-- lib/src/value.dart | 5 ----- pubspec.yaml | 14 ++++++------ test/embedded_process.dart | 17 ++++++++------ test/function_test.dart | 6 ++--- test/importer_test.dart | 6 ++--- test/length_delimited_test.dart | 8 +++---- test/protocol_test.dart | 4 ++-- test/utils.dart | 20 ++++++++--------- tool/grind.dart | 4 ++-- 18 files changed, 77 insertions(+), 90 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..a2571cbb1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0-beta.8 + +* Internal changes only. diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index d431ac14a..d073441db 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -39,13 +39,12 @@ void main(List args) { request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED ? sass.OutputStyle.compressed : sass.OutputStyle.expanded; - var color = request.alertColor ?? false; - var ascii = request.alertAscii ?? false; - var logger = Logger(dispatcher, request.id, color: color, ascii: ascii); + var logger = Logger(dispatcher, request.id, + color: request.alertColor, ascii: request.alertAscii); try { String result; - source_maps.SingleMapping sourceMap; + source_maps.SingleMapping? sourceMap; var sourceMapCallback = request.sourceMap ? (source_maps.SingleMapping map) => sourceMap = map : null; @@ -61,7 +60,7 @@ void main(List args) { case InboundMessage_CompileRequest_Input.string: var input = request.string; result = sass.compileString(input.source, - color: color, + color: request.alertColor, logger: logger, importers: importers, importer: _decodeImporter(dispatcher, request, input.importer), @@ -75,7 +74,7 @@ void main(List args) { case InboundMessage_CompileRequest_Input.path: try { result = sass.compile(request.path, - color: color, + color: request.alertColor, logger: logger, importers: importers, functions: globalFunctions, @@ -97,11 +96,13 @@ void main(List args) { var success = OutboundMessage_CompileResponse_CompileSuccess() ..css = result; if (sourceMap != null) { - success.sourceMap = json.encode(sourceMap.toJson()); + // dart-lang/language#1536 + success.sourceMap = json.encode(sourceMap!.toJson()); } return OutboundMessage_CompileResponse()..success = success; } on sass.SassException catch (error) { - var formatted = withGlyphs(() => error.toString(color: color), + var formatted = withGlyphs( + () => error.toString(color: request.alertColor), ascii: request.alertAscii); return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() @@ -114,7 +115,7 @@ void main(List args) { } /// Converts [importer] into an [Importer]. -sass.Importer _decodeImporter( +sass.Importer? _decodeImporter( Dispatcher dispatcher, InboundMessage_CompileRequest request, InboundMessage_CompileRequest_Importer importer) { @@ -131,7 +132,4 @@ sass.Importer _decodeImporter( case InboundMessage_CompileRequest_Importer_Importer.notSet: return null; } - - // dart-lang/sdk#38790 - throw "Unknown Importer.importer $importer."; } diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index fcbd814bb..11e87c387 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -23,7 +23,7 @@ class Dispatcher { /// The completers are located at indexes in this list matching the request /// IDs. `null` elements indicate IDs whose requests have been responded to, /// and which are therefore free to re-use. - final _outstandingRequests = >[]; + final _outstandingRequests = ?>[]; /// Creates a [Dispatcher] that sends and receives encoded protocol buffers /// over [channel]. @@ -47,7 +47,7 @@ class Dispatcher { // for new input. await Future.value(); - InboundMessage message; + InboundMessage? message; try { try { message = InboundMessage.fromBuffer(binaryMessage); @@ -182,7 +182,7 @@ class Dispatcher { /// Returns the id for [message] if it it's a request, or `null` /// otherwise. - int _inboundId(InboundMessage message) { + int? _inboundId(InboundMessage? message) { if (message == null) return null; switch (message.whichMessage()) { case InboundMessage_Message.compileRequest: @@ -210,7 +210,7 @@ class Dispatcher { message.functionCallRequest.id = id; break; default: - return null; + break; } } } diff --git a/lib/src/function_registry.dart b/lib/src/function_registry.dart index 79b0cacce..1cfd69a05 100644 --- a/lib/src/function_registry.dart +++ b/lib/src/function_registry.dart @@ -29,5 +29,5 @@ class FunctionRegistry { /// Returns the compiler-side function associated with [id]. /// /// If no such function exists, returns `null`. - sass.SassFunction operator [](int id) => _functionsById[id]; + sass.SassFunction? operator [](int id) => _functionsById[id]; } diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index e3990aaf7..bb567d419 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -23,7 +23,7 @@ import 'value.dart'; /// Throws a [ProtocolError] if [signature] is invalid. sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, int compilationId, String signature, - {int id}) { + {int? id}) { var openParen = signature.indexOf('('); if (openParen == -1) { throw paramsError( @@ -38,7 +38,7 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, var name = signature.substring(0, openParen); try { - return sass.Callable( + return sass.Callable.function( name, signature.substring(openParen + 1, signature.length - 1), (arguments) { var request = OutboundMessage_FunctionCallRequest() @@ -66,9 +66,6 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, case InboundMessage_FunctionCallResponse_Result.notSet: throw mandatoryError('FunctionCallResponse.result'); } - - // dart-lang/sdk#38790 - throw "Unknown FunctionCallResponse.result $response."; } on ProtocolError catch (error) { error.id = errorId; stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " diff --git a/lib/src/importer.dart b/lib/src/importer.dart index 4b6d9d4ec..7e871482c 100644 --- a/lib/src/importer.dart +++ b/lib/src/importer.dart @@ -4,7 +4,6 @@ import 'dart:cli'; -import 'package:meta/meta.dart'; import 'package:sass/sass.dart' as sass; import 'dispatcher.dart'; @@ -24,7 +23,7 @@ class Importer extends sass.Importer { Importer(this._dispatcher, this._compilationId, this._importerId); - Uri canonicalize(Uri url) { + Uri? canonicalize(Uri url) { return waitFor(() async { var response = await _dispatcher .sendCanonicalizeRequest(OutboundMessage_CanonicalizeRequest() @@ -42,9 +41,6 @@ class Importer extends sass.Importer { case InboundMessage_CanonicalizeResponse_Result.notSet: return null; } - - // dart-lang/sdk#38790 - throw "Unknown CanonicalizeResponse.result $response."; }()); } @@ -70,11 +66,7 @@ class Importer extends sass.Importer { case InboundMessage_ImportResponse_Result.notSet: _sendAndThrow(mandatoryError("ImportResponse.result")); - break; // dart-lang/sdk#34048 } - - // dart-lang/sdk#38790 - throw "Unknown ImporterResponse.result $response."; }()); } @@ -96,8 +88,7 @@ class Importer extends sass.Importer { /// Sends [error] to the remote endpoint, and also throws it so that the Sass /// compilation fails. - @alwaysThrows - void _sendAndThrow(ProtocolError error) { + Never _sendAndThrow(ProtocolError error) { _dispatcher.sendError(error); throw "Protocol error: ${error.message}"; } diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 06b82fb3f..566c0a2ab 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -47,9 +47,9 @@ class Logger implements sass.Logger { } void warn(String message, - {FileSpan span, Trace trace, bool deprecation = false}) { + {FileSpan? span, Trace? trace, bool deprecation = false}) { var formatted = withGlyphs(() { - var buffer = new StringBuffer(); + var buffer = StringBuffer(); if (_color) { buffer.write('\u001b[33m\u001b[1m'); if (deprecation) buffer.write('Deprecation '); diff --git a/lib/src/util/length_delimited_transformer.dart b/lib/src/util/length_delimited_transformer.dart index aba63ab7f..20bc33c98 100644 --- a/lib/src/util/length_delimited_transformer.dart +++ b/lib/src/util/length_delimited_transformer.dart @@ -23,7 +23,7 @@ final StreamChannelTransformer> lengthDelimited = final lengthDelimitedDecoder = StreamTransformer, Uint8List>.fromBind((stream) { // The number of bits we've consumed so far to fill out [nextMessageLength]. - int nextMessageLengthBits = 0; + var nextMessageLengthBits = 0; // The length of the next message, in bytes. // @@ -31,16 +31,16 @@ final lengthDelimitedDecoder = // initialized. // // [varint]: https://developers.google.com/protocol-buffers/docs/encoding#varints - int nextMessageLength = 0; + var nextMessageLength = 0; // The buffer into which the packet data itself is written. Initialized once // [nextMessageLength] is known. - Uint8List buffer; + Uint8List? buffer; // The index of the next byte to write to [buffer]. Once this is equal to // [buffer.length] (or equivalently [nextMessageLength]), the full packet is // available. - int bufferIndex; + var bufferIndex = 0; // It seems a little silly to use a nested [StreamTransformer] here, but we // need the outer one to establish a closure context so we can share state @@ -54,6 +54,8 @@ final lengthDelimitedDecoder = var i = 0; while (i < chunk.length) { + var buffer_ = buffer; // dart-lang/language#1536 + // We can be in one of two states here: // // * [buffer] is `null`, in which case we're adding data to @@ -63,7 +65,7 @@ final lengthDelimitedDecoder = // * [buffer] is not `null`, in which case we're waiting for [buffer] to // have [nextMessageLength] bytes in it before we send it to // [queue.local.sink] and start waiting for the next message. - if (buffer == null) { + if (buffer_ == null) { var byte = chunk[i]; // Varints encode data in the 7 lower bits of each byte, which we access @@ -79,7 +81,7 @@ final lengthDelimitedDecoder = // Otherwise, [nextMessageLength] is now finalized and we can allocate // the data buffer. - buffer = Uint8List(nextMessageLength); + buffer_ = buffer = Uint8List(nextMessageLength); bufferIndex = 0; } @@ -88,18 +90,17 @@ final lengthDelimitedDecoder = // message after the current one) or more than the chunk has available (if // the current message is split across multiple chunks). var bytesToWrite = - math.min(buffer.length - bufferIndex, chunk.length - i); - buffer.setRange(bufferIndex, bufferIndex + bytesToWrite, chunk, i); + math.min(buffer_.length - bufferIndex, chunk.length - i); + buffer_.setRange(bufferIndex, bufferIndex + bytesToWrite, chunk, i); i += bytesToWrite; bufferIndex += bytesToWrite; if (bufferIndex < nextMessageLength) return; // Once we've filled the buffer, emit it and reset our state. - sink.add(buffer); + sink.add(buffer_); nextMessageLength = 0; nextMessageLengthBits = 0; buffer = null; - bufferIndex = null; } })); }); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index a74e19a9c..dbd547c8a 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,7 +2,6 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'package:meta/meta.dart'; import 'package:sass/sass.dart' as sass; import 'package:source_span/source_span.dart'; import 'package:term_glyph/term_glyph.dart' as term_glyph; @@ -66,7 +65,7 @@ String indent(String string, int indentation) => /// Returns the result of running [callback] with the global ASCII config set /// to [ascii]. -T withGlyphs(T callback(), {@required bool ascii}) { +T withGlyphs(T callback(), {required bool ascii}) { var currentConfig = term_glyph.ascii; term_glyph.ascii = ascii; var result = callback(); diff --git a/lib/src/value.dart b/lib/src/value.dart index 065a2fcb8..6c286ecae 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -166,15 +166,10 @@ sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, default: throw "Unknown Value.singleton ${value.singleton}"; } - // dart-lang/sdk#39304 - throw "Unreachable"; // ignore: dead_code case Value_Value.notSet: throw mandatoryError("Value.value"); } - - // dart-lang/sdk#38790 - throw "Unknown Value.value $value."; } /// Converts [separator] to its Sass representation. diff --git a/pubspec.yaml b/pubspec.yaml index 7202a2605..28765ef44 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: sass_embedded -version: 1.0.0-beta.7 +version: 1.0.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded environment: - sdk: '>=2.10.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' executables: dart-sass-embedded: dart_sass_embedded @@ -13,8 +13,8 @@ executables: dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 - protobuf: ^1.0.0 - sass: ^1.21.0 + protobuf: ^2.0.0 + sass: ^1.25.0 source_maps: ^0.10.5 source_span: ^1.1.0 stack_trace: ^1.6.0 @@ -23,8 +23,8 @@ dependencies: dev_dependencies: cli_pkg: ^1.2.0 - grinder: ^0.8.0 - protoc_plugin: ^19.0.0 + grinder: ^0.9.0 + protoc_plugin: ^20.0.0 path: ^1.6.0 test: ^1.0.0 - test_descriptor: ^1.0.0 + test_descriptor: ^2.0.0 diff --git a/test/embedded_process.dart b/test/embedded_process.dart index 9919992e7..75ca7897f 100644 --- a/test/embedded_process.dart +++ b/test/embedded_process.dart @@ -26,11 +26,11 @@ class EmbeddedProcess { /// A [StreamQueue] that emits each outbound protocol buffer from the process. StreamQueue get outbound => _outbound; - StreamQueue _outbound; + late StreamQueue _outbound; /// A [StreamQueue] that emits each line of stderr from the process. StreamQueue get stderr => _stderr; - StreamQueue _stderr; + late StreamQueue _stderr; /// A splitter that can emit new copies of [outbound]. final StreamSplitter _outboundSplitter; @@ -49,7 +49,7 @@ class EmbeddedProcess { final _log = []; /// Whether [_log] has been passed to [printOnFailure] yet. - bool _loggedOutput = false; + var _loggedOutput = false; /// Returns a [Future] which completes to the exit code of the process, once /// it completes. @@ -60,8 +60,11 @@ class EmbeddedProcess { /// Completes to [_process]'s exit code if it's exited, otherwise completes to /// `null` immediately. - Future get _exitCodeOrNull async => - await exitCode.timeout(Duration.zero, onTimeout: () => null); + Future get _exitCodeOrNull async { + var exitCode = + await this.exitCode.timeout(Duration.zero, onTimeout: () => -1); + return exitCode == -1 ? null : exitCode; + } /// Starts a process. /// @@ -73,8 +76,8 @@ class EmbeddedProcess { /// [stderr] will be printed to the console as they appear. This is only /// intended to be set temporarily to help when debugging test failures. static Future start( - {String workingDirectory, - Map environment, + {String? workingDirectory, + Map? environment, bool includeParentEnvironment = true, bool runInShell = false, bool forwardOutput = false}) async { diff --git a/test/function_test.dart b/test/function_test.dart index fd5e3dd97..349352eae 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -14,7 +14,7 @@ final _true = Value()..singleton = Value_Singleton.TRUE; final _false = Value()..singleton = Value_Singleton.FALSE; final _null = Value()..singleton = Value_Singleton.NULL; -EmbeddedProcess _process; +late EmbeddedProcess _process; void main() { setUp(() async { @@ -67,7 +67,7 @@ void main() { group("includes in FunctionCallRequest", () { var compilationId = 1234; - OutboundMessage_FunctionCallRequest request; + late OutboundMessage_FunctionCallRequest request; setUp(() async { _process.inbound.add(compileString("a {b: foo()}", id: compilationId, functions: ["foo()"])); @@ -1232,7 +1232,7 @@ Future _deprotofy(Value value, {bool inspect = false}) async { var success = await getCompileSuccess(await _process.outbound.next); expect(_process.kill(), completes); - return RegExp(r" b: (.*);").firstMatch(success.css)[1]; + return RegExp(r" b: (.*);").firstMatch(success.css)![1]!; } /// Asserts that [value] causes a parameter error with a message matching diff --git a/test/importer_test.dart b/test/importer_test.dart index f60c7607b..42688095d 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -13,7 +13,7 @@ import 'embedded_process.dart'; import 'utils.dart'; void main() { - EmbeddedProcess process; + late EmbeddedProcess process; setUp(() async { process = await EmbeddedProcess.start(); }); @@ -101,7 +101,7 @@ void main() { group("includes in CanonicalizeRequest", () { var compilationId = 1234; var importerId = 5679; - OutboundMessage_CanonicalizeRequest request; + late OutboundMessage_CanonicalizeRequest request; setUp(() async { process.inbound.add(compileString("@import 'other'", id: compilationId, @@ -256,7 +256,7 @@ void main() { group("includes in ImportRequest", () { var compilationId = 1234; var importerId = 5678; - OutboundMessage_ImportRequest request; + late OutboundMessage_ImportRequest request; setUp(() async { process.inbound.add(compileString("@import 'other'", id: compilationId, diff --git a/test/length_delimited_test.dart b/test/length_delimited_test.dart index 1fc831821..38c247b8c 100644 --- a/test/length_delimited_test.dart +++ b/test/length_delimited_test.dart @@ -12,8 +12,8 @@ import 'package:test/test.dart'; void main() { group("encoder", () { - Sink> sink; - Stream> stream; + late Sink> sink; + late Stream> stream; setUp(() { var controller = StreamController>(); sink = controller.sink; @@ -52,8 +52,8 @@ void main() { }); group("decoder", () { - Sink> sink; - StreamQueue queue; + late Sink> sink; + late StreamQueue queue; setUp(() { var controller = StreamController>(); sink = controller.sink; diff --git a/test/protocol_test.dart b/test/protocol_test.dart index dd839b573..9b3ab4835 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -13,7 +13,7 @@ import 'embedded_process.dart'; import 'utils.dart'; void main() { - EmbeddedProcess process; + late EmbeddedProcess process; setUp(() async { process = await EmbeddedProcess.start(); }); @@ -119,7 +119,7 @@ void main() { process.outbound, emits(isSuccess("a { b: 3px; }", sourceMap: (map) { var mapping = source_maps.parse(map); - var span = mapping.spanFor(2, 5); + var span = mapping.spanFor(2, 5)!; expect(span.start.line, equals(0)); expect(span.start.column, equals(3)); expect(span.end, equals(span.start)); diff --git a/test/utils.dart b/test/utils.dart index 6a2823248..e3fe8e087 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -13,16 +13,16 @@ import 'embedded_process.dart'; /// Returns a [InboundMessage] that compiles the given plain CSS /// string. InboundMessage compileString(String css, - {int id, - bool alertColor, - bool alertAscii, - InboundMessage_Syntax syntax, - InboundMessage_CompileRequest_OutputStyle style, - String url, - bool sourceMap, - Iterable importers, - InboundMessage_CompileRequest_Importer importer, - Iterable functions}) { + {int? id, + bool? alertColor, + bool? alertAscii, + InboundMessage_Syntax? syntax, + InboundMessage_CompileRequest_OutputStyle? style, + String? url, + bool? sourceMap, + Iterable? importers, + InboundMessage_CompileRequest_Importer? importer, + Iterable? functions}) { var input = InboundMessage_CompileRequest_StringInput()..source = css; if (syntax != null) input.syntax = syntax; if (url != null) input.url = url; diff --git a/tool/grind.dart b/tool/grind.dart index 4cb59a20f..2247a2c55 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -10,7 +10,7 @@ import 'package:grinder/grinder.dart'; import 'utils.dart'; main(List args) { - pkg.githubBearerToken.value = Platform.environment["GH_BEARER_TOKEN"]; + pkg.githubBearerToken.fn = () => Platform.environment["GH_BEARER_TOKEN"]!; pkg.addGithubTasks(); grind(args); @@ -44,6 +44,6 @@ dart pub run protoc_plugin %* runOptions: RunOptions(environment: { "PATH": 'build' + (Platform.isWindows ? ";" : ":") + - Platform.environment["PATH"] + Platform.environment["PATH"]! })); } From 32575970e3ca20f1edd77adf53442d99a39f1fe2 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 24 May 2021 16:43:30 -0700 Subject: [PATCH 043/162] Avoid /-as-division deprecation warnings --- test/function_test.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/function_test.dart b/test/function_test.dart index 349352eae..f3b23cd2e 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -333,21 +333,24 @@ void main() { }); test("with one denominator", () async { - var value = (await _protofy('1/1em')).number; + var value = (await _protofy('math.div(1,1em)')).number; expect(value.value, equals(1.0)); expect(value.numerators, isEmpty); expect(value.denominators, ["em"]); }); test("with multiple denominators", () async { - var value = (await _protofy('1/1em/1px/1foo')).number; + var value = + (await _protofy('math.div(math.div(math.div(1, 1em), 1px), 1foo)')) + .number; expect(value.value, equals(1.0)); expect(value.numerators, isEmpty); expect(value.denominators, unorderedEquals(["em", "px", "foo"])); }); test("with numerators and denominators", () async { - var value = (await _protofy('1em * 1px/1s/1foo')).number; + var value = + (await _protofy('1em * math.div(math.div(1px, 1s), 1foo)')).number; expect(value.value, equals(1.0)); expect(value.numerators, unorderedEquals(["em", "px"])); expect(value.denominators, unorderedEquals(["s", "foo"])); @@ -1192,6 +1195,7 @@ Future _protofy(String sassScript) async { _process.inbound.add(compileString(""" @use 'sass:list'; @use 'sass:map'; +@use 'sass:math'; \$_: foo(($sassScript)); """, functions: [r"foo($arg)"])); From 49ef4c11218908a8bc4c24246091d335c9ff3107 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 24 May 2021 16:46:34 -0700 Subject: [PATCH 044/162] Use the new enum names in the latest protocol version --- bin/dart_sass_embedded.dart | 2 +- lib/src/dispatcher.dart | 4 +-- lib/src/logger.dart | 6 ++-- lib/src/utils.dart | 10 +++--- lib/src/value.dart | 28 +++++++-------- test/function_test.dart | 72 ++++++++++++++++++------------------- test/importer_test.dart | 6 ++-- test/protocol_test.dart | 20 +++++------ test/utils.dart | 10 +++--- 9 files changed, 79 insertions(+), 79 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index d073441db..1bf5a1895 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -36,7 +36,7 @@ void main(List args) { var functions = FunctionRegistry(); var style = - request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED + request.style == OutputStyle.COMPRESSED ? sass.OutputStyle.compressed : sass.OutputStyle.expanded; var logger = Logger(dispatcher, request.id, diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 11e87c387..706b44409 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -98,7 +98,7 @@ class Dispatcher { var errorMessage = "$error\n${Chain.forTrace(stackTrace)}"; stderr.write("Internal compiler error: $errorMessage"); sendError(ProtocolError() - ..type = ProtocolError_ErrorType.INTERNAL + ..type = ProtocolErrorType.INTERNAL ..id = _inboundId(message) ?? errorId ..message = errorMessage); _channel.sink.close(); @@ -177,7 +177,7 @@ class Dispatcher { /// Returns a [ProtocolError] with type `PARSE` and the given [message]. ProtocolError _parseError(String message) => ProtocolError() - ..type = ProtocolError_ErrorType.PARSE + ..type = ProtocolErrorType.PARSE ..message = message; /// Returns the id for [message] if it it's a request, or `null` diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 566c0a2ab..bac6d86ad 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -40,7 +40,7 @@ class Logger implements sass.Logger { _dispatcher.sendLog(OutboundMessage_LogEvent() ..compilationId = _compilationId - ..type = OutboundMessage_LogEvent_Type.DEBUG + ..type = LogEventType.DEBUG ..message = message ..span = protofySpan(span) ..formatted = buffer.toString()); @@ -74,8 +74,8 @@ class Logger implements sass.Logger { var event = OutboundMessage_LogEvent() ..compilationId = _compilationId ..type = deprecation - ? OutboundMessage_LogEvent_Type.DEPRECATION_WARNING - : OutboundMessage_LogEvent_Type.WARNING + ? LogEventType.DEPRECATION_WARNING + : LogEventType.WARNING ..message = message ..formatted = formatted; if (span != null) event.span = protofySpan(span); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index dbd547c8a..4f2b2059b 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -24,7 +24,7 @@ ProtocolError paramsError(String message) => ProtocolError() // Set the ID to [errorId] by default. This will be overwritten by the // dispatcher if a request ID is available. ..id = errorId - ..type = ProtocolError_ErrorType.PARAMS + ..type = ProtocolErrorType.PARAMS ..message = message; /// Converts a Dart source span to a protocol buffer source span. @@ -46,13 +46,13 @@ SourceSpan_SourceLocation _protofyLocation(SourceLocation location) => ..column = location.column; /// Converts a protocol buffer syntax enum into a Sass API syntax enum. -sass.Syntax syntaxToSyntax(InboundMessage_Syntax syntax) { +sass.Syntax syntaxToSyntax(Syntax syntax) { switch (syntax) { - case InboundMessage_Syntax.SCSS: + case Syntax.SCSS: return sass.Syntax.scss; - case InboundMessage_Syntax.INDENTED: + case Syntax.INDENTED: return sass.Syntax.sass; - case InboundMessage_Syntax.CSS: + case Syntax.CSS: return sass.Syntax.css; default: throw "Unknown syntax $syntax."; diff --git a/lib/src/value.dart b/lib/src/value.dart index 6c286ecae..5c8c1a2d7 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -52,11 +52,11 @@ Value protofyValue(FunctionRegistry functions, sass.Value value) { } else if (value is sass.SassFunction) { result.compilerFunction = functions.protofy(value); } else if (value == sass.sassTrue) { - result.singleton = Value_Singleton.TRUE; + result.singleton = SingletonValue.TRUE; } else if (value == sass.sassFalse) { - result.singleton = Value_Singleton.FALSE; + result.singleton = SingletonValue.FALSE; } else if (value == sass.sassNull) { - result.singleton = Value_Singleton.NULL; + result.singleton = SingletonValue.NULL; } else { throw "Unknown Value $value"; } @@ -64,14 +64,14 @@ Value protofyValue(FunctionRegistry functions, sass.Value value) { } /// Converts [separator] to its protocol buffer representation. -Value_List_Separator _protofySeparator(sass.ListSeparator separator) { +ListSeparator _protofySeparator(sass.ListSeparator separator) { switch (separator) { case sass.ListSeparator.comma: - return Value_List_Separator.COMMA; + return ListSeparator.COMMA; case sass.ListSeparator.space: - return Value_List_Separator.SPACE; + return ListSeparator.SPACE; case sass.ListSeparator.undecided: - return Value_List_Separator.UNDECIDED; + return ListSeparator.UNDECIDED; default: throw "Unknown ListSeparator $separator"; } @@ -157,11 +157,11 @@ sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, case Value_Value.singleton: switch (value.singleton) { - case Value_Singleton.TRUE: + case SingletonValue.TRUE: return sass.sassTrue; - case Value_Singleton.FALSE: + case SingletonValue.FALSE: return sass.sassFalse; - case Value_Singleton.NULL: + case SingletonValue.NULL: return sass.sassNull; default: throw "Unknown Value.singleton ${value.singleton}"; @@ -173,13 +173,13 @@ sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, } /// Converts [separator] to its Sass representation. -sass.ListSeparator _deprotofySeparator(Value_List_Separator separator) { +sass.ListSeparator _deprotofySeparator(ListSeparator separator) { switch (separator) { - case Value_List_Separator.COMMA: + case ListSeparator.COMMA: return sass.ListSeparator.comma; - case Value_List_Separator.SPACE: + case ListSeparator.SPACE: return sass.ListSeparator.space; - case Value_List_Separator.UNDECIDED: + case ListSeparator.UNDECIDED: return sass.ListSeparator.undecided; default: throw "Unknown separator $separator"; diff --git a/test/function_test.dart b/test/function_test.dart index f3b23cd2e..cbcd77103 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -10,9 +10,9 @@ import 'package:sass_embedded/src/utils.dart'; import 'embedded_process.dart'; import 'utils.dart'; -final _true = Value()..singleton = Value_Singleton.TRUE; -final _false = Value()..singleton = Value_Singleton.FALSE; -final _null = Value()..singleton = Value_Singleton.NULL; +final _true = Value()..singleton = SingletonValue.TRUE; +final _false = Value()..singleton = SingletonValue.FALSE; +final _null = Value()..singleton = SingletonValue.NULL; late EmbeddedProcess _process; @@ -144,7 +144,7 @@ void main() { _true, Value() ..list = (Value_List() - ..separator = Value_List_Separator.COMMA + ..separator = ListSeparator.COMMA ..hasBrackets = false ..contents.addAll([_false, _null])) ])); @@ -479,7 +479,7 @@ void main() { var list = (await _protofy("[]")).list; expect(list.contents, isEmpty); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.UNDECIDED)); + expect(list.separator, equals(ListSeparator.UNDECIDED)); }); test("with a comma separator", () async { @@ -487,7 +487,7 @@ void main() { (await _protofy(r"list.join([], [], $separator: comma)")).list; expect(list.contents, isEmpty); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.COMMA)); + expect(list.separator, equals(ListSeparator.COMMA)); }); test("with a space separator", () async { @@ -495,7 +495,7 @@ void main() { (await _protofy(r"list.join([], [], $separator: space)")).list; expect(list.contents, isEmpty); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.SPACE)); + expect(list.separator, equals(ListSeparator.SPACE)); }); }); @@ -504,7 +504,7 @@ void main() { var list = (await _protofy("()")).list; expect(list.contents, isEmpty); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.UNDECIDED)); + expect(list.separator, equals(ListSeparator.UNDECIDED)); }); test("with a comma separator", () async { @@ -512,7 +512,7 @@ void main() { (await _protofy(r"list.join((), (), $separator: comma)")).list; expect(list.contents, isEmpty); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.COMMA)); + expect(list.separator, equals(ListSeparator.COMMA)); }); test("with a space separator", () async { @@ -520,7 +520,7 @@ void main() { (await _protofy(r"list.join((), (), $separator: space)")).list; expect(list.contents, isEmpty); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.SPACE)); + expect(list.separator, equals(ListSeparator.SPACE)); }); }); }); @@ -531,14 +531,14 @@ void main() { var list = (await _protofy("[true]")).list; expect(list.contents, equals([_true])); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.UNDECIDED)); + expect(list.separator, equals(ListSeparator.UNDECIDED)); }); test("with a comma separator", () async { var list = (await _protofy(r"[true,]")).list; expect(list.contents, equals([_true])); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.COMMA)); + expect(list.separator, equals(ListSeparator.COMMA)); }); test("with a space separator", () async { @@ -547,7 +547,7 @@ void main() { .list; expect(list.contents, equals([_true])); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.SPACE)); + expect(list.separator, equals(ListSeparator.SPACE)); }); }); @@ -556,7 +556,7 @@ void main() { var list = (await _protofy(r"(true,)")).list; expect(list.contents, equals([_true])); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.COMMA)); + expect(list.separator, equals(ListSeparator.COMMA)); }); test("with a space separator", () async { @@ -565,7 +565,7 @@ void main() { .list; expect(list.contents, equals([_true])); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.SPACE)); + expect(list.separator, equals(ListSeparator.SPACE)); }); }); }); @@ -576,14 +576,14 @@ void main() { var list = (await _protofy(r"[true, null, false]")).list; expect(list.contents, equals([_true, _null, _false])); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.COMMA)); + expect(list.separator, equals(ListSeparator.COMMA)); }); test("with a space separator", () async { var list = (await _protofy(r"[true null false]")).list; expect(list.contents, equals([_true, _null, _false])); expect(list.hasBrackets, isTrue); - expect(list.separator, equals(Value_List_Separator.SPACE)); + expect(list.separator, equals(ListSeparator.SPACE)); }); }); @@ -592,14 +592,14 @@ void main() { var list = (await _protofy(r"true, null, false")).list; expect(list.contents, equals([_true, _null, _false])); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.COMMA)); + expect(list.separator, equals(ListSeparator.COMMA)); }); test("with a space separator", () async { var list = (await _protofy(r"true null false")).list; expect(list.contents, equals([_true, _null, _false])); expect(list.hasBrackets, isFalse); - expect(list.separator, equals(Value_List_Separator.SPACE)); + expect(list.separator, equals(ListSeparator.SPACE)); }); }); }); @@ -874,7 +874,7 @@ void main() { Value() ..list = (Value_List() ..hasBrackets = true - ..separator = Value_List_Separator.UNDECIDED), + ..separator = ListSeparator.UNDECIDED), "[]"); }); @@ -883,7 +883,7 @@ void main() { Value() ..list = (Value_List() ..hasBrackets = true - ..separator = Value_List_Separator.COMMA), + ..separator = ListSeparator.COMMA), "[]"); }); @@ -892,7 +892,7 @@ void main() { Value() ..list = (Value_List() ..hasBrackets = true - ..separator = Value_List_Separator.SPACE), + ..separator = ListSeparator.SPACE), "[]"); }); }); @@ -903,7 +903,7 @@ void main() { Value() ..list = (Value_List() ..hasBrackets = false - ..separator = Value_List_Separator.UNDECIDED), + ..separator = ListSeparator.UNDECIDED), "()", inspect: true); }); @@ -913,7 +913,7 @@ void main() { Value() ..list = (Value_List() ..hasBrackets = false - ..separator = Value_List_Separator.COMMA), + ..separator = ListSeparator.COMMA), "()", inspect: true); }); @@ -923,7 +923,7 @@ void main() { Value() ..list = (Value_List() ..hasBrackets = false - ..separator = Value_List_Separator.SPACE), + ..separator = ListSeparator.SPACE), "()", inspect: true); }); @@ -938,7 +938,7 @@ void main() { ..list = (Value_List() ..contents.add(_true) ..hasBrackets = true - ..separator = Value_List_Separator.UNDECIDED), + ..separator = ListSeparator.UNDECIDED), "[true]"); }); @@ -949,7 +949,7 @@ void main() { ..list = (Value_List() ..contents.add(_true) ..hasBrackets = true - ..separator = Value_List_Separator.COMMA), + ..separator = ListSeparator.COMMA), inspect: true), "[true,]"); }); @@ -960,7 +960,7 @@ void main() { ..list = (Value_List() ..contents.add(_true) ..hasBrackets = true - ..separator = Value_List_Separator.SPACE), + ..separator = ListSeparator.SPACE), "[true]"); }); }); @@ -972,7 +972,7 @@ void main() { ..list = (Value_List() ..contents.add(_true) ..hasBrackets = false - ..separator = Value_List_Separator.UNDECIDED), + ..separator = ListSeparator.UNDECIDED), "true"); }); @@ -983,7 +983,7 @@ void main() { ..list = (Value_List() ..contents.add(_true) ..hasBrackets = false - ..separator = Value_List_Separator.COMMA), + ..separator = ListSeparator.COMMA), inspect: true), "(true,)"); }); @@ -994,7 +994,7 @@ void main() { ..list = (Value_List() ..contents.add(_true) ..hasBrackets = false - ..separator = Value_List_Separator.SPACE), + ..separator = ListSeparator.SPACE), "true"); }); }); @@ -1009,7 +1009,7 @@ void main() { ..list = (Value_List() ..contents.addAll([_true, _null, _false]) ..hasBrackets = true - ..separator = Value_List_Separator.COMMA), + ..separator = ListSeparator.COMMA), inspect: true), "[true, null, false]"); }); @@ -1021,7 +1021,7 @@ void main() { ..list = (Value_List() ..contents.addAll([_true, _null, _false]) ..hasBrackets = true - ..separator = Value_List_Separator.SPACE), + ..separator = ListSeparator.SPACE), inspect: true), "[true null false]"); }); @@ -1035,7 +1035,7 @@ void main() { ..list = (Value_List() ..contents.addAll([_true, _null, _false]) ..hasBrackets = false - ..separator = Value_List_Separator.COMMA), + ..separator = ListSeparator.COMMA), inspect: true), "true, null, false"); }); @@ -1047,7 +1047,7 @@ void main() { ..list = (Value_List() ..contents.addAll([_true, _null, _false]) ..hasBrackets = false - ..separator = Value_List_Separator.SPACE), + ..separator = ListSeparator.SPACE), inspect: true), "true null false"); }); @@ -1181,7 +1181,7 @@ void main() { Value() ..list = (Value_List() ..contents.addAll([_true, _false]) - ..separator = Value_List_Separator.UNDECIDED), + ..separator = ListSeparator.UNDECIDED), endsWith("can't have an undecided separator because it has 2 " "elements")); }); diff --git a/test/importer_test.dart b/test/importer_test.dart index 42688095d..ef4afdc44 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -337,7 +337,7 @@ void main() { ..id = request.id ..success = (InboundMessage_ImportResponse_ImportSuccess() ..contents = "a\n b: 1px + 2px" - ..syntax = InboundMessage_Syntax.INDENTED))); + ..syntax = Syntax.INDENTED))); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); @@ -355,7 +355,7 @@ void main() { ..id = request.id ..success = (InboundMessage_ImportResponse_ImportSuccess() ..contents = "a {b: c}" - ..syntax = InboundMessage_Syntax.CSS))); + ..syntax = Syntax.CSS))); await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); await process.kill(); @@ -506,7 +506,7 @@ Future _canonicalize(EmbeddedProcess process) async { /// [message] on its protobuf stream and causes the compilation to fail. Future _expectImportParamsError(EmbeddedProcess process, message) async { await expectLater(process.outbound, - emits(isProtocolError(errorId, ProtocolError_ErrorType.PARAMS, message))); + emits(isProtocolError(errorId, ProtocolErrorType.PARAMS, message))); var failure = getCompileFailure(await process.outbound.next); expect(failure.message, equals('Protocol error: $message')); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 9b3ab4835..b3f4393e3 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -42,21 +42,21 @@ void main() { test("an SCSS string explicitly", () async { process.inbound.add(compileString("a {b: 1px + 2px}", - syntax: InboundMessage_Syntax.SCSS)); + syntax: Syntax.SCSS)); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); }); test("an indented syntax string", () async { process.inbound.add(compileString("a\n b: 1px + 2px", - syntax: InboundMessage_Syntax.INDENTED)); + syntax: Syntax.INDENTED)); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); }); test("a plain CSS string", () async { process.inbound - .add(compileString("a {b: c}", syntax: InboundMessage_Syntax.CSS)); + .add(compileString("a {b: c}", syntax: Syntax.CSS)); await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); await process.kill(); }); @@ -85,7 +85,7 @@ void main() { group("compiles CSS in", () { test("expanded mode", () async { process.inbound.add(compileString("a {b: 1px + 2px}", - style: InboundMessage_CompileRequest_OutputStyle.EXPANDED)); + style: OutputStyle.EXPANDED)); await expectLater( process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); await process.kill(); @@ -93,7 +93,7 @@ void main() { test("compressed mode", () async { process.inbound.add(compileString("a {b: 1px + 2px}", - style: InboundMessage_CompileRequest_OutputStyle.COMPRESSED)); + style: OutputStyle.COMPRESSED)); await expectLater(process.outbound, emits(isSuccess(equals("a{b:3px}")))); await process.kill(); }); @@ -135,7 +135,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.DEBUG)); + expect(logEvent.type, equals(LogEventType.DEBUG)); expect(logEvent.message, equals("hello")); expect(logEvent.span.text, equals("@debug hello")); expect(logEvent.span.start, equals(location(3, 0, 3))); @@ -162,7 +162,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, equals(OutboundMessage_LogEvent_Type.WARNING)); + expect(logEvent.type, equals(LogEventType.WARNING)); expect(logEvent.message, equals("hello")); expect(logEvent.span, equals(SourceSpan())); expect(logEvent.stackTrace, equals("- 1:4 root stylesheet\n")); @@ -205,7 +205,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); expect(logEvent.type, - equals(OutboundMessage_LogEvent_Type.DEPRECATION_WARNING)); + equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, equals( @@ -226,7 +226,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); expect(logEvent.type, - equals(OutboundMessage_LogEvent_Type.DEPRECATION_WARNING)); + equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, equals("As of Dart Sass 2.0.0, !global assignments won't be able to\n" @@ -358,7 +358,7 @@ a { test("caused by using Sass features in CSS", () async { process.inbound.add( - compileString("a {b: 1px + 2px}", syntax: InboundMessage_Syntax.CSS)); + compileString("a {b: 1px + 2px}", syntax: Syntax.CSS)); var failure = getCompileFailure(await process.outbound.next); expect(failure.message, equals("Operators aren't allowed in plain CSS.")); diff --git a/test/utils.dart b/test/utils.dart index e3fe8e087..1f6f73346 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -16,8 +16,8 @@ InboundMessage compileString(String css, {int? id, bool? alertColor, bool? alertAscii, - InboundMessage_Syntax? syntax, - InboundMessage_CompileRequest_OutputStyle? style, + Syntax? syntax, + OutputStyle? style, String? url, bool? sourceMap, Iterable? importers, @@ -44,7 +44,7 @@ InboundMessage compileString(String css, /// [message] on its protobuf stream and prints a notice on stderr. Future expectParseError(EmbeddedProcess process, message) async { await expectLater(process.outbound, - emits(isProtocolError(errorId, ProtocolError_ErrorType.PARSE, message))); + emits(isProtocolError(errorId, ProtocolErrorType.PARSE, message))); var stderrPrefix = "Host caused parse error: "; await expectLater( @@ -58,7 +58,7 @@ Future expectParseError(EmbeddedProcess process, message) async { /// [message] on its protobuf stream and prints a notice on stderr. Future expectParamsError(EmbeddedProcess process, int id, message) async { await expectLater(process.outbound, - emits(isProtocolError(id, ProtocolError_ErrorType.PARAMS, message))); + emits(isProtocolError(id, ProtocolErrorType.PARAMS, message))); var stderrPrefix = "Host caused params error" "${id == errorId ? '' : " with request $id"}: "; @@ -71,7 +71,7 @@ Future expectParamsError(EmbeddedProcess process, int id, message) async { /// Asserts that an [OutboundMessage] is a [ProtocolError] with the given [id], /// [type], and optionally [message]. -Matcher isProtocolError(int id, ProtocolError_ErrorType type, [message]) => +Matcher isProtocolError(int id, ProtocolErrorType type, [message]) => predicate((value) { expect(value, isA()); var outboundMessage = value as OutboundMessage; From de335d884e11d23e725df534c89076587a18b266 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 24 May 2021 17:42:44 -0700 Subject: [PATCH 045/162] Fix warning expectations in tests --- test/protocol_test.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/protocol_test.dart b/test/protocol_test.dart index b3f4393e3..a2d503db2 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -211,7 +211,8 @@ void main() { equals( '@elseif is deprecated and will not be supported in future Sass ' 'versions.\n' - 'Use "@else if" instead.')); + '\n' + 'Recommendation: @else if')); expect(logEvent.span.text, equals("@elseif")); expect(logEvent.span.start, equals(location(12, 0, 12))); expect(logEvent.span.end, equals(location(19, 0, 19))); @@ -229,10 +230,10 @@ void main() { equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, - equals("As of Dart Sass 2.0.0, !global assignments won't be able to\n" - "declare new variables. Consider adding `\$var: null` at the " - "root of the\n" - "stylesheet.")); + equals("As of Dart Sass 2.0.0, !global assignments won't be able to " + "declare new variables.\n" + "\n" + "Recommendation: add `\$var: null` at the stylesheet root.")); expect(logEvent.span.text, equals("\$var: value !global")); expect(logEvent.span.start, equals(location(3, 0, 3))); expect(logEvent.span.end, equals(location(22, 0, 22))); From 12c468004cc3337c6b1d56b346678903aaacd225 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 25 May 2021 17:59:17 -0700 Subject: [PATCH 046/162] Implement CanonicalizeRequest.from_import (#41) See sass/sass#3055 See webpack-contrib/sass-loader#905 See sass/embedded-protocol#61 --- CHANGELOG.md | 3 ++- lib/src/importer.dart | 3 ++- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2571cbb1..61a75e4c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ ## 1.0.0-beta.8 -* Internal changes only. +* Support version 1.0.0-beta.11 of the Sass embedded protocol: + * Set CanonicalizeRequest.from_import. diff --git a/lib/src/importer.dart b/lib/src/importer.dart index 7e871482c..da1dfe538 100644 --- a/lib/src/importer.dart +++ b/lib/src/importer.dart @@ -29,7 +29,8 @@ class Importer extends sass.Importer { .sendCanonicalizeRequest(OutboundMessage_CanonicalizeRequest() ..compilationId = _compilationId ..importerId = _importerId - ..url = url.toString()); + ..url = url.toString() + ..fromImport = fromImport); switch (response.whichResult()) { case InboundMessage_CanonicalizeResponse_Result.url: diff --git a/pubspec.yaml b/pubspec.yaml index 28765ef44..31f3ebca7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 protobuf: ^2.0.0 - sass: ^1.25.0 + sass: ^1.33.0 source_maps: ^0.10.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 66ab368582997915c2f3c6ce81f5673d926a49ee Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 26 May 2021 13:10:56 -0700 Subject: [PATCH 047/162] Support fuzzy range errors (#45) Closes #32 --- CHANGELOG.md | 2 + lib/src/function_registry.dart | 3 +- lib/src/value.dart | 190 ++++++++++++++++----------------- test/function_test.dart | 22 ++-- 4 files changed, 107 insertions(+), 110 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61a75e4c6..83e48c7ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,5 @@ * Support version 1.0.0-beta.11 of the Sass embedded protocol: * Set CanonicalizeRequest.from_import. + +* Properly throw errors for range checks for colors. diff --git a/lib/src/function_registry.dart b/lib/src/function_registry.dart index 1cfd69a05..f8ca94b71 100644 --- a/lib/src/function_registry.dart +++ b/lib/src/function_registry.dart @@ -3,7 +3,8 @@ // https://opensource.org/licenses/MIT. import 'package:sass/sass.dart' as sass; -import 'package:sass_embedded/src/embedded_sass.pb.dart'; + +import 'embedded_sass.pb.dart'; /// A registry of [SassFunction]s indexed by ID so that the host can invoke /// them. diff --git a/lib/src/value.dart b/lib/src/value.dart index 5c8c1a2d7..18b5992f1 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -3,9 +3,9 @@ // https://opensource.org/licenses/MIT. import 'package:sass/sass.dart' as sass; -import 'package:sass_embedded/src/embedded_sass.pb.dart'; import 'dispatcher.dart'; +import 'embedded_sass.pb.dart'; import 'function_registry.dart'; import 'host_callable.dart'; import 'utils.dart'; @@ -88,87 +88,97 @@ sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, var deprotofy = (Value value) => deprotofyValue(dispatcher, functions, compilationId, value); - switch (value.whichValue()) { - case Value_Value.string: - return value.string.text.isEmpty - ? sass.SassString.empty(quotes: value.string.quoted) - : sass.SassString(value.string.text, quotes: value.string.quoted); - - case Value_Value.number: - return sass.SassNumber.withUnits(value.number.value, - numeratorUnits: value.number.numerators, - denominatorUnits: value.number.denominators); - - case Value_Value.rgbColor: - return sass.SassColor.rgb( - _checkInRange('RgbColor.red', value.rgbColor.red, 0, 255), - _checkInRange('RgbColor.green', value.rgbColor.green, 0, 255), - _checkInRange('RgbColor.blue', value.rgbColor.blue, 0, 255), - _checkInRange('RgbColor.alpha', value.rgbColor.alpha, 0, 1)); - - case Value_Value.hslColor: - return sass.SassColor.hsl( - value.hslColor.hue, - _checkInRange( - 'HslColor.saturation', value.hslColor.saturation, 0, 100), - _checkInRange('HslColor.lightness', value.hslColor.lightness, 0, 100), - _checkInRange('HslColor.alpha', value.hslColor.alpha, 0, 1)); - - case Value_Value.list: - var separator = _deprotofySeparator(value.list.separator); - if (value.list.contents.isEmpty) { - return sass.SassList.empty( - separator: separator, brackets: value.list.hasBrackets); - } - - var length = value.list.contents.length; - if (separator == sass.ListSeparator.undecided && length > 1) { - throw paramsError( - "List $value can't have an undecided separator because it has " - "$length elements"); - } - - return sass.SassList([ - for (var element in value.list.contents) deprotofy(element) - ], separator, brackets: value.list.hasBrackets); - - case Value_Value.map: - return value.map.entries.isEmpty - ? const sass.SassMap.empty() - : sass.SassMap({ - for (var entry in value.map.entries) - deprotofy(entry.key): deprotofy(entry.value) - }); - - case Value_Value.compilerFunction: - var id = value.compilerFunction.id; - var function = functions[id]; - if (function == null) { - throw paramsError( - "CompilerFunction.id $id doesn't match any known functions"); - } - - return function; - - case Value_Value.hostFunction: - return sass.SassFunction(hostCallable( - dispatcher, functions, compilationId, value.hostFunction.signature, - id: value.hostFunction.id)); - - case Value_Value.singleton: - switch (value.singleton) { - case SingletonValue.TRUE: - return sass.sassTrue; - case SingletonValue.FALSE: - return sass.sassFalse; - case SingletonValue.NULL: - return sass.sassNull; - default: - throw "Unknown Value.singleton ${value.singleton}"; - } - - case Value_Value.notSet: - throw mandatoryError("Value.value"); + try { + switch (value.whichValue()) { + case Value_Value.string: + return value.string.text.isEmpty + ? sass.SassString.empty(quotes: value.string.quoted) + : sass.SassString(value.string.text, quotes: value.string.quoted); + + case Value_Value.number: + return sass.SassNumber.withUnits(value.number.value, + numeratorUnits: value.number.numerators, + denominatorUnits: value.number.denominators); + + case Value_Value.rgbColor: + return sass.SassColor.rgb(value.rgbColor.red, value.rgbColor.green, + value.rgbColor.blue, value.rgbColor.alpha); + + case Value_Value.hslColor: + return sass.SassColor.hsl(value.hslColor.hue, value.hslColor.saturation, + value.hslColor.lightness, value.hslColor.alpha); + + case Value_Value.list: + var separator = _deprotofySeparator(value.list.separator); + if (value.list.contents.isEmpty) { + return sass.SassList.empty( + separator: separator, brackets: value.list.hasBrackets); + } + + var length = value.list.contents.length; + if (separator == sass.ListSeparator.undecided && length > 1) { + throw paramsError( + "List $value can't have an undecided separator because it has " + "$length elements"); + } + + return sass.SassList([ + for (var element in value.list.contents) deprotofy(element) + ], separator, brackets: value.list.hasBrackets); + + case Value_Value.map: + return value.map.entries.isEmpty + ? const sass.SassMap.empty() + : sass.SassMap({ + for (var entry in value.map.entries) + deprotofy(entry.key): deprotofy(entry.value) + }); + + case Value_Value.compilerFunction: + var id = value.compilerFunction.id; + var function = functions[id]; + if (function == null) { + throw paramsError( + "CompilerFunction.id $id doesn't match any known functions"); + } + + return function; + + case Value_Value.hostFunction: + return sass.SassFunction(hostCallable( + dispatcher, functions, compilationId, value.hostFunction.signature, + id: value.hostFunction.id)); + + case Value_Value.singleton: + switch (value.singleton) { + case SingletonValue.TRUE: + return sass.sassTrue; + case SingletonValue.FALSE: + return sass.sassFalse; + case SingletonValue.NULL: + return sass.sassNull; + default: + throw "Unknown Value.singleton ${value.singleton}"; + } + + case Value_Value.notSet: + throw mandatoryError("Value.value"); + } + } on RangeError catch (error) { + var name = error.name; + if (name == null || error.start == null || error.end == null) { + throw paramsError(error.toString()); + } + + if (value.whichValue() == Value_Value.rgbColor) { + name = 'RgbColor.$name'; + } else if (value.whichValue() == Value_Value.hslColor) { + name = 'HslColor.$name'; + } + + throw paramsError( + '$name must be between ${error.start} and ${error.end}, was ' + '${error.invalidValue}'); } } @@ -185,19 +195,3 @@ sass.ListSeparator _deprotofySeparator(ListSeparator separator) { throw "Unknown separator $separator"; } } - -/// Throws a parameter error if [value] isn't between [lower] and [upper], both -/// inclusive. -/// -/// Returns [value] if it is within the range. -T _checkInRange(String field, T value, num lower, num upper) { - if (value < lower) { - throw paramsError( - '$field must be greater than or equal to $lower, was $value'); - } else if (value > upper) { - throw paramsError( - '$field must be less than or equal to $upper, was $value'); - } else { - return value; - } -} diff --git a/test/function_test.dart b/test/function_test.dart index cbcd77103..c5c4d64c4 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -1118,61 +1118,61 @@ void main() { group("a color", () { test("with red above 255", () async { await _expectDeprotofyError(_rgb(256, 0, 0, 1.0), - "RgbColor.red must be less than or equal to 255, was 256"); + "RgbColor.red must be between 0 and 255, was 256"); }); test("with green above 255", () async { await _expectDeprotofyError(_rgb(0, 256, 0, 1.0), - "RgbColor.green must be less than or equal to 255, was 256"); + "RgbColor.green must be between 0 and 255, was 256"); }); test("with blue above 255", () async { await _expectDeprotofyError(_rgb(0, 0, 256, 1.0), - "RgbColor.blue must be less than or equal to 255, was 256"); + "RgbColor.blue must be between 0 and 255, was 256"); }); test("with RGB alpha below 0", () async { await _expectDeprotofyError(_rgb(0, 0, 0, -0.1), - "RgbColor.alpha must be greater than or equal to 0, was -0.1"); + "RgbColor.alpha must be between 0 and 1, was -0.1"); }); test("with RGB alpha above 1", () async { await _expectDeprotofyError(_rgb(0, 0, 0, 1.1), - "RgbColor.alpha must be less than or equal to 1, was 1.1"); + "RgbColor.alpha must be between 0 and 1, was 1.1"); }); test("with saturation below 0", () async { await _expectDeprotofyError(_hsl(0, -0.1, 0, 1.0), - "HslColor.saturation must be greater than or equal to 0, was -0.1"); + "HslColor.saturation must be between 0 and 100, was -0.1"); }); test("with saturation above 100", () async { await _expectDeprotofyError( _hsl(0, 100.1, 0, 1.0), - "HslColor.saturation must be less than or equal to 100, was " + "HslColor.saturation must be between 0 and 100, was " "100.1"); }); test("with lightness below 0", () async { await _expectDeprotofyError(_hsl(0, 0, -0.1, 1.0), - "HslColor.lightness must be greater than or equal to 0, was -0.1"); + "HslColor.lightness must be between 0 and 100, was -0.1"); }); test("with lightness above 100", () async { await _expectDeprotofyError( _hsl(0, 0, 100.1, 1.0), - "HslColor.lightness must be less than or equal to 100, was " + "HslColor.lightness must be between 0 and 100, was " "100.1"); }); test("with HSL alpha below 0", () async { await _expectDeprotofyError(_hsl(0, 0, 0, -0.1), - "HslColor.alpha must be greater than or equal to 0, was -0.1"); + "HslColor.alpha must be between 0 and 1, was -0.1"); }); test("with HSL alpha above 1", () async { await _expectDeprotofyError(_hsl(0, 0, 0, 1.1), - "HslColor.alpha must be less than or equal to 1, was 1.1"); + "HslColor.alpha must be between 0 and 1, was 1.1"); }); }); From 67bd395df5526e9c24da671921cd3fa7e806a6b3 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 14 Jun 2021 12:44:31 -0700 Subject: [PATCH 048/162] Add a CI task that checks formatting --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 811a405b8..bcfbcac18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,16 @@ jobs: - name: Analyze dart run: dartanalyzer --fatal-warnings ./ + format: + name: Code formatting + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + - run: dart format --fix . + - run: git diff --exit-code + deploy_github_linux: name: "Deploy Github: Linux" runs-on: ubuntu-latest From f0501ec114d5864560da1c301998a3ecb6cfc4ef Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 14 Jun 2021 12:49:48 -0700 Subject: [PATCH 049/162] Reformat --- bin/dart_sass_embedded.dart | 7 +++---- lib/src/logger.dart | 5 ++--- test/protocol_test.dart | 29 +++++++++++++---------------- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 1bf5a1895..6f66982e7 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -35,10 +35,9 @@ void main(List args) { dispatcher.listen((request) async { var functions = FunctionRegistry(); - var style = - request.style == OutputStyle.COMPRESSED - ? sass.OutputStyle.compressed - : sass.OutputStyle.expanded; + var style = request.style == OutputStyle.COMPRESSED + ? sass.OutputStyle.compressed + : sass.OutputStyle.expanded; var logger = Logger(dispatcher, request.id, color: request.alertColor, ascii: request.alertAscii); diff --git a/lib/src/logger.dart b/lib/src/logger.dart index bac6d86ad..55b365f41 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -73,9 +73,8 @@ class Logger implements sass.Logger { var event = OutboundMessage_LogEvent() ..compilationId = _compilationId - ..type = deprecation - ? LogEventType.DEPRECATION_WARNING - : LogEventType.WARNING + ..type = + deprecation ? LogEventType.DEPRECATION_WARNING : LogEventType.WARNING ..message = message ..formatted = formatted; if (span != null) event.span = protofySpan(span); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index a2d503db2..fdb74ad03 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -41,22 +41,21 @@ void main() { }); test("an SCSS string explicitly", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - syntax: Syntax.SCSS)); + process.inbound + .add(compileString("a {b: 1px + 2px}", syntax: Syntax.SCSS)); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); }); test("an indented syntax string", () async { - process.inbound.add(compileString("a\n b: 1px + 2px", - syntax: Syntax.INDENTED)); + process.inbound + .add(compileString("a\n b: 1px + 2px", syntax: Syntax.INDENTED)); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); }); test("a plain CSS string", () async { - process.inbound - .add(compileString("a {b: c}", syntax: Syntax.CSS)); + process.inbound.add(compileString("a {b: c}", syntax: Syntax.CSS)); await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); await process.kill(); }); @@ -84,16 +83,16 @@ void main() { group("compiles CSS in", () { test("expanded mode", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - style: OutputStyle.EXPANDED)); + process.inbound + .add(compileString("a {b: 1px + 2px}", style: OutputStyle.EXPANDED)); await expectLater( process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); await process.kill(); }); test("compressed mode", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - style: OutputStyle.COMPRESSED)); + process.inbound.add( + compileString("a {b: 1px + 2px}", style: OutputStyle.COMPRESSED)); await expectLater(process.outbound, emits(isSuccess(equals("a{b:3px}")))); await process.kill(); }); @@ -204,8 +203,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, - equals(LogEventType.DEPRECATION_WARNING)); + expect(logEvent.type, equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, equals( @@ -226,8 +224,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, - equals(LogEventType.DEPRECATION_WARNING)); + expect(logEvent.type, equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, equals("As of Dart Sass 2.0.0, !global assignments won't be able to " @@ -358,8 +355,8 @@ a { }); test("caused by using Sass features in CSS", () async { - process.inbound.add( - compileString("a {b: 1px + 2px}", syntax: Syntax.CSS)); + process.inbound + .add(compileString("a {b: 1px + 2px}", syntax: Syntax.CSS)); var failure = getCompileFailure(await process.outbound.next); expect(failure.message, equals("Operators aren't allowed in plain CSS.")); From 1c773f1cb113926d0869a6d7e968af6bf30dfbbd Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 14 Jun 2021 12:51:01 -0700 Subject: [PATCH 050/162] Support VersionRequest and VersionResponse (#46) Closes #33 --- CHANGELOG.md | 3 ++- lib/src/dispatcher.dart | 13 +++++++++++++ pubspec.yaml | 5 ++++- test/protocol_test.dart | 43 ++++++++++++++++++++++++++--------------- tool/grind.dart | 16 +++++++++++++++ 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83e48c7ec..3055d95d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.0.0-beta.8 * Support version 1.0.0-beta.11 of the Sass embedded protocol: - * Set CanonicalizeRequest.from_import. + * Support `VersionRequest` and `VersionResponse`. + * Set `CanonicalizeRequest.from_import`. * Properly throw errors for range checks for colors. diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 706b44409..2a77f20ec 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -56,6 +56,19 @@ class Dispatcher { } switch (message.whichMessage()) { + case InboundMessage_Message.versionRequest: + _send(OutboundMessage() + ..versionResponse = (OutboundMessage_VersionResponse() + ..protocolVersion = + const String.fromEnvironment("protocol-version") + ..compilerVersion = + const String.fromEnvironment("compiler-version") + ..implementationVersion = + const String.fromEnvironment("implementation-version") + ..implementationName = "Dart Sass" + ..id = message.versionRequest.id)); + break; + case InboundMessage_Message.compileRequest: var request = message.compileRequest; var response = await callback(request); diff --git a/pubspec.yaml b/pubspec.yaml index 31f3ebca7..6a6a87ea7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,9 +22,12 @@ dependencies: typed_data: ^1.1.0 dev_dependencies: - cli_pkg: ^1.2.0 + cli_pkg: ^1.4.0 grinder: ^0.9.0 protoc_plugin: ^20.0.0 path: ^1.6.0 test: ^1.0.0 test_descriptor: ^2.0.0 + yaml: ^3.1.0 + pubspec_parse: ^1.0.0 + pub_semver: ^2.0.0 diff --git a/test/protocol_test.dart b/test/protocol_test.dart index a2d503db2..930881ea6 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -3,6 +3,7 @@ // https://opensource.org/licenses/MIT. import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:source_maps/source_maps.dart' as source_maps; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; @@ -33,6 +34,19 @@ void main() { }); }); + test("a version response is valid", () async { + process.inbound.add(InboundMessage() + ..versionRequest = (InboundMessage_VersionRequest()..id = 123)); + var response = (await process.outbound.next).versionResponse; + expect(response.id, equals(123)); + + Version.parse(response.protocolVersion); // shouldn't throw + Version.parse(response.compilerVersion); // shouldn't throw + Version.parse(response.implementationVersion); // shouldn't throw + expect(response.implementationName, equals("Dart Sass")); + await process.kill(); + }); + group("compiles CSS from", () { test("an SCSS string by default", () async { process.inbound.add(compileString("a {b: 1px + 2px}")); @@ -41,22 +55,21 @@ void main() { }); test("an SCSS string explicitly", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - syntax: Syntax.SCSS)); + process.inbound + .add(compileString("a {b: 1px + 2px}", syntax: Syntax.SCSS)); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); }); test("an indented syntax string", () async { - process.inbound.add(compileString("a\n b: 1px + 2px", - syntax: Syntax.INDENTED)); + process.inbound + .add(compileString("a\n b: 1px + 2px", syntax: Syntax.INDENTED)); await expectLater(process.outbound, emits(isSuccess("a { b: 3px; }"))); await process.kill(); }); test("a plain CSS string", () async { - process.inbound - .add(compileString("a {b: c}", syntax: Syntax.CSS)); + process.inbound.add(compileString("a {b: c}", syntax: Syntax.CSS)); await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); await process.kill(); }); @@ -84,16 +97,16 @@ void main() { group("compiles CSS in", () { test("expanded mode", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - style: OutputStyle.EXPANDED)); + process.inbound + .add(compileString("a {b: 1px + 2px}", style: OutputStyle.EXPANDED)); await expectLater( process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}")))); await process.kill(); }); test("compressed mode", () async { - process.inbound.add(compileString("a {b: 1px + 2px}", - style: OutputStyle.COMPRESSED)); + process.inbound.add( + compileString("a {b: 1px + 2px}", style: OutputStyle.COMPRESSED)); await expectLater(process.outbound, emits(isSuccess(equals("a{b:3px}")))); await process.kill(); }); @@ -204,8 +217,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, - equals(LogEventType.DEPRECATION_WARNING)); + expect(logEvent.type, equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, equals( @@ -226,8 +238,7 @@ void main() { var logEvent = getLogEvent(await process.outbound.next); expect(logEvent.compilationId, equals(0)); - expect(logEvent.type, - equals(LogEventType.DEPRECATION_WARNING)); + expect(logEvent.type, equals(LogEventType.DEPRECATION_WARNING)); expect( logEvent.message, equals("As of Dart Sass 2.0.0, !global assignments won't be able to " @@ -358,8 +369,8 @@ a { }); test("caused by using Sass features in CSS", () async { - process.inbound.add( - compileString("a {b: 1px + 2px}", syntax: Syntax.CSS)); + process.inbound + .add(compileString("a {b: 1px + 2px}", syntax: Syntax.CSS)); var failure = getCompileFailure(await process.outbound.next); expect(failure.message, equals("Operators aren't allowed in plain CSS.")); diff --git a/tool/grind.dart b/tool/grind.dart index 2247a2c55..aac8c47f7 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -6,16 +6,32 @@ import 'dart:io'; import 'package:cli_pkg/cli_pkg.dart' as pkg; import 'package:grinder/grinder.dart'; +import 'package:yaml/yaml.dart'; import 'utils.dart'; main(List args) { pkg.githubBearerToken.fn = () => Platform.environment["GH_BEARER_TOKEN"]!; + pkg.environmentConstants.fn = () => { + ...pkg.environmentConstants.defaultValue, + "protocol-version": + File('build/embedded-protocol/VERSION').readAsStringSync().trim(), + "compiler-version": pkg.pubspec.version!.toString(), + "implementation-version": _implementationVersion + }; + pkg.addGithubTasks(); grind(args); } +/// Returns the version of Dart Sass that this package uses. +String get _implementationVersion { + var lockfile = loadYaml(File('pubspec.lock').readAsStringSync(), + sourceUrl: Uri(path: 'pubspec.lock')); + return lockfile['packages']['sass']['version']; +} + @Task('Compile the protocol buffer definition to a Dart library.') protobuf() async { Directory('build').createSync(recursive: true); From c919db73aad44fd8cc12218bf0bb8b77573dec88 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 16 Jun 2021 13:36:56 -0700 Subject: [PATCH 051/162] Support CompileRequest.quiet_deps and .verbose (#48) Closes #44 --- CHANGELOG.md | 1 + bin/dart_sass_embedded.dart | 4 ++++ pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3055d95d5..47e604ded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Support version 1.0.0-beta.11 of the Sass embedded protocol: * Support `VersionRequest` and `VersionResponse`. + * Support `CompileRequest.quiet_deps` and `.verbose`. * Set `CanonicalizeRequest.from_import`. * Properly throw errors for range checks for colors. diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 6f66982e7..9e58988e6 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -67,6 +67,8 @@ void main(List args) { syntax: syntaxToSyntax(input.syntax), style: style, url: input.url.isEmpty ? null : input.url, + quietDeps: request.quietDeps, + verbose: request.verbose, sourceMap: sourceMapCallback); break; @@ -78,6 +80,8 @@ void main(List args) { importers: importers, functions: globalFunctions, style: style, + quietDeps: request.quietDeps, + verbose: request.verbose, sourceMap: sourceMapCallback); } on FileSystemException catch (error) { return OutboundMessage_CompileResponse() diff --git a/pubspec.yaml b/pubspec.yaml index 6a6a87ea7..7b837eda2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 protobuf: ^2.0.0 - sass: ^1.33.0 + sass: ^1.34.0 source_maps: ^0.10.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From b402a20757f8cc43fd701e7b9a4dd4221981e080 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 29 Jun 2021 16:14:01 -0700 Subject: [PATCH 052/162] Refer to "main" branches (#49) --- .github/workflows/ci.yml | 2 +- tool/utils.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcfbcac18..ac5dce359 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ env: on: push: - branches: [master, feature.*] + branches: [main, feature.*] tags: ['**'] pull_request: diff --git a/tool/utils.dart b/tool/utils.dart index d5059b543..2eb303b1d 100644 --- a/tool/utils.dart +++ b/tool/utils.dart @@ -12,7 +12,7 @@ import 'package:path/path.dart' as p; /// /// Returns the path to the repository. Future cloneOrPull(String url) async => - cloneOrCheckout(url, "origin/master"); + cloneOrCheckout(url, "origin/main"); /// Ensure that the repository at [url] is cloned into the build directory and /// pointing to [ref]. From c80320f777dd5fb805eb5831b6777d43937ff8ec Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 23 Jul 2021 21:41:39 +0000 Subject: [PATCH 053/162] Set CompileSuccess.loaded_urls (#50) --- CHANGELOG.md | 1 + bin/dart_sass_embedded.dart | 24 ++++++++++-------------- pubspec.yaml | 5 ++--- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e604ded..a5b18f673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,5 +4,6 @@ * Support `VersionRequest` and `VersionResponse`. * Support `CompileRequest.quiet_deps` and `.verbose`. * Set `CanonicalizeRequest.from_import`. + * Set `CompileSuccess.loaded_urls`. * Properly throw errors for range checks for colors. diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 9e58988e6..6730036da 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -6,7 +6,6 @@ import 'dart:io'; import 'dart:convert'; import 'package:sass/sass.dart' as sass; -import 'package:source_maps/source_maps.dart' as source_maps; import 'package:stream_channel/stream_channel.dart'; import 'package:sass_embedded/src/dispatcher.dart'; @@ -42,12 +41,6 @@ void main(List args) { color: request.alertColor, ascii: request.alertAscii); try { - String result; - source_maps.SingleMapping? sourceMap; - var sourceMapCallback = request.sourceMap - ? (source_maps.SingleMapping map) => sourceMap = map - : null; - var importers = request.importers.map((importer) => _decodeImporter(dispatcher, request, importer) ?? (throw mandatoryError("Importer.importer"))); @@ -55,10 +48,11 @@ void main(List args) { var globalFunctions = request.globalFunctions.map((signature) => hostCallable(dispatcher, functions, request.id, signature)); + late sass.CompileResult result; switch (request.whichInput()) { case InboundMessage_CompileRequest_Input.string: var input = request.string; - result = sass.compileString(input.source, + result = sass.compileStringToResult(input.source, color: request.alertColor, logger: logger, importers: importers, @@ -69,12 +63,12 @@ void main(List args) { url: input.url.isEmpty ? null : input.url, quietDeps: request.quietDeps, verbose: request.verbose, - sourceMap: sourceMapCallback); + sourceMap: request.sourceMap); break; case InboundMessage_CompileRequest_Input.path: try { - result = sass.compile(request.path, + result = sass.compileToResult(request.path, color: request.alertColor, logger: logger, importers: importers, @@ -82,7 +76,7 @@ void main(List args) { style: style, quietDeps: request.quietDeps, verbose: request.verbose, - sourceMap: sourceMapCallback); + sourceMap: request.sourceMap); } on FileSystemException catch (error) { return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() @@ -97,10 +91,12 @@ void main(List args) { } var success = OutboundMessage_CompileResponse_CompileSuccess() - ..css = result; + ..css = result.css + ..loadedUrls.addAll(result.loadedUrls.map((url) => url.toString())); + + var sourceMap = result.sourceMap; if (sourceMap != null) { - // dart-lang/language#1536 - success.sourceMap = json.encode(sourceMap!.toJson()); + success.sourceMap = json.encode(sourceMap.toJson()); } return OutboundMessage_CompileResponse()..success = success; } on sass.SassException catch (error) { diff --git a/pubspec.yaml b/pubspec.yaml index 7b837eda2..4af116726 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.0.0-beta.8 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded @@ -14,8 +14,7 @@ dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 protobuf: ^2.0.0 - sass: ^1.34.0 - source_maps: ^0.10.5 + sass: ^1.36.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 0de8deb48977afcb75c2f6a0172872b4f1f2e070 Mon Sep 17 00:00:00 2001 From: Awjin Ahn Date: Tue, 17 Aug 2021 14:36:59 -0700 Subject: [PATCH 054/162] Give nnbd an explicit guarantee on the switch case. (#51) --- CHANGELOG.md | 4 ++++ lib/src/value.dart | 1 + pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5b18f673..7dae363ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-beta.9 + +* No user-visible changes. + ## 1.0.0-beta.8 * Support version 1.0.0-beta.11 of the Sass embedded protocol: diff --git a/lib/src/value.dart b/lib/src/value.dart index 18b5992f1..9e806e34c 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -162,6 +162,7 @@ sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, } case Value_Value.notSet: + default: throw mandatoryError("Value.value"); } } on RangeError catch (error) { diff --git a/pubspec.yaml b/pubspec.yaml index 4af116726..edf4ba2eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.8 +version: 1.0.0-beta.9 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 5ff4e84b4acefcf75e5607ec9d620a6238b4b9f8 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 17 Aug 2021 13:48:25 -0700 Subject: [PATCH 055/162] Support slash-separated lists --- CHANGELOG.md | 4 ++ lib/src/value.dart | 4 ++ pubspec.yaml | 2 +- test/function_test.dart | 104 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dae363ac..2eb79cd80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-beta.10 + +* Support slash-separated lists. + ## 1.0.0-beta.9 * No user-visible changes. diff --git a/lib/src/value.dart b/lib/src/value.dart index 9e806e34c..a0f62f779 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -70,6 +70,8 @@ ListSeparator _protofySeparator(sass.ListSeparator separator) { return ListSeparator.COMMA; case sass.ListSeparator.space: return ListSeparator.SPACE; + case sass.ListSeparator.slash: + return ListSeparator.SLASH; case sass.ListSeparator.undecided: return ListSeparator.UNDECIDED; default: @@ -190,6 +192,8 @@ sass.ListSeparator _deprotofySeparator(ListSeparator separator) { return sass.ListSeparator.comma; case ListSeparator.SPACE: return sass.ListSeparator.space; + case ListSeparator.SLASH: + return sass.ListSeparator.slash; case ListSeparator.UNDECIDED: return sass.ListSeparator.undecided; default: diff --git a/pubspec.yaml b/pubspec.yaml index edf4ba2eb..c2b3662e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.9 +version: 1.0.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded diff --git a/test/function_test.dart b/test/function_test.dart index c5c4d64c4..e0ccb6a58 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -497,6 +497,14 @@ void main() { expect(list.hasBrackets, isTrue); expect(list.separator, equals(ListSeparator.SPACE)); }); + + test("with a slash separator", () async { + var list = + (await _protofy(r"list.join([], [], $separator: slash)")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(ListSeparator.SLASH)); + }); }); group("without brackets", () { @@ -522,6 +530,14 @@ void main() { expect(list.hasBrackets, isFalse); expect(list.separator, equals(ListSeparator.SPACE)); }); + + test("with a slash separator", () async { + var list = + (await _protofy(r"list.join((), (), $separator: slash)")).list; + expect(list.contents, isEmpty); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(ListSeparator.SLASH)); + }); }); }); @@ -549,6 +565,15 @@ void main() { expect(list.hasBrackets, isTrue); expect(list.separator, equals(ListSeparator.SPACE)); }); + + test("with a slash separator", () async { + var list = + (await _protofy(r"list.join([true], [], $separator: slash)")) + .list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isTrue); + expect(list.separator, equals(ListSeparator.SLASH)); + }); }); group("without brackets", () { @@ -567,6 +592,15 @@ void main() { expect(list.hasBrackets, isFalse); expect(list.separator, equals(ListSeparator.SPACE)); }); + + test("with a slash separator", () async { + var list = + (await _protofy(r"list.join(true, (), $separator: slash)")) + .list; + expect(list.contents, equals([_true])); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(ListSeparator.SLASH)); + }); }); }); @@ -601,6 +635,13 @@ void main() { expect(list.hasBrackets, isFalse); expect(list.separator, equals(ListSeparator.SPACE)); }); + + test("with a slash separator", () async { + var list = (await _protofy(r"list.slash(true, null, false)")).list; + expect(list.contents, equals([_true, _null, _false])); + expect(list.hasBrackets, isFalse); + expect(list.separator, equals(ListSeparator.SLASH)); + }); }); }); }); @@ -895,6 +936,15 @@ void main() { ..separator = ListSeparator.SPACE), "[]"); }); + + group("with a slash separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = true + ..separator = ListSeparator.SLASH), + "[]"); + }); }); group("without brackets", () { @@ -927,6 +977,16 @@ void main() { "()", inspect: true); }); + + group("with a slash separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..hasBrackets = false + ..separator = ListSeparator.SLASH), + "()", + inspect: true); + }); }); }); @@ -963,6 +1023,16 @@ void main() { ..separator = ListSeparator.SPACE), "[true]"); }); + + group("with a slash separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = true + ..separator = ListSeparator.SLASH), + "[true]"); + }); }); group("without brackets", () { @@ -997,6 +1067,16 @@ void main() { ..separator = ListSeparator.SPACE), "true"); }); + + group("with a slash separator", () { + _testSerializationAndRoundTrip( + Value() + ..list = (Value_List() + ..contents.add(_true) + ..hasBrackets = false + ..separator = ListSeparator.SLASH), + "true"); + }); }); }); @@ -1025,6 +1105,18 @@ void main() { inspect: true), "[true null false]"); }); + + test("with a slash separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _null, _false]) + ..hasBrackets = true + ..separator = ListSeparator.SLASH), + inspect: true), + "[true / null / false]"); + }); }); group("without brackets", () { @@ -1051,6 +1143,18 @@ void main() { inspect: true), "true null false"); }); + + test("with a slash separator", () async { + expect( + await _deprotofy( + Value() + ..list = (Value_List() + ..contents.addAll([_true, _null, _false]) + ..hasBrackets = false + ..separator = ListSeparator.SLASH), + inspect: true), + "true / null / false"); + }); }); }); }); From e98484afca6f695b3b64975341cfd7c5dee5e4d2 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 9 Aug 2021 16:11:51 -0700 Subject: [PATCH 056/162] Add support for argument lists --- CHANGELOG.md | 3 + lib/src/host_callable.dart | 11 +- lib/src/protofier.dart | 274 +++++++++++++++++++++++++++++++++++++ pubspec.yaml | 4 +- test/function_test.dart | 202 +++++++++++++++++++++++++-- 5 files changed, 471 insertions(+), 23 deletions(-) create mode 100644 lib/src/protofier.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eb79cd80..afe916c74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## 1.0.0-beta.10 +* Support version 1.0.0-beta.12 of the Sass embedded protocol: + * Support `Value.ArgumentList`. + * Support slash-separated lists. ## 1.0.0-beta.9 diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index bb567d419..924116922 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -10,8 +10,8 @@ import 'package:sass/sass.dart' as sass; import 'dispatcher.dart'; import 'embedded_sass.pb.dart'; import 'function_registry.dart'; +import 'protofier.dart'; import 'utils.dart'; -import 'value.dart'; /// Returns a Sass callable that invokes a function defined on the host with the /// given [signature]. @@ -41,11 +41,11 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, return sass.Callable.function( name, signature.substring(openParen + 1, signature.length - 1), (arguments) { + var protofier = Protofier(dispatcher, functions, compilationId); var request = OutboundMessage_FunctionCallRequest() ..compilationId = compilationId - ..arguments.addAll([ - for (var argument in arguments) protofyValue(functions, argument) - ]); + ..arguments.addAll( + [for (var argument in arguments) protofier.protofy(argument)]); if (id != null) { request.functionId = id; @@ -57,8 +57,7 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, try { switch (response.whichResult()) { case InboundMessage_FunctionCallResponse_Result.success: - return deprotofyValue( - dispatcher, functions, compilationId, response.success); + return protofier.deprotofyResponse(response); case InboundMessage_FunctionCallResponse_Result.error: throw response.error; diff --git a/lib/src/protofier.dart b/lib/src/protofier.dart new file mode 100644 index 000000000..3c2ef53d8 --- /dev/null +++ b/lib/src/protofier.dart @@ -0,0 +1,274 @@ +// Copyright 2019 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:sass/sass.dart' as sass; + +import 'dispatcher.dart'; +import 'embedded_sass.pb.dart'; +import 'function_registry.dart'; +import 'host_callable.dart'; +import 'utils.dart'; + +/// A class that converts Sass [sass.Value] objects into [Value] protobufs. +/// +/// A given [Protofier] instance is valid only within the scope of a single +/// custom function call. +class Protofier { + /// The dispatcher, for invoking deprotofied [Value_HostFunction]s. + final Dispatcher _dispatcher; + + /// The IDs of first-class functions. + final FunctionRegistry _functions; + + /// The ID of the current compilation. + final int _compilationId; + + /// Any argument lists transitively contained in [value]. + /// + /// The IDs of the [Value_ArgumentList] protobufs are always one greater than + /// the index of the corresponding list in this array (since 0 is reserved for + /// argument lists created by the host). + final _argumentLists = []; + + /// Creates a [Protofier] that's valid within the scope of a single custom + /// function call. + /// + /// The [functions] tracks the IDs of first-class functions so that the host + /// can pass them back to the compiler. + Protofier(this._dispatcher, this._functions, this._compilationId); + + /// Converts [value] to its protocol buffer representation. + Value protofy(sass.Value value) { + var result = Value(); + if (value is sass.SassString) { + result.string = Value_String() + ..text = value.text + ..quoted = value.hasQuotes; + } else if (value is sass.SassNumber) { + var number = Value_Number()..value = value.value * 1.0; + number.numerators.addAll(value.numeratorUnits); + number.denominators.addAll(value.denominatorUnits); + result.number = number; + } else if (value is sass.SassColor) { + // TODO(nweiz): If the color is represented as HSL internally, this coerces + // it to RGB. Is it worth providing some visibility into its internal + // representation so we can serialize without converting? + result.rgbColor = Value_RgbColor() + ..red = value.red + ..green = value.green + ..blue = value.blue + ..alpha = value.alpha * 1.0; + } else if (value is sass.SassArgumentList) { + _argumentLists.add(value); + var argList = Value_ArgumentList() + ..id = _argumentLists.length + ..separator = _protofySeparator(value.separator) + ..contents.addAll([for (var element in value.asList) protofy(element)]); + value.keywordsWithoutMarking.forEach((key, value) { + argList.keywords[key] = protofy(value); + }); + + result.argumentList = argList; + } else if (value is sass.SassList) { + result.list = Value_List() + ..separator = _protofySeparator(value.separator) + ..hasBrackets = value.hasBrackets + ..contents.addAll([for (var element in value.asList) protofy(element)]); + } else if (value is sass.SassMap) { + var map = Value_Map(); + value.contents.forEach((key, value) { + map.entries.add(Value_Map_Entry() + ..key = protofy(key) + ..value = protofy(value)); + }); + result.map = map; + } else if (value is sass.SassFunction) { + result.compilerFunction = _functions.protofy(value); + } else if (value == sass.sassTrue) { + result.singleton = SingletonValue.TRUE; + } else if (value == sass.sassFalse) { + result.singleton = SingletonValue.FALSE; + } else if (value == sass.sassNull) { + result.singleton = SingletonValue.NULL; + } else { + throw "Unknown Value $value"; + } + return result; + } + + /// Converts [separator] to its protocol buffer representation. + ListSeparator _protofySeparator(sass.ListSeparator separator) { + switch (separator) { + case sass.ListSeparator.comma: + return ListSeparator.COMMA; + case sass.ListSeparator.space: + return ListSeparator.SPACE; + case sass.ListSeparator.slash: + return ListSeparator.SLASH; + case sass.ListSeparator.undecided: + return ListSeparator.UNDECIDED; + default: + throw "Unknown ListSeparator $separator"; + } + } + + /// Converts [response]'s return value to its Sass representation. + sass.Value deprotofyResponse(InboundMessage_FunctionCallResponse response) { + for (var id in response.accessedArgumentLists) { + // Mark the `keywords` field as accessed. + _argumentListForId(id).keywords; + } + + return _deprotofy(response.success); + } + + /// Converts [value] to its Sass representation. + sass.Value _deprotofy(Value value) { + try { + switch (value.whichValue()) { + case Value_Value.string: + return value.string.text.isEmpty + ? sass.SassString.empty(quotes: value.string.quoted) + : sass.SassString(value.string.text, quotes: value.string.quoted); + + case Value_Value.number: + return sass.SassNumber.withUnits(value.number.value, + numeratorUnits: value.number.numerators, + denominatorUnits: value.number.denominators); + + case Value_Value.rgbColor: + return sass.SassColor.rgb(value.rgbColor.red, value.rgbColor.green, + value.rgbColor.blue, value.rgbColor.alpha); + + case Value_Value.hslColor: + return sass.SassColor.hsl( + value.hslColor.hue, + value.hslColor.saturation, + value.hslColor.lightness, + value.hslColor.alpha); + + case Value_Value.argumentList: + if (value.argumentList.id != 0) { + return _argumentListForId(value.argumentList.id); + } + + var separator = _deprotofySeparator(value.argumentList.separator); + var length = value.argumentList.contents.length; + if (separator == sass.ListSeparator.undecided && length > 1) { + throw paramsError( + "List $value can't have an undecided separator because it has " + "$length elements"); + } + + return sass.SassArgumentList([ + for (var element in value.argumentList.contents) _deprotofy(element) + ], { + for (var entry in value.argumentList.keywords.entries) + entry.key: _deprotofy(entry.value) + }, separator); + + case Value_Value.list: + var separator = _deprotofySeparator(value.list.separator); + if (value.list.contents.isEmpty) { + return sass.SassList.empty( + separator: separator, brackets: value.list.hasBrackets); + } + + var length = value.list.contents.length; + if (separator == sass.ListSeparator.undecided && length > 1) { + throw paramsError( + "List $value can't have an undecided separator because it has " + "$length elements"); + } + + return sass.SassList([ + for (var element in value.list.contents) _deprotofy(element) + ], separator, brackets: value.list.hasBrackets); + + case Value_Value.map: + return value.map.entries.isEmpty + ? const sass.SassMap.empty() + : sass.SassMap({ + for (var entry in value.map.entries) + _deprotofy(entry.key): _deprotofy(entry.value) + }); + + case Value_Value.compilerFunction: + var id = value.compilerFunction.id; + var function = _functions[id]; + if (function == null) { + throw paramsError( + "CompilerFunction.id $id doesn't match any known functions"); + } + + return function; + + case Value_Value.hostFunction: + return sass.SassFunction(hostCallable(_dispatcher, _functions, + _compilationId, value.hostFunction.signature, + id: value.hostFunction.id)); + + case Value_Value.singleton: + switch (value.singleton) { + case SingletonValue.TRUE: + return sass.sassTrue; + case SingletonValue.FALSE: + return sass.sassFalse; + case SingletonValue.NULL: + return sass.sassNull; + default: + throw "Unknown Value.singleton ${value.singleton}"; + } + + case Value_Value.notSet: + throw mandatoryError("Value.value"); + } + } on RangeError catch (error) { + var name = error.name; + if (name == null || error.start == null || error.end == null) { + throw paramsError(error.toString()); + } + + if (value.whichValue() == Value_Value.rgbColor) { + name = 'RgbColor.$name'; + } else if (value.whichValue() == Value_Value.hslColor) { + name = 'HslColor.$name'; + } + + throw paramsError( + '$name must be between ${error.start} and ${error.end}, was ' + '${error.invalidValue}'); + } + } + + /// Returns the argument list in [_argumentLists] that corresponds to [id]. + sass.SassArgumentList _argumentListForId(int id) { + if (id < 1) { + throw paramsError( + "Value.ArgumentList.id $id can't be marked as accessed"); + } else if (id > _argumentLists.length) { + throw paramsError( + "Value.ArgumentList.id $id doesn't match any known argument " + "lists"); + } else { + return _argumentLists[id - 1]; + } + } + + /// Converts [separator] to its Sass representation. + sass.ListSeparator _deprotofySeparator(ListSeparator separator) { + switch (separator) { + case ListSeparator.COMMA: + return sass.ListSeparator.comma; + case ListSeparator.SPACE: + return sass.ListSeparator.space; + case ListSeparator.SLASH: + return sass.ListSeparator.slash; + case ListSeparator.UNDECIDED: + return sass.ListSeparator.undecided; + default: + throw "Unknown separator $separator"; + } + } +} diff --git a/pubspec.yaml b/pubspec.yaml index c2b3662e5..f6bd6ca24 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.0.0-beta.10 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 protobuf: ^2.0.0 - sass: ^1.36.0 + sass: ^1.38.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" diff --git a/test/function_test.dart b/test/function_test.dart index e0ccb6a58..4a263039b 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -133,22 +133,74 @@ void main() { await _process.kill(); }); - test("from argument lists", () async { - _process.inbound.add(compileString("a {b: foo(true, false, null)}", - functions: [r"foo($arg, $args...)"])); - var request = getFunctionCallRequest(await _process.outbound.next); + group("from argument lists", () { + test("with no named arguments", () async { + _process.inbound.add(compileString("a {b: foo(true, false, null)}", + functions: [r"foo($arg, $args...)"])); + var request = getFunctionCallRequest(await _process.outbound.next); - expect( - request.arguments, - equals([ - _true, - Value() - ..list = (Value_List() - ..separator = ListSeparator.COMMA - ..hasBrackets = false - ..contents.addAll([_false, _null])) - ])); - await _process.kill(); + expect( + request.arguments, + equals([ + _true, + Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..separator = ListSeparator.COMMA + ..contents.addAll([_false, _null])) + ])); + await _process.kill(); + }); + + test("with named arguments", () async { + _process.inbound.add(compileString(r"a {b: foo(true, $arg: false)}", + functions: [r"foo($args...)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + + expect( + request.arguments, + equals([ + Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..separator = ListSeparator.COMMA + ..contents.addAll([_true]) + ..keywords.addAll({"arg": _false})) + ])); + await _process.kill(); + }); + + test("throws if named arguments are unused", () async { + _process.inbound.add(compileString(r"a {b: foo($arg: false)}", + functions: [r"foo($args...)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = _true)); + + var failure = getCompileFailure(await _process.outbound.next); + expect(failure.message, equals(r"No argument named $arg.")); + await _process.kill(); + }); + + test("doesn't throw if named arguments are used", () async { + _process.inbound.add(compileString(r"a {b: foo($arg: false)}", + functions: [r"foo($args...)"])); + var request = getFunctionCallRequest(await _process.outbound.next); + + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..accessedArgumentLists + .add(request.arguments.first.argumentList.id) + ..success = _true)); + + await expectLater(_process.outbound, + emits(isSuccess(equals("a {\n b: true;\n}")))); + await _process.kill(); + }); }); }); }); @@ -646,6 +698,48 @@ void main() { }); }); + group("an argument list", () { + test("that's empty", () async { + var list = (await _protofy(r"capture-args()")).argumentList; + expect(list.contents, isEmpty); + expect(list.keywords, isEmpty); + expect(list.separator, equals(ListSeparator.COMMA)); + }); + + test("with arguments", () async { + var list = + (await _protofy(r"capture-args(true, null, false)")).argumentList; + expect(list.contents, [_true, _null, _false]); + expect(list.keywords, isEmpty); + expect(list.separator, equals(ListSeparator.COMMA)); + }); + + test("with a space separator", () async { + var list = + (await _protofy(r"capture-args(true null false...)")).argumentList; + expect(list.contents, [_true, _null, _false]); + expect(list.keywords, isEmpty); + expect(list.separator, equals(ListSeparator.SPACE)); + }); + + test("with a slash separator", () async { + var list = + (await _protofy(r"capture-args(list.slash(true, null, false)...)")) + .argumentList; + expect(list.contents, [_true, _null, _false]); + expect(list.keywords, isEmpty); + expect(list.separator, equals(ListSeparator.SLASH)); + }); + + test("with keywords", () async { + var list = (await _protofy(r"capture-args($arg1: true, $arg2: false)")) + .argumentList; + expect(list.contents, isEmpty); + expect(list.keywords, equals({"arg1": _true, "arg2": _false})); + expect(list.separator, equals(ListSeparator.COMMA)); + }); + }); + group("a map", () { test("with no elements", () async { expect((await _protofy("map.remove((1: 2), 1)")).map.entries, isEmpty); @@ -1159,6 +1253,71 @@ void main() { }); }); + group("an argument list", () { + test("with no elements", () async { + expect( + await _roundTrip(Value() + ..argumentList = + (Value_ArgumentList()..separator = ListSeparator.UNDECIDED)), + equals(Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..separator = ListSeparator.UNDECIDED))); + }); + + test("with comma separator", () async { + expect( + await _roundTrip(Value() + ..argumentList = (Value_ArgumentList() + ..contents.addAll([_true, _false, _null]) + ..separator = ListSeparator.COMMA)), + equals(Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..contents.addAll([_true, _false, _null]) + ..separator = ListSeparator.COMMA))); + }); + + test("with space separator", () async { + expect( + await _roundTrip(Value() + ..argumentList = (Value_ArgumentList() + ..contents.addAll([_true, _false, _null]) + ..separator = ListSeparator.SPACE)), + equals(Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..contents.addAll([_true, _false, _null]) + ..separator = ListSeparator.SPACE))); + }); + + test("with slash separator", () async { + expect( + await _roundTrip(Value() + ..argumentList = (Value_ArgumentList() + ..contents.addAll([_true, _false, _null]) + ..separator = ListSeparator.SLASH)), + equals(Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..contents.addAll([_true, _false, _null]) + ..separator = ListSeparator.SLASH))); + }); + + test("with keywords", () async { + expect( + await _roundTrip(Value() + ..argumentList = (Value_ArgumentList() + ..keywords.addAll({"arg1": _true, "arg2": _false}) + ..separator = ListSeparator.COMMA)), + equals(Value() + ..argumentList = (Value_ArgumentList() + ..id = 1 + ..keywords.addAll({"arg1": _true, "arg2": _false}) + ..separator = ListSeparator.COMMA))); + }); + }); + group("a map", () { group("with no elements", () { _testSerializationAndRoundTrip(Value()..map = Value_Map(), "()", @@ -1289,6 +1448,13 @@ void main() { endsWith("can't have an undecided separator because it has 2 " "elements")); }); + + test("an arglist with an unknown id", () async { + await _expectDeprotofyError( + Value()..argumentList = (Value_ArgumentList()..id = 1), + equals( + "Value.ArgumentList.id 1 doesn't match any known argument lists")); + }); }); }); } @@ -1300,6 +1466,12 @@ Future _protofy(String sassScript) async { @use 'sass:list'; @use 'sass:map'; @use 'sass:math'; +@use 'sass:meta'; + +@function capture-args(\$args...) { + \$_: meta.keywords(\$args); + @return \$args; +} \$_: foo(($sassScript)); """, functions: [r"foo($arg)"])); From 439669327625e0500f159c8d220cb61b33f89eab Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 30 Aug 2021 17:15:06 -0700 Subject: [PATCH 057/162] Support consuming Value.HwbColor and emitting Value.HslColor (#54) --- CHANGELOG.md | 7 ++++++ lib/src/function_registry.dart | 2 +- lib/src/host_callable.dart | 2 +- lib/src/importer.dart | 2 +- lib/src/logger.dart | 2 +- lib/src/protofier.dart | 30 ++++++++++++++++++-------- lib/src/utils.dart | 2 +- lib/src/value.dart | 2 +- pubspec.yaml | 4 ++-- test/function_test.dart | 39 ++++++++++++++++------------------ 10 files changed, 54 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe916c74..0aaf3777a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.0.0-beta.11 + +* Support version 1.0.0-beta.13 of the Sass embedded protocol: + * Support `Value.HwbColor`. + * Emit colors as `Value.HslColor` if that internal representation is + available. + ## 1.0.0-beta.10 * Support version 1.0.0-beta.12 of the Sass embedded protocol: diff --git a/lib/src/function_registry.dart b/lib/src/function_registry.dart index f8ca94b71..cd8c7086d 100644 --- a/lib/src/function_registry.dart +++ b/lib/src/function_registry.dart @@ -2,7 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'embedded_sass.pb.dart'; diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index 924116922..f869dcb1e 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -5,7 +5,7 @@ import 'dart:cli'; import 'dart:io'; -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'dispatcher.dart'; import 'embedded_sass.pb.dart'; diff --git a/lib/src/importer.dart b/lib/src/importer.dart index da1dfe538..37e488cc0 100644 --- a/lib/src/importer.dart +++ b/lib/src/importer.dart @@ -4,7 +4,7 @@ import 'dart:cli'; -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'dispatcher.dart'; import 'embedded_sass.pb.dart' hide SourceSpan; diff --git a/lib/src/logger.dart b/lib/src/logger.dart index 55b365f41..9aa31b7ff 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -3,7 +3,7 @@ // https://opensource.org/licenses/MIT. import 'package:path/path.dart' as p; -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; diff --git a/lib/src/protofier.dart b/lib/src/protofier.dart index 3c2ef53d8..8f021c383 100644 --- a/lib/src/protofier.dart +++ b/lib/src/protofier.dart @@ -2,7 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'dispatcher.dart'; import 'embedded_sass.pb.dart'; @@ -51,14 +51,19 @@ class Protofier { number.denominators.addAll(value.denominatorUnits); result.number = number; } else if (value is sass.SassColor) { - // TODO(nweiz): If the color is represented as HSL internally, this coerces - // it to RGB. Is it worth providing some visibility into its internal - // representation so we can serialize without converting? - result.rgbColor = Value_RgbColor() - ..red = value.red - ..green = value.green - ..blue = value.blue - ..alpha = value.alpha * 1.0; + if (value.hasCalculatedHsl) { + result.hslColor = Value_HslColor() + ..hue = value.hue * 1.0 + ..saturation = value.saturation * 1.0 + ..lightness = value.lightness * 1.0 + ..alpha = value.alpha * 1.0; + } else { + result.rgbColor = Value_RgbColor() + ..red = value.red + ..green = value.green + ..blue = value.blue + ..alpha = value.alpha * 1.0; + } } else if (value is sass.SassArgumentList) { _argumentLists.add(value); var argList = Value_ArgumentList() @@ -148,6 +153,13 @@ class Protofier { value.hslColor.lightness, value.hslColor.alpha); + case Value_Value.hwbColor: + return sass.SassColor.hwb( + value.hwbColor.hue, + value.hwbColor.whiteness, + value.hwbColor.blackness, + value.hwbColor.alpha); + case Value_Value.argumentList: if (value.argumentList.id != 0) { return _argumentListForId(value.argumentList.id); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 4f2b2059b..16cf103e7 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -2,7 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'package:source_span/source_span.dart'; import 'package:term_glyph/term_glyph.dart' as term_glyph; diff --git a/lib/src/value.dart b/lib/src/value.dart index a0f62f779..246478035 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -2,7 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. -import 'package:sass/sass.dart' as sass; +import 'package:sass_api/sass_api.dart' as sass; import 'dispatcher.dart'; import 'embedded_sass.pb.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index f6bd6ca24..8fa2880b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.10 +version: 1.0.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 protobuf: ^2.0.0 - sass: ^1.38.0 + sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" diff --git a/test/function_test.dart b/test/function_test.dart index 4a263039b..fbb38980a 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -447,60 +447,57 @@ void main() { group("without alpha:", () { group("hue", () { test("0", () async { - expect( - await _protofy('hsl(0, 50%, 50%)'), _rgb(191, 64, 64, 1.0)); + expect(await _protofy('hsl(0, 50%, 50%)'), _hsl(0, 50, 50, 1.0)); }); test("360", () async { expect( - await _protofy('hsl(360, 50%, 50%)'), _rgb(191, 64, 64, 1.0)); + await _protofy('hsl(360, 50%, 50%)'), _hsl(0, 50, 50, 1.0)); }); test("below 0", () async { expect(await _protofy('hsl(-100, 50%, 50%)'), - _rgb(106, 64, 191, 1.0)); + _hsl(260, 50, 50, 1.0)); }); test("between 0 and 360", () async { - expect(await _protofy('hsl(100, 50%, 50%)'), - _rgb(106, 191, 64, 1.0)); + expect( + await _protofy('hsl(100, 50%, 50%)'), _hsl(100, 50, 50, 1.0)); }); test("above 360", () async { - expect(await _protofy('hsl(560, 50%, 50%)'), - _rgb(64, 149, 191, 1.0)); + expect( + await _protofy('hsl(560, 50%, 50%)'), _hsl(200, 50, 50, 1.0)); }); }); group("saturation", () { test("0", () async { - expect( - await _protofy('hsl(0, 0%, 50%)'), _rgb(128, 128, 128, 1.0)); + expect(await _protofy('hsl(0, 0%, 50%)'), _hsl(0, 0, 50, 1.0)); }); test("100", () async { - expect(await _protofy('hsl(0, 100%, 50%)'), _rgb(255, 0, 0, 1.0)); + expect( + await _protofy('hsl(0, 100%, 50%)'), _hsl(0, 100, 50, 1.0)); }); test("in the middle", () async { - expect( - await _protofy('hsl(0, 42%, 50%)'), _rgb(181, 74, 74, 1.0)); + expect(await _protofy('hsl(0, 42%, 50%)'), _hsl(0, 42, 50, 1.0)); }); }); group("lightness", () { test("0", () async { - expect(await _protofy('hsl(0, 50%, 0%)'), _rgb(0, 0, 0, 1.0)); + expect(await _protofy('hsl(0, 50%, 0%)'), _hsl(0, 50, 0, 1.0)); }); test("100", () async { - expect(await _protofy('hsl(0, 50%, 100%)'), - _rgb(255, 255, 255, 1.0)); + expect( + await _protofy('hsl(0, 50%, 100%)'), _hsl(0, 50, 100, 1.0)); }); test("in the middle", () async { - expect( - await _protofy('hsl(0, 50%, 42%)'), _rgb(161, 54, 54, 1.0)); + expect(await _protofy('hsl(0, 50%, 42%)'), _hsl(0, 50, 42, 1.0)); }); }); }); @@ -508,17 +505,17 @@ void main() { group("with alpha", () { test("0", () async { expect(await _protofy('hsl(10, 20%, 30%, 0)'), - equals(_rgb(92, 66, 61, 0.0))); + equals(_hsl(10, 20, 30, 0.0))); }); test("1", () async { expect(await _protofy('hsl(10, 20%, 30%, 1)'), - equals(_rgb(92, 66, 61, 1.0))); + equals(_hsl(10, 20, 30, 1.0))); }); test("between 0 and 1", () async { expect(await _protofy('hsl(10, 20%, 30%, 0.123)'), - equals(_rgb(92, 66, 61, 0.123))); + equals(_hsl(10, 20, 30, 0.123))); }); }); }); From d2063513af2763a39cbedcd1425ce02c9a754136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 1 Sep 2021 17:33:09 -0700 Subject: [PATCH 058/162] Implement --version flag for cli (#53) Co-authored-by: Natalie Weizenbaum --- CHANGELOG.md | 3 +++ README.md | 5 +++++ bin/dart_sass_embedded.dart | 8 ++++++++ lib/src/dispatcher.dart | 24 ++++++++++++++---------- pubspec.yaml | 2 +- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aaf3777a..c5bd31ec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * Emit colors as `Value.HslColor` if that internal representation is available. +* Add a `--version` flag that will print a `VersionResponse` as JSON, for ease + of human identification. + ## 1.0.0-beta.10 * Support version 1.0.0-beta.12 of the Sass embedded protocol: diff --git a/README.md b/README.md index aa839b7a4..e534c0fcb 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,11 @@ and importers. [Dart Sass]: https://sass-lang.com/dart-sass [Embedded Sass protocol]: https://github.com/sass/sass-embedded-protocol/blob/master/README.md#readme +### Usage + +- `dart_sass_embedded` starts the compiler and listens on stdin. +- `dart_sass_embedded --version` prints `versionResponse` with `id = 0` in JSON and exits. + ### Releases Binary releases are available from the [GitHub release page]. We recommend that diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 6730036da..5663fda05 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -19,6 +19,14 @@ import 'package:sass_embedded/src/utils.dart'; void main(List args) { if (args.isNotEmpty) { + if (args.first == "--version") { + var response = Dispatcher.versionResponse(); + response.id = 0; + stdout.writeln( + JsonEncoder.withIndent(" ").convert(response.toProto3Json())); + return; + } + stderr.writeln( "This executable is not intended to be executed with arguments.\n" "See https://github.com/sass/embedded-protocol#readme for details."); diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 2a77f20ec..6c8ed1d22 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -57,16 +57,10 @@ class Dispatcher { switch (message.whichMessage()) { case InboundMessage_Message.versionRequest: - _send(OutboundMessage() - ..versionResponse = (OutboundMessage_VersionResponse() - ..protocolVersion = - const String.fromEnvironment("protocol-version") - ..compilerVersion = - const String.fromEnvironment("compiler-version") - ..implementationVersion = - const String.fromEnvironment("implementation-version") - ..implementationName = "Dart Sass" - ..id = message.versionRequest.id)); + var request = message.versionRequest; + var response = versionResponse(); + response.id = request.id; + _send(OutboundMessage()..versionResponse = response); break; case InboundMessage_Message.compileRequest: @@ -226,4 +220,14 @@ class Dispatcher { break; } } + + /// Creates a [OutboundMessage_VersionResponse] + static OutboundMessage_VersionResponse versionResponse() { + return OutboundMessage_VersionResponse() + ..protocolVersion = const String.fromEnvironment("protocol-version") + ..compilerVersion = const String.fromEnvironment("compiler-version") + ..implementationVersion = + const String.fromEnvironment("implementation-version") + ..implementationName = "Dart Sass"; + } } diff --git a/pubspec.yaml b/pubspec.yaml index 8fa2880b1..d71602263 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.0.0-beta.11 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 53cbcdb58e4edd969706b29c00422f81ffc8d81b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 29 Sep 2021 00:17:11 +0000 Subject: [PATCH 059/162] Add support for calculations (#55) See sass/sass#818 --- CHANGELOG.md | 5 + lib/src/protofier.dart | 167 +++++++++++++++- pubspec.yaml | 3 +- test/function_test.dart | 345 ++++++++++++++++++++++++++++++++ test/length_delimited_test.dart | 5 +- 5 files changed, 516 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5bd31ec4..bfe3ae74f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.0.0-beta.12 + +* Support version 1.0.0-beta.14 of the Sass embedded protocol: + * Support `Value.Calculation`. + ## 1.0.0-beta.11 * Support version 1.0.0-beta.13 of the Sass embedded protocol: diff --git a/lib/src/protofier.dart b/lib/src/protofier.dart index 8f021c383..e948a7c66 100644 --- a/lib/src/protofier.dart +++ b/lib/src/protofier.dart @@ -46,10 +46,7 @@ class Protofier { ..text = value.text ..quoted = value.hasQuotes; } else if (value is sass.SassNumber) { - var number = Value_Number()..value = value.value * 1.0; - number.numerators.addAll(value.numeratorUnits); - number.denominators.addAll(value.denominatorUnits); - result.number = number; + result.number = _protofyNumber(value); } else if (value is sass.SassColor) { if (value.hasCalculatedHsl) { result.hslColor = Value_HslColor() @@ -88,6 +85,8 @@ class Protofier { ..value = protofy(value)); }); result.map = map; + } else if (value is sass.SassCalculation) { + result.calculation = _protofyCalculation(value); } else if (value is sass.SassFunction) { result.compilerFunction = _functions.protofy(value); } else if (value == sass.sassTrue) { @@ -102,6 +101,14 @@ class Protofier { return result; } + /// Converts [number] to its protocol buffer representation. + Value_Number _protofyNumber(sass.SassNumber number) { + var value = Value_Number()..value = number.value * 1.0; + value.numerators.addAll(number.numeratorUnits); + value.denominators.addAll(number.denominatorUnits); + return value; + } + /// Converts [separator] to its protocol buffer representation. ListSeparator _protofySeparator(sass.ListSeparator separator) { switch (separator) { @@ -118,6 +125,55 @@ class Protofier { } } + /// Converts [calculation] to its protocol buffer representation. + Value_Calculation _protofyCalculation(sass.SassCalculation calculation) => + Value_Calculation() + ..name = calculation.name + ..arguments.addAll([ + for (var argument in calculation.arguments) + _protofyCalculationValue(argument) + ]); + + /// Converts a calculation value that appears within a `SassCalculation` to + /// its protocol buffer representation. + Value_Calculation_CalculationValue _protofyCalculationValue(Object value) { + var result = Value_Calculation_CalculationValue(); + if (value is sass.SassNumber) { + result.number = _protofyNumber(value); + } else if (value is sass.SassCalculation) { + result.calculation = _protofyCalculation(value); + } else if (value is sass.SassString) { + result.string = value.text; + } else if (value is sass.CalculationOperation) { + result.operation = Value_Calculation_CalculationOperation() + ..operator = _protofyCalculationOperator(value.operator) + ..left = _protofyCalculationValue(value.left) + ..right = _protofyCalculationValue(value.right); + } else if (value is sass.CalculationInterpolation) { + result.interpolation = value.value; + } else { + throw "Unknown calculation value $value"; + } + return result; + } + + /// Converts [operator] to its protocol buffer representation. + CalculationOperator _protofyCalculationOperator( + sass.CalculationOperator operator) { + switch (operator) { + case sass.CalculationOperator.plus: + return CalculationOperator.PLUS; + case sass.CalculationOperator.minus: + return CalculationOperator.MINUS; + case sass.CalculationOperator.times: + return CalculationOperator.TIMES; + case sass.CalculationOperator.dividedBy: + return CalculationOperator.DIVIDE; + default: + throw "Unknown CalculationOperator $operator"; + } + } + /// Converts [response]'s return value to its Sass representation. sass.Value deprotofyResponse(InboundMessage_FunctionCallResponse response) { for (var id in response.accessedArgumentLists) { @@ -138,9 +194,7 @@ class Protofier { : sass.SassString(value.string.text, quotes: value.string.quoted); case Value_Value.number: - return sass.SassNumber.withUnits(value.number.value, - numeratorUnits: value.number.numerators, - denominatorUnits: value.number.denominators); + return _deprotofyNumber(value.number); case Value_Value.rgbColor: return sass.SassColor.rgb(value.rgbColor.red, value.rgbColor.green, @@ -221,6 +275,9 @@ class Protofier { _compilationId, value.hostFunction.signature, id: value.hostFunction.id)); + case Value_Value.calculation: + return _deprotofyCalculation(value.calculation); + case Value_Value.singleton: switch (value.singleton) { case SingletonValue.TRUE: @@ -254,6 +311,12 @@ class Protofier { } } + /// Converts [number] to its Sass representation. + sass.SassNumber _deprotofyNumber(Value_Number number) => + sass.SassNumber.withUnits(number.value, + numeratorUnits: number.numerators, + denominatorUnits: number.denominators); + /// Returns the argument list in [_argumentLists] that corresponds to [id]. sass.SassArgumentList _argumentListForId(int id) { if (id < 1) { @@ -283,4 +346,94 @@ class Protofier { throw "Unknown separator $separator"; } } + + /// Converts [calculation] to its Sass representation. + sass.Value _deprotofyCalculation(Value_Calculation calculation) { + if (calculation.name == "calc") { + if (calculation.arguments.length != 1) { + throw paramsError( + "Value.Calculation.arguments must have exactly one argument for " + "calc()."); + } + + return sass.SassCalculation.calc( + _deprotofyCalculationValue(calculation.arguments[0])); + } else if (calculation.name == "clamp") { + if (calculation.arguments.length != 3) { + throw paramsError( + "Value.Calculation.arguments must have exactly 3 arguments for " + "clamp()."); + } + + return sass.SassCalculation.clamp( + _deprotofyCalculationValue(calculation.arguments[0]), + _deprotofyCalculationValue(calculation.arguments[1]), + _deprotofyCalculationValue(calculation.arguments[2])); + } else if (calculation.name == "min") { + if (calculation.arguments.isEmpty) { + throw paramsError( + "Value.Calculation.arguments must have at least 1 argument for " + "min()."); + } + + return sass.SassCalculation.min( + calculation.arguments.map(_deprotofyCalculationValue)); + } else if (calculation.name == "max") { + if (calculation.arguments.isEmpty) { + throw paramsError( + "Value.Calculation.arguments must have at least 1 argument for " + "max()."); + } + + return sass.SassCalculation.max( + calculation.arguments.map(_deprotofyCalculationValue)); + } else { + throw paramsError( + 'Value.Calculation.name "${calculation.name}" is not a recognized ' + 'calculation type.'); + } + } + + /// Converts [value] to its Sass representation. + Object _deprotofyCalculationValue(Value_Calculation_CalculationValue value) { + switch (value.whichValue()) { + case Value_Calculation_CalculationValue_Value.number: + return _deprotofyNumber(value.number); + + case Value_Calculation_CalculationValue_Value.calculation: + return _deprotofyCalculation(value.calculation); + + case Value_Calculation_CalculationValue_Value.string: + return sass.SassString(value.string, quotes: false); + + case Value_Calculation_CalculationValue_Value.operation: + return sass.SassCalculation.operate( + _deprotofyCalculationOperator(value.operation.operator), + _deprotofyCalculationValue(value.operation.left), + _deprotofyCalculationValue(value.operation.right)); + + case Value_Calculation_CalculationValue_Value.interpolation: + return sass.CalculationInterpolation(value.interpolation); + + case Value_Calculation_CalculationValue_Value.notSet: + throw mandatoryError("Value.Calculation.value"); + } + } + + /// Converts [operator] to its Sass representation. + sass.CalculationOperator _deprotofyCalculationOperator( + CalculationOperator operator) { + switch (operator) { + case CalculationOperator.PLUS: + return sass.CalculationOperator.plus; + case CalculationOperator.MINUS: + return sass.CalculationOperator.minus; + case CalculationOperator.TIMES: + return sass.CalculationOperator.times; + case CalculationOperator.DIVIDE: + return sass.CalculationOperator.dividedBy; + default: + throw "Unknown CalculationOperator $operator"; + } + } } diff --git a/pubspec.yaml b/pubspec.yaml index d71602263..21cbf5b8b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.11 +version: 1.0.0-beta.12 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded @@ -14,6 +14,7 @@ dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 protobuf: ^2.0.0 + sass: ^1.42.0 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 diff --git a/test/function_test.dart b/test/function_test.dart index fbb38980a..c33f654ed 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -775,6 +775,85 @@ void main() { }); }); + group("a calculation", () { + test("with a string argument", () async { + expect( + (await _protofy("calc(var(--foo))")).calculation, + equals(Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..string = "var(--foo)"))); + }); + + test("with an interpolation argument", () async { + expect( + (await _protofy("calc(#{var(--foo)})")).calculation, + equals(Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..interpolation = "var(--foo)"))); + }); + + test("with number arguments", () async { + expect( + (await _protofy("clamp(1%, 2px, 3em)")).calculation, + equals(Value_Calculation() + ..name = "clamp" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 3.0 + ..numerators.add("em"))))); + }); + + test("with a calculation argument", () async { + expect( + (await _protofy("min(max(1%, 2px), 3em)")).calculation, + equals(Value_Calculation() + ..name = "min" + ..arguments.add(Value_Calculation_CalculationValue() + ..calculation = (Value_Calculation() + ..name = "max" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 3.0 + ..numerators.add("em"))))); + }); + + test("with an operation", () async { + expect( + (await _protofy("calc(1% + 2px)")).calculation, + equals(Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..operation = (Value_Calculation_CalculationOperation() + ..operator = CalculationOperator.PLUS + ..left = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..right = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))))))); + }); + }); + test("true", () async { expect((await _protofy("true")), equals(_true)); }); @@ -1362,6 +1441,175 @@ void main() { }); }); + group("a calculation", () { + test("with a string argument", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..string = "var(--foo)"))), + "calc(var(--foo))"); + }); + + test("with an interpolation argument", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..interpolation = "var(--foo)"))), + "calc(var(--foo))"); + }); + + test("with number arguments", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "clamp" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 3.0 + ..numerators.add("em"))))), + "clamp(1%, 2px, 3em)"); + }); + + test("with a calculation argument", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "min" + ..arguments.add(Value_Calculation_CalculationValue() + ..calculation = (Value_Calculation() + ..name = "max" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 3.0 + ..numerators.add("em"))))), + "min(max(1%, 2px), 3em)"); + }); + + test("with an operation", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..operation = (Value_Calculation_CalculationOperation() + ..operator = CalculationOperator.PLUS + ..left = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..right = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))))))), + "calc(1% + 2px)"); + }); + + group("simplifies", () { + test("an operation", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..operation = (Value_Calculation_CalculationOperation() + ..operator = CalculationOperator.PLUS + ..left = (Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..right = (Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0)))))), + "3"); + }); + + test("a nested operation", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..operation = (Value_Calculation_CalculationOperation() + ..operator = CalculationOperator.PLUS + ..left = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("%"))) + ..right = (Value_Calculation_CalculationValue() + ..operation = (Value_Calculation_CalculationOperation() + ..operator = CalculationOperator.PLUS + ..left = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("px"))) + ..right = (Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 3.0 + ..numerators.add("px"))))))))), + "calc(1% + 5px)"); + }); + + test("min", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "min" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 3.0)))), + "1"); + }); + + test("max", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "max" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 3.0)))), + "3"); + }); + + test("clamp", () async { + expect( + await _deprotofy(Value() + ..calculation = (Value_Calculation() + ..name = "clamp" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 3.0)))), + "2"); + }); + }); + }); + test("true", () async { expect(await _deprotofy(_true), equals("true")); }); @@ -1452,6 +1700,103 @@ void main() { equals( "Value.ArgumentList.id 1 doesn't match any known argument lists")); }); + + group("a calculation", () { + group("with too many arguments", () { + test("for calc", () async { + await _expectDeprotofyError( + Value() + ..calculation = (Value_Calculation() + ..name = "calc" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0))), + equals("Value.Calculation.arguments must have exactly one " + "argument for calc().")); + }); + + test("for clamp", () async { + await _expectDeprotofyError( + Value() + ..calculation = (Value_Calculation() + ..name = "clamp" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 3.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 4.0))), + equals("Value.Calculation.arguments must have exactly 3 " + "arguments for clamp().")); + }); + }); + + group("with too few arguments", () { + test("for calc", () async { + await _expectDeprotofyError( + Value()..calculation = (Value_Calculation()..name = "calc"), + equals("Value.Calculation.arguments must have exactly one " + "argument for calc().")); + }); + + test("for clamp", () async { + await _expectDeprotofyError( + Value() + ..calculation = (Value_Calculation() + ..name = "clamp" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 1.0)) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number()..value = 2.0))), + equals("Value.Calculation.arguments must have exactly 3 " + "arguments for clamp().")); + }); + + test("for min", () async { + await _expectDeprotofyError( + Value()..calculation = (Value_Calculation()..name = "min"), + equals("Value.Calculation.arguments must have at least 1 " + "argument for min().")); + }); + + test("for max", () async { + await _expectDeprotofyError( + Value()..calculation = (Value_Calculation()..name = "max"), + equals("Value.Calculation.arguments must have at least 1 " + "argument for max().")); + }); + }); + + test("reports a compilation failure when simplification fails", + () async { + _process.inbound + .add(compileString("a {b: foo()}", functions: [r"foo()"])); + + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, isEmpty); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = (Value() + ..calculation = (Value_Calculation() + ..name = "min" + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 1.0 + ..numerators.add("px"))) + ..arguments.add(Value_Calculation_CalculationValue() + ..number = (Value_Number() + ..value = 2.0 + ..numerators.add("s"))))))); + + var failure = await getCompileFailure(await _process.outbound.next); + expect(failure.message, equals("1px and 2s are incompatible.")); + expect(_process.kill(), completes); + }); + }); }); }); } diff --git a/test/length_delimited_test.dart b/test/length_delimited_test.dart index 38c247b8c..525367a49 100644 --- a/test/length_delimited_test.dart +++ b/test/length_delimited_test.dart @@ -79,7 +79,10 @@ void main() { }); test("from multiple chunks", () { - sink..add([172])..add([2, 1])..add(List.filled(299, 1)); + sink + ..add([172]) + ..add([2, 1]) + ..add(List.filled(299, 1)); expect(queue, emits(List.filled(300, 1))); }); From 17f1e69a4669b8faefee1b79e2f3ea718bac140b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 14 Dec 2021 15:43:35 -0800 Subject: [PATCH 060/162] Report a better error message for an empty CompileRequest.Input.path (#56) --- CHANGELOG.md | 4 ++++ bin/dart_sass_embedded.dart | 4 ++++ pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe3ae74f..352481ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-beta.13 + +* Report a better error message for an empty `CompileRequest.Input.path`. + ## 1.0.0-beta.12 * Support version 1.0.0-beta.14 of the Sass embedded protocol: diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 5663fda05..a75e0cfc5 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -75,6 +75,10 @@ void main(List args) { break; case InboundMessage_CompileRequest_Input.path: + if (request.path.isEmpty) { + throw mandatoryError("CompileRequest.Input.path"); + } + try { result = sass.compileToResult(request.path, color: request.alertColor, diff --git a/pubspec.yaml b/pubspec.yaml index 21cbf5b8b..cdf35c4a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.12 +version: 1.0.0-beta.13 description: An implementation of the Sass embedded protocol using Dart Sass. author: Sass Team homepage: https://github.com/sass/dart-sass-embedded From 1cbb0c5417faf62e814bd48a16c0105b08db6d55 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 15 Dec 2021 15:40:10 -0800 Subject: [PATCH 061/162] Implement FileImporter (#57) --- CHANGELOG.md | 4 + bin/dart_sass_embedded.dart | 9 +- lib/src/dispatcher.dart | 18 +- lib/src/importer/base.dart | 45 +++ lib/src/importer/file.dart | 66 +++++ lib/src/{importer.dart => importer/host.dart} | 48 +-- pubspec.yaml | 3 +- test/file_importer_test.dart | 280 ++++++++++++++++++ test/utils.dart | 10 + 9 files changed, 439 insertions(+), 44 deletions(-) create mode 100644 lib/src/importer/base.dart create mode 100644 lib/src/importer/file.dart rename lib/src/{importer.dart => importer/host.dart} (57%) create mode 100644 test/file_importer_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 352481ada..e99ac6259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-beta.14 + +* Support `FileImporter`s. + ## 1.0.0-beta.13 * Report a better error message for an empty `CompileRequest.Input.path`. diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index a75e0cfc5..5cbccb02c 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -12,7 +12,8 @@ import 'package:sass_embedded/src/dispatcher.dart'; import 'package:sass_embedded/src/embedded_sass.pb.dart'; import 'package:sass_embedded/src/function_registry.dart'; import 'package:sass_embedded/src/host_callable.dart'; -import 'package:sass_embedded/src/importer.dart'; +import 'package:sass_embedded/src/importer/file.dart'; +import 'package:sass_embedded/src/importer/host.dart'; import 'package:sass_embedded/src/logger.dart'; import 'package:sass_embedded/src/util/length_delimited_transformer.dart'; import 'package:sass_embedded/src/utils.dart'; @@ -125,7 +126,7 @@ void main(List args) { }); } -/// Converts [importer] into an [Importer]. +/// Converts [importer] into a [sass.Importer]. sass.Importer? _decodeImporter( Dispatcher dispatcher, InboundMessage_CompileRequest request, @@ -135,10 +136,10 @@ sass.Importer? _decodeImporter( return sass.FilesystemImporter(importer.path); case InboundMessage_CompileRequest_Importer_Importer.importerId: - return Importer(dispatcher, request.id, importer.importerId); + return HostImporter(dispatcher, request.id, importer.importerId); case InboundMessage_CompileRequest_Importer_Importer.fileImporterId: - throw "CompileRequest.Importer.fileImporterId is not yet supported"; + return FileImporter(dispatcher, request.id, importer.fileImporterId); case InboundMessage_CompileRequest_Importer_Importer.notSet: return null; diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 6c8ed1d22..881cb4b5b 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -80,6 +80,11 @@ class Dispatcher { _dispatchResponse(response.id, response); break; + case InboundMessage_Message.fileImportResponse: + var response = message.fileImportResponse; + _dispatchResponse(response.id, response); + break; + case InboundMessage_Message.functionCallResponse: var response = message.functionCallResponse; _dispatchResponse(response.id, response); @@ -131,6 +136,11 @@ class Dispatcher { _sendRequest( OutboundMessage()..importRequest = request); + Future sendFileImportRequest( + OutboundMessage_FileImportRequest request) => + _sendRequest( + OutboundMessage()..fileImportRequest = request); + Future sendFunctionCallRequest( OutboundMessage_FunctionCallRequest request) => _sendRequest( @@ -165,8 +175,12 @@ class Dispatcher { /// Throws an error if there's no outstanding request with the given [id] or /// if that request is expecting a different type of response. void _dispatchResponse(int id, T response) { - var completer = - id < _outstandingRequests.length ? _outstandingRequests[id] : null; + Completer? completer; + if (id < _outstandingRequests.length) { + completer = _outstandingRequests[id]; + _outstandingRequests[id] = null; + } + if (completer == null) { throw paramsError( "Response ID $id doesn't match any outstanding requests."); diff --git a/lib/src/importer/base.dart b/lib/src/importer/base.dart new file mode 100644 index 000000000..b1a6ae603 --- /dev/null +++ b/lib/src/importer/base.dart @@ -0,0 +1,45 @@ +// Copyright 2021 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:meta/meta.dart'; +import 'package:sass_api/sass_api.dart' as sass; + +import '../dispatcher.dart'; +import '../embedded_sass.pb.dart' hide SourceSpan; +import '../utils.dart'; + +/// An abstract base class for importers that communicate with the host in some +/// way. +abstract class ImporterBase extends sass.Importer { + /// The [Dispatcher] to which to send requests. + @protected + final Dispatcher dispatcher; + + ImporterBase(this.dispatcher); + + /// Parses [url] as a [Uri] and throws an error if it's invalid or relative + /// (including root-relative). + /// + /// The [field] name is used in the error message if one is thrown. + @protected + Uri parseAbsoluteUrl(String field, String url) { + Uri parsedUrl; + try { + parsedUrl = Uri.parse(url); + } on FormatException catch (error) { + sendAndThrow(paramsError("$field is invalid: $error")); + } + + if (parsedUrl.scheme.isNotEmpty) return parsedUrl; + sendAndThrow(paramsError('$field must be absolute, was "$parsedUrl"')); + } + + /// Sends [error] to the remote endpoint, and also throws it so that the Sass + /// compilation fails. + @protected + Never sendAndThrow(ProtocolError error) { + dispatcher.sendError(error); + throw "Protocol error: ${error.message}"; + } +} diff --git a/lib/src/importer/file.dart b/lib/src/importer/file.dart new file mode 100644 index 000000000..19181963d --- /dev/null +++ b/lib/src/importer/file.dart @@ -0,0 +1,66 @@ +// Copyright 2021 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:cli'; + +import 'package:sass_api/sass_api.dart' as sass; + +import '../dispatcher.dart'; +import '../embedded_sass.pb.dart' hide SourceSpan; +import '../utils.dart'; +import 'base.dart'; + +/// A filesystem importer to use for most implementation details of +/// [FileImporter]. +/// +/// This allows us to avoid duplicating logic between the two importers. +final _filesystemImporter = sass.FilesystemImporter('.'); + +/// An importer that asks the host to resolve imports in a simplified, +/// file-system-centric way. +class FileImporter extends ImporterBase { + /// The ID of the compilation in which this importer is used. + final int _compilationId; + + /// The host-provided ID of the importer to invoke. + final int _importerId; + + FileImporter(Dispatcher dispatcher, this._compilationId, this._importerId) + : super(dispatcher); + + Uri? canonicalize(Uri url) { + if (url.scheme == 'file') return _filesystemImporter.canonicalize(url); + + return waitFor(() async { + var response = await dispatcher + .sendFileImportRequest(OutboundMessage_FileImportRequest() + ..compilationId = _compilationId + ..importerId = _importerId + ..url = url.toString() + ..fromImport = fromImport); + + switch (response.whichResult()) { + case InboundMessage_FileImportResponse_Result.fileUrl: + var url = + parseAbsoluteUrl("FileImportResponse.file_url", response.fileUrl); + if (url.scheme != 'file') { + sendAndThrow(paramsError( + 'FileImportResponse.file_url must be a file: URL, was "$url"')); + } + + return _filesystemImporter.canonicalize(url); + + case InboundMessage_FileImportResponse_Result.error: + throw response.error; + + case InboundMessage_FileImportResponse_Result.notSet: + return null; + } + }()); + } + + sass.ImporterResult? load(Uri url) => _filesystemImporter.load(url); + + String toString() => "FileImporter"; +} diff --git a/lib/src/importer.dart b/lib/src/importer/host.dart similarity index 57% rename from lib/src/importer.dart rename to lib/src/importer/host.dart index 37e488cc0..2187f4ccf 100644 --- a/lib/src/importer.dart +++ b/lib/src/importer/host.dart @@ -6,26 +6,25 @@ import 'dart:cli'; import 'package:sass_api/sass_api.dart' as sass; -import 'dispatcher.dart'; -import 'embedded_sass.pb.dart' hide SourceSpan; -import 'utils.dart'; +import '../dispatcher.dart'; +import '../embedded_sass.pb.dart' hide SourceSpan; +import '../utils.dart'; +import 'base.dart'; /// An importer that asks the host to resolve imports. -class Importer extends sass.Importer { - /// The [Dispatcher] to which to send requests. - final Dispatcher _dispatcher; - +class HostImporter extends ImporterBase { /// The ID of the compilation in which this importer is used. final int _compilationId; /// The host-provided ID of the importer to invoke. final int _importerId; - Importer(this._dispatcher, this._compilationId, this._importerId); + HostImporter(Dispatcher dispatcher, this._compilationId, this._importerId) + : super(dispatcher); Uri? canonicalize(Uri url) { return waitFor(() async { - var response = await _dispatcher + var response = await dispatcher .sendCanonicalizeRequest(OutboundMessage_CanonicalizeRequest() ..compilationId = _compilationId ..importerId = _importerId @@ -34,7 +33,7 @@ class Importer extends sass.Importer { switch (response.whichResult()) { case InboundMessage_CanonicalizeResponse_Result.url: - return _parseAbsoluteUrl("CanonicalizeResponse.url", response.url); + return parseAbsoluteUrl("CanonicalizeResponse.url", response.url); case InboundMessage_CanonicalizeResponse_Result.error: throw response.error; @@ -48,7 +47,7 @@ class Importer extends sass.Importer { sass.ImporterResult load(Uri url) { return waitFor(() async { var response = - await _dispatcher.sendImportRequest(OutboundMessage_ImportRequest() + await dispatcher.sendImportRequest(OutboundMessage_ImportRequest() ..compilationId = _compilationId ..importerId = _importerId ..url = url.toString()); @@ -58,7 +57,7 @@ class Importer extends sass.Importer { return sass.ImporterResult(response.success.contents, sourceMapUrl: response.success.sourceMapUrl.isEmpty ? null - : _parseAbsoluteUrl("ImportResponse.success.source_map_url", + : parseAbsoluteUrl("ImportResponse.success.source_map_url", response.success.sourceMapUrl), syntax: syntaxToSyntax(response.success.syntax)); @@ -66,33 +65,10 @@ class Importer extends sass.Importer { throw response.error; case InboundMessage_ImportResponse_Result.notSet: - _sendAndThrow(mandatoryError("ImportResponse.result")); + sendAndThrow(mandatoryError("ImportResponse.result")); } }()); } - /// Parses [url] as a [Uri] and throws an error if it's invalid or relative - /// (including root-relative). - /// - /// The [field] name is used in the error message if one is thrown. - Uri _parseAbsoluteUrl(String field, String url) { - Uri parsedUrl; - try { - parsedUrl = Uri.parse(url); - } on FormatException catch (error) { - _sendAndThrow(paramsError("$field is invalid: $error")); - } - - if (parsedUrl.scheme.isNotEmpty) return parsedUrl; - _sendAndThrow(paramsError('$field must be absolute, was "$parsedUrl"')); - } - - /// Sends [error] to the remote endpoint, and also throws it so that the Sass - /// compilation fails. - Never _sendAndThrow(ProtocolError error) { - _dispatcher.sendError(error); - throw "Protocol error: ${error.message}"; - } - String toString() => "HostImporter"; } diff --git a/pubspec.yaml b/pubspec.yaml index cdf35c4a5..aac5b66ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,6 @@ name: sass_embedded -version: 1.0.0-beta.13 +version: 1.0.0-beta.14 description: An implementation of the Sass embedded protocol using Dart Sass. -author: Sass Team homepage: https://github.com/sass/dart-sass-embedded environment: diff --git a/test/file_importer_test.dart b/test/file_importer_test.dart new file mode 100644 index 000000000..16b9b2a5d --- /dev/null +++ b/test/file_importer_test.dart @@ -0,0 +1,280 @@ +// Copyright 2021 Google LLC. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; +import 'package:test_descriptor/test_descriptor.dart' as d; + +import 'package:sass_embedded/src/embedded_sass.pb.dart'; +import 'package:sass_embedded/src/utils.dart'; + +import 'embedded_process.dart'; +import 'utils.dart'; + +void main() { + late EmbeddedProcess process; + setUp(() async { + process = await EmbeddedProcess.start(); + }); + + group("emits a protocol error", () { + late OutboundMessage_FileImportRequest request; + + setUp(() async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..fileImporterId = 1 + ])); + + request = getFileImportRequest(await process.outbound.next); + }); + + test("for a response without a corresponding request ID", () async { + process.inbound.add(InboundMessage() + ..fileImportResponse = + (InboundMessage_FileImportResponse()..id = request.id + 1)); + + await expectParamsError( + process, + errorId, + "Response ID ${request.id + 1} doesn't match any outstanding " + "requests."); + await process.kill(); + }); + + test("for a response that doesn't match the request type", () async { + process.inbound.add(InboundMessage() + ..canonicalizeResponse = + (InboundMessage_CanonicalizeResponse()..id = request.id)); + + await expectParamsError( + process, + errorId, + "Request ID ${request.id} doesn't match response type " + "InboundMessage_CanonicalizeResponse."); + await process.kill(); + }); + + group("for a FileImportResponse with a URL", () { + test("that's empty", () async { + process.inbound.add(InboundMessage() + ..fileImportResponse = (InboundMessage_FileImportResponse() + ..id = request.id + ..fileUrl = "")); + + await _expectImportParamsError( + process, 'FileImportResponse.file_url must be absolute, was ""'); + await process.kill(); + }); + + test("that's relative", () async { + process.inbound.add(InboundMessage() + ..fileImportResponse = (InboundMessage_FileImportResponse() + ..id = request.id + ..fileUrl = "foo")); + + await _expectImportParamsError( + process, 'FileImportResponse.file_url must be absolute, was "foo"'); + await process.kill(); + }); + + test("that's not file:", () async { + process.inbound.add(InboundMessage() + ..fileImportResponse = (InboundMessage_FileImportResponse() + ..id = request.id + ..fileUrl = "other:foo")); + + await _expectImportParamsError(process, + 'FileImportResponse.file_url must be a file: URL, was "other:foo"'); + await process.kill(); + }); + }); + }); + + group("includes in FileImportRequest", () { + var compilationId = 1234; + var importerId = 5679; + late OutboundMessage_FileImportRequest request; + setUp(() async { + process.inbound.add( + compileString("@import 'other'", id: compilationId, importers: [ + InboundMessage_CompileRequest_Importer()..fileImporterId = importerId + ])); + request = getFileImportRequest(await process.outbound.next); + }); + + test("the same compilationId as the compilation", () async { + expect(request.compilationId, equals(compilationId)); + await process.kill(); + }); + + test("a known importerId", () async { + expect(request.importerId, equals(importerId)); + await process.kill(); + }); + + test("the imported URL", () async { + expect(request.url, equals("other")); + await process.kill(); + }); + + test("whether the import came from an @import", () async { + expect(request.fromImport, isTrue); + await process.kill(); + }); + }); + + test("errors cause compilation to fail", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..fileImporterId = 1 + ])); + + var request = getFileImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..fileImportResponse = (InboundMessage_FileImportResponse() + ..id = request.id + ..error = "oh no")); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals('oh no')); + expect(failure.span.text, equals("'other'")); + expect(failure.stackTrace, equals('- 1:9 root stylesheet\n')); + await process.kill(); + }); + + test("null results count as not found", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..fileImporterId = 1 + ])); + + var request = getFileImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..fileImportResponse = + (InboundMessage_FileImportResponse()..id = request.id)); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals("Can't find stylesheet to import.")); + expect(failure.span.text, equals("'other'")); + await process.kill(); + }); + + group("attempts importers in order", () { + test("with multiple file importers", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + for (var i = 0; i < 10; i++) + InboundMessage_CompileRequest_Importer()..fileImporterId = i + ])); + + for (var i = 0; i < 10; i++) { + var request = getFileImportRequest(await process.outbound.next); + expect(request.importerId, equals(i)); + process.inbound.add(InboundMessage() + ..fileImportResponse = + (InboundMessage_FileImportResponse()..id = request.id)); + } + + await process.kill(); + }); + + test("with a mixture of file and normal importers", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + for (var i = 0; i < 10; i++) + if (i % 2 == 0) + InboundMessage_CompileRequest_Importer()..fileImporterId = i + else + InboundMessage_CompileRequest_Importer()..importerId = i + ])); + + for (var i = 0; i < 10; i++) { + if (i % 2 == 0) { + var request = getFileImportRequest(await process.outbound.next); + expect(request.importerId, equals(i)); + process.inbound.add(InboundMessage() + ..fileImportResponse = + (InboundMessage_FileImportResponse()..id = request.id)); + } else { + var request = getCanonicalizeRequest(await process.outbound.next); + expect(request.importerId, equals(i)); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = + (InboundMessage_CanonicalizeResponse()..id = request.id)); + } + } + + await process.kill(); + }); + }); + + test("tries resolved URL as a relative path first", () async { + await d.file("upstream.scss", "a {b: c}").create(); + await d.file("midstream.scss", "@import 'upstream';").create(); + + process.inbound.add(compileString("@import 'midstream'", importers: [ + for (var i = 0; i < 10; i++) + InboundMessage_CompileRequest_Importer()..fileImporterId = i + ])); + + for (var i = 0; i < 5; i++) { + var request = getFileImportRequest(await process.outbound.next); + expect(request.url, equals("midstream")); + expect(request.importerId, equals(i)); + process.inbound.add(InboundMessage() + ..fileImportResponse = + (InboundMessage_FileImportResponse()..id = request.id)); + } + + var request = getFileImportRequest(await process.outbound.next); + expect(request.importerId, equals(5)); + process.inbound.add(InboundMessage() + ..fileImportResponse = (InboundMessage_FileImportResponse() + ..id = request.id + ..fileUrl = p.toUri(d.path("midstream")).toString())); + + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + + group("handles an importer for a string compile request", () { + setUp(() async { + await d.file("other.scss", "a {b: c}").create(); + }); + + test("without a base URL", () async { + process.inbound.add(compileString("@import 'other'", + importer: InboundMessage_CompileRequest_Importer() + ..fileImporterId = 1)); + + var request = getFileImportRequest(await process.outbound.next); + expect(request.url, equals("other")); + + process.inbound.add(InboundMessage() + ..fileImportResponse = (InboundMessage_FileImportResponse() + ..id = request.id + ..fileUrl = p.toUri(d.path("other")).toString())); + + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + + test("with a base URL", () async { + process.inbound.add(compileString("@import 'other'", + url: p.toUri(d.path("input")).toString(), + importer: InboundMessage_CompileRequest_Importer() + ..fileImporterId = 1)); + + await expectLater(process.outbound, emits(isSuccess("a { b: c; }"))); + await process.kill(); + }); + }); +} + +/// Asserts that [process] emits a [ProtocolError] params error with the given +/// [message] on its protobuf stream and causes the compilation to fail. +Future _expectImportParamsError(EmbeddedProcess process, message) async { + await expectLater(process.outbound, + emits(isProtocolError(errorId, ProtocolErrorType.PARAMS, message))); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals('Protocol error: $message')); + expect(failure.span.text, equals("'other'")); +} diff --git a/test/utils.dart b/test/utils.dart index 1f6f73346..67c37c633 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -103,6 +103,16 @@ OutboundMessage_ImportRequest getImportRequest(value) { return message.importRequest; } +/// Asserts that [message] is an [OutboundMessage] with a `FileImportRequest` +/// and returns it. +OutboundMessage_FileImportRequest getFileImportRequest(value) { + expect(value, isA()); + var message = value as OutboundMessage; + expect(message.hasFileImportRequest(), isTrue, + reason: "Expected $message to have a FileImportRequest"); + return message.fileImportRequest; +} + /// Asserts that [message] is an [OutboundMessage] with a /// `FunctionCallRequest` and returns it. OutboundMessage_FunctionCallRequest getFunctionCallRequest(value) { From 26127d8a00095b65bdfe9819eed8f9c85eb21923 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 29 Dec 2021 15:00:16 -0800 Subject: [PATCH 062/162] Treat invalid function signatures as function errors (#58) See sass/embedded-protocol#85 --- CHANGELOG.md | 6 +++ bin/dart_sass_embedded.dart | 9 +++- lib/src/host_callable.dart | 79 ++++++++++++++---------------- pubspec.yaml | 2 +- test/function_test.dart | 96 ++++++++++++++++++++++++++++++++----- 5 files changed, 135 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e99ac6259..f306b549b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.0.0-beta.15 + +* Support version 1.0.0-beta.16 of the Sass embedded protocol: + * Treat invalid host function signatures as function errors rather than + protocol errors. + ## 1.0.0-beta.14 * Support `FileImporter`s. diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 5cbccb02c..10c8d8312 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -54,8 +54,13 @@ void main(List args) { _decodeImporter(dispatcher, request, importer) ?? (throw mandatoryError("Importer.importer"))); - var globalFunctions = request.globalFunctions.map((signature) => - hostCallable(dispatcher, functions, request.id, signature)); + var globalFunctions = request.globalFunctions.map((signature) { + try { + return hostCallable(dispatcher, functions, request.id, signature); + } on sass.SassException catch (error) { + throw paramsError('CompileRequest.global_functions: $error'); + } + }); late sass.CompileResult result; switch (request.whichInput()) { diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index f869dcb1e..a62a090ce 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -6,6 +6,7 @@ import 'dart:cli'; import 'dart:io'; import 'package:sass_api/sass_api.dart' as sass; +import 'package:source_span/source_span.dart'; import 'dispatcher.dart'; import 'embedded_sass.pb.dart'; @@ -20,60 +21,54 @@ import 'utils.dart'; /// anonymous functions defined on the host). Otherwise, it will be called using /// the name defined in the [signature]. /// -/// Throws a [ProtocolError] if [signature] is invalid. +/// Throws a [sass.SassException] if [signature] is invalid. sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, int compilationId, String signature, {int? id}) { var openParen = signature.indexOf('('); - if (openParen == -1) { - throw paramsError( - 'CompileRequest.global_functions: "$signature" is missing "("'); - } + if (openParen == -1) + throw sass.SassException('"$signature" is missing "("', + SourceFile.fromString(signature).span(0)); if (!signature.endsWith(")")) { - throw paramsError( - 'CompileRequest.global_functions: "$signature" doesn\'t end with ' - '")"'); + throw sass.SassException('"$signature" doesn\'t end with ")"', + SourceFile.fromString(signature).span(signature.length)); } var name = signature.substring(0, openParen); - try { - return sass.Callable.function( - name, signature.substring(openParen + 1, signature.length - 1), - (arguments) { - var protofier = Protofier(dispatcher, functions, compilationId); - var request = OutboundMessage_FunctionCallRequest() - ..compilationId = compilationId - ..arguments.addAll( - [for (var argument in arguments) protofier.protofy(argument)]); + return sass.Callable.function( + name, signature.substring(openParen + 1, signature.length - 1), + (arguments) { + var protofier = Protofier(dispatcher, functions, compilationId); + var request = OutboundMessage_FunctionCallRequest() + ..compilationId = compilationId + ..arguments.addAll( + [for (var argument in arguments) protofier.protofy(argument)]); - if (id != null) { - request.functionId = id; - } else { - request.name = name; - } + if (id != null) { + request.functionId = id; + } else { + request.name = name; + } - var response = waitFor(dispatcher.sendFunctionCallRequest(request)); - try { - switch (response.whichResult()) { - case InboundMessage_FunctionCallResponse_Result.success: - return protofier.deprotofyResponse(response); + var response = waitFor(dispatcher.sendFunctionCallRequest(request)); + try { + switch (response.whichResult()) { + case InboundMessage_FunctionCallResponse_Result.success: + return protofier.deprotofyResponse(response); - case InboundMessage_FunctionCallResponse_Result.error: - throw response.error; + case InboundMessage_FunctionCallResponse_Result.error: + throw response.error; - case InboundMessage_FunctionCallResponse_Result.notSet: - throw mandatoryError('FunctionCallResponse.result'); - } - } on ProtocolError catch (error) { - error.id = errorId; - stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " - "${error.message}"); - dispatcher.sendError(error); - throw error.message; + case InboundMessage_FunctionCallResponse_Result.notSet: + throw mandatoryError('FunctionCallResponse.result'); } - }); - } on sass.SassException catch (error) { - throw paramsError('CompileRequest.global_functions: $error'); - } + } on ProtocolError catch (error) { + error.id = errorId; + stderr.writeln("Host caused ${error.type.name.toLowerCase()} error: " + "${error.message}"); + dispatcher.sendError(error); + throw error.message; + } + }); } diff --git a/pubspec.yaml b/pubspec.yaml index aac5b66ea..318d194e0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.14 +version: 1.0.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded diff --git a/test/function_test.dart b/test/function_test.dart index c33f654ed..42393d1de 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -21,36 +21,64 @@ void main() { _process = await EmbeddedProcess.start(); }); - group("emits a protocol error", () { - test("for an empty signature", () async { + group("emits a protocol error for a custom function with a signature", () { + test("that's empty", () async { _process.inbound.add(compileString("a {b: c}", functions: [r""])); await expectParamsError( - _process, 0, 'CompileRequest.global_functions: "" is missing "("'); + _process, + 0, + 'CompileRequest.global_functions: Error: "" is missing "("\n' + ' ╷\n' + '1 │ \n' + ' │ ^\n' + ' ╵\n' + ' - 1:1 root stylesheet'); await _process.kill(); }); - test("for a signature with just a name", () async { + test("that's just a name", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo"])); await expectParamsError( - _process, 0, 'CompileRequest.global_functions: "foo" is missing "("'); + _process, + 0, + 'CompileRequest.global_functions: Error: "foo" is missing "("\n' + ' ╷\n' + '1 │ foo\n' + ' │ ^^^\n' + ' ╵\n' + ' - 1:1 root stylesheet'); await _process.kill(); }); - test("for a signature without a closing paren", () async { + test("without a closing paren", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo($bar"])); - await expectParamsError(_process, 0, - 'CompileRequest.global_functions: "foo(\$bar" doesn\'t end with ")"'); + await expectParamsError( + _process, + 0, + 'CompileRequest.global_functions: Error: "foo(\$bar" doesn\'t end with ")"\n' + ' ╷\n' + '1 │ foo(\$bar\n' + ' │ ^\n' + ' ╵\n' + ' - 1:9 root stylesheet'); await _process.kill(); }); - test("for a signature with text after the closing paren", () async { + test("with text after the closing paren", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo() "])); - await expectParamsError(_process, 0, - 'CompileRequest.global_functions: "foo() " doesn\'t end with ")"'); + await expectParamsError( + _process, + 0, + 'CompileRequest.global_functions: Error: "foo() " doesn\'t end with ")"\n' + ' ╷\n' + '1 │ foo() \n' + ' │ ^\n' + ' ╵\n' + ' - 1:7 root stylesheet'); await _process.kill(); }); - test("for a signature with invalid arguments", () async { + test("with invalid arguments", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo($)"])); await expectParamsError( _process, @@ -1797,6 +1825,50 @@ void main() { expect(_process.kill(), completes); }); }); + + group("reports a compilation error for a function with a signature", () { + Future expectSignatureError( + String signature, Object message) async { + _process.inbound.add( + compileString("a {b: inspect(foo())}", functions: [r"foo()"])); + + var request = getFunctionCallRequest(await _process.outbound.next); + expect(request.arguments, isEmpty); + _process.inbound.add(InboundMessage() + ..functionCallResponse = (InboundMessage_FunctionCallResponse() + ..id = request.id + ..success = (Value() + ..hostFunction = (Value_HostFunction() + ..id = 1234 + ..signature = signature)))); + + var failure = await getCompileFailure(await _process.outbound.next); + expect(failure.message, message); + expect(_process.kill(), completes); + } + + test("that's empty", () async { + await expectSignatureError("", '"" is missing "("'); + }); + + test("that's just a name", () async { + await expectSignatureError("foo", '"foo" is missing "("'); + }); + + test("without a closing paren", () async { + await expectSignatureError( + r"foo($bar", '"foo(\$bar" doesn\'t end with ")"'); + }); + + test("with text after the closing paren", () async { + await expectSignatureError( + r"foo() ", '"foo() " doesn\'t end with ")"'); + }); + + test("with invalid arguments", () async { + await expectSignatureError(r"foo($)", 'Expected identifier.'); + }); + }); }); }); } From 5012b5c3da851bf683b709e50b138e6f8e72c0f4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 29 Dec 2021 16:01:03 -0800 Subject: [PATCH 063/162] Allow ImporterResponse.result to be null (#59) --- CHANGELOG.md | 5 ++++- lib/src/importer/host.dart | 4 ++-- test/importer_test.dart | 38 +++++++++++++++++++++++--------------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f306b549b..f8e789a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ ## 1.0.0-beta.15 -* Support version 1.0.0-beta.16 of the Sass embedded protocol: +* Support version 1.0.0-beta.17 of the Sass embedded protocol: + * Treat invalid host function signatures as function errors rather than protocol errors. + * Allow `ImportResponse.result` to be null. + ## 1.0.0-beta.14 * Support `FileImporter`s. diff --git a/lib/src/importer/host.dart b/lib/src/importer/host.dart index 2187f4ccf..e1a0f9734 100644 --- a/lib/src/importer/host.dart +++ b/lib/src/importer/host.dart @@ -44,7 +44,7 @@ class HostImporter extends ImporterBase { }()); } - sass.ImporterResult load(Uri url) { + sass.ImporterResult? load(Uri url) { return waitFor(() async { var response = await dispatcher.sendImportRequest(OutboundMessage_ImportRequest() @@ -65,7 +65,7 @@ class HostImporter extends ImporterBase { throw response.error; case InboundMessage_ImportResponse_Result.notSet: - sendAndThrow(mandatoryError("ImportResponse.result")); + return null; } }()); } diff --git a/test/importer_test.dart b/test/importer_test.dart index ef4afdc44..a553d958a 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -217,21 +217,6 @@ void main() { group("importing", () { group("emits a protocol error", () { - test("for an unset import result", () async { - process.inbound.add(compileString("@import 'other'", importers: [ - InboundMessage_CompileRequest_Importer()..importerId = 1 - ])); - await _canonicalize(process); - - var import = getImportRequest(await process.outbound.next); - process.inbound.add(InboundMessage() - ..importResponse = (InboundMessage_ImportResponse()..id = import.id)); - - await _expectImportParamsError( - process, "Missing mandatory field ImportResponse.result"); - await process.kill(); - }); - test("for an import result with a relative sourceMapUrl", () async { process.inbound.add(compileString("@import 'other'", importers: [ InboundMessage_CompileRequest_Importer()..importerId = 1 @@ -289,6 +274,29 @@ void main() { }); }); + test("null results count as not found", () async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..importerId = 1 + ])); + + var canonicalizeRequest = + getCanonicalizeRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..canonicalizeResponse = (InboundMessage_CanonicalizeResponse() + ..id = canonicalizeRequest.id + ..url = "o:other")); + + var importRequest = getImportRequest(await process.outbound.next); + process.inbound.add(InboundMessage() + ..importResponse = + (InboundMessage_ImportResponse()..id = importRequest.id)); + + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals("Can't find stylesheet to import.")); + expect(failure.span.text, equals("'other'")); + await process.kill(); + }); + test("errors cause compilation to fail", () async { process.inbound.add(compileString("@import 'other'", importers: [ InboundMessage_CompileRequest_Importer()..importerId = 1 From 21f0219157b4f0b8c59242cc7bb86ef7e03a76ec Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 29 Dec 2021 17:18:10 -0800 Subject: [PATCH 064/162] Don't return a CompileFailure without a span (#60) We weren't adding a span for a compile failure due to a path not being found. There's no real source in this situation, so we just create an empty span instead. --- CHANGELOG.md | 2 ++ bin/dart_sass_embedded.dart | 7 ++++++- pubspec.yaml | 4 ++-- test/protocol_test.dart | 6 +++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8e789a82..c4c8caeb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * Allow `ImportResponse.result` to be null. +* Fix a bug where the compiler could return a `CompileFailure` without a span. + ## 1.0.0-beta.14 * Support `FileImporter`s. diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 10c8d8312..21c8ad6b5 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'dart:convert'; +import 'package:path/path.dart' as p; import 'package:sass/sass.dart' as sass; import 'package:stream_channel/stream_channel.dart'; @@ -100,7 +101,11 @@ void main(List args) { ..failure = (OutboundMessage_CompileResponse_CompileFailure() ..message = error.path == null ? error.message - : "${error.message}: ${error.path}"); + : "${error.message}: ${error.path}" + ..span = (SourceSpan() + ..start = SourceSpan_SourceLocation() + ..end = SourceSpan_SourceLocation() + ..url = p.toUri(request.path).toString())); } break; diff --git a/pubspec.yaml b/pubspec.yaml index 318d194e0..6b93a88c1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.0.0-beta.15 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -12,6 +12,7 @@ executables: dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 + path: ^1.6.0 protobuf: ^2.0.0 sass: ^1.42.0 sass_api: ^1.0.0-beta.5 @@ -24,7 +25,6 @@ dev_dependencies: cli_pkg: ^1.4.0 grinder: ^0.9.0 protoc_plugin: ^20.0.0 - path: ^1.6.0 test: ^1.0.0 test_descriptor: ^2.0.0 yaml: ^3.1.0 diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 930881ea6..1b79f418a 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -300,7 +300,11 @@ void main() { expect(failure.message, startsWith("Cannot open file: ")); expect(failure.message.replaceFirst("Cannot open file: ", "").trim(), equalsPath(d.path('test.scss'))); - expect(failure.span, equals(SourceSpan())); + expect(failure.span.text, equals('')); + expect(failure.span.context, equals('')); + expect(failure.span.start, equals(SourceSpan_SourceLocation())); + expect(failure.span.end, equals(SourceSpan_SourceLocation())); + expect(failure.span.url, equals(p.toUri(d.path('test.scss')).toString())); expect(failure.stackTrace, isEmpty); await process.kill(); }); From e3e25c787c30ef400d3731ce59db2e056154ae48 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 30 Dec 2021 14:01:54 -0800 Subject: [PATCH 065/162] Commit the lockfile (#63) Closes #61 --- .gitignore | 2 - pubspec.lock | 495 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 495 insertions(+), 2 deletions(-) create mode 100644 pubspec.lock diff --git a/.gitignore b/.gitignore index 2bc89f310..a075e0626 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,6 @@ .dart_tool/ .packages build/ -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock # Directory created by dartdoc # If you don't generate documentation locally you can remove this line. diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 000000000..e21cb1856 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,495 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "22.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.2" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.6" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + async: + dependency: "direct main" + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_pkg: + dependency: "direct dev" + description: + name: cli_pkg + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + cli_repl: + dependency: transitive + description: + name: cli_repl + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.2" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.14" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + grinder: + dependency: "direct dev" + description: + name: grinder + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.0" + http: + dependency: transitive + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.11" + meta: + dependency: "direct main" + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + node_interop: + dependency: transitive + description: + name: node_interop + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + path: + dependency: "direct main" + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + protobuf: + dependency: "direct main" + description: + name: protobuf + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + protoc_plugin: + dependency: "direct dev" + description: + name: protoc_plugin + url: "https://pub.dartlang.org" + source: hosted + version: "20.0.0" + pub_semver: + dependency: "direct dev" + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + pubspec_parse: + dependency: "direct dev" + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1+1" + sass: + dependency: "direct main" + description: + name: sass + url: "https://pub.dartlang.org" + source: hosted + version: "1.45.1" + sass_api: + dependency: "direct main" + description: + name: sass_api + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0-beta.24" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.10" + source_span: + dependency: "direct main" + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: "direct main" + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: "direct main" + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test: + dependency: "direct dev" + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.18.1" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.5" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.4" + test_descriptor: + dependency: "direct dev" + description: + name: test_descriptor + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + test_process: + dependency: transitive + description: + name: test_process + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + tuple: + dependency: transitive + description: + name: tuple + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + typed_data: + dependency: "direct main" + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "7.5.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "5.3.1" + yaml: + dependency: "direct dev" + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" +sdks: + dart: ">=2.14.0 <3.0.0" From ff0afc3451f59e3720e085738f45724206a04cd2 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 14 Jan 2022 00:20:13 +0000 Subject: [PATCH 066/162] Update dependency versions (#65) --- CHANGELOG.md | 7 +++++++ pubspec.lock | 8 ++++---- pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4c8caeb7..46098447c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.0.0-beta.16 + +* Upgrade to Sass 1.48.0. + +* Fix a bug where the compiler could crash when an error was detected in a + stylesheet provided by string. + ## 1.0.0-beta.15 * Support version 1.0.0-beta.17 of the Sass embedded protocol: diff --git a/pubspec.lock b/pubspec.lock index e21cb1856..798b2e0a9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,7 +21,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.8" args: dependency: transitive description: @@ -308,14 +308,14 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.45.1" + version: "1.48.0" sass_api: dependency: "direct main" description: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.24" + version: "1.0.0-beta.28" shelf: dependency: transitive description: @@ -364,7 +364,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 6b93a88c1..1c2e1bd4e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.15 +version: 1.0.0-beta.16 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded From 53464a7979a609d88e8320a3faac7f3e119d98e1 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 25 Jan 2022 17:16:17 -0800 Subject: [PATCH 067/162] Use the Sass shared Dart analysis options (#67) --- analysis_options.yaml | 3 +++ lib/src/dispatcher.dart | 2 +- lib/src/host_callable.dart | 5 ++++- lib/src/importer/file.dart | 2 ++ lib/src/importer/host.dart | 3 +++ lib/src/value.dart | 2 +- pubspec.lock | 16 ++++++++++++++++ pubspec.yaml | 2 ++ test/embedded_process.dart | 10 +++++----- test/file_importer_test.dart | 3 ++- test/function_test.dart | 8 ++++---- test/importer_test.dart | 3 ++- test/protocol_test.dart | 2 +- test/utils.dart | 27 +++++++++++++++------------ tool/grind.dart | 6 +++--- 15 files changed, 64 insertions(+), 30 deletions(-) create mode 100644 analysis_options.yaml diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 000000000..33f240d10 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,3 @@ +include: package:sass_analysis/analysis_options.yaml +analyzer: + exclude: ['**/*.pb*.dart'] diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index 881cb4b5b..e215c779a 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -45,7 +45,7 @@ class Dispatcher { // microtask from the initial request dispatch. Otherwise, [waitFor] will // deadlock the event loop fiber that would otherwise be checking stdin // for new input. - await Future.value(); + await Future.value(); InboundMessage? message; try { diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index a62a090ce..203ca750f 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -2,6 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +// ignore: deprecated_member_use import 'dart:cli'; import 'dart:io'; @@ -26,9 +27,10 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, int compilationId, String signature, {int? id}) { var openParen = signature.indexOf('('); - if (openParen == -1) + if (openParen == -1) { throw sass.SassException('"$signature" is missing "("', SourceFile.fromString(signature).span(0)); + } if (!signature.endsWith(")")) { throw sass.SassException('"$signature" doesn\'t end with ")"', @@ -51,6 +53,7 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, request.name = name; } + // ignore: deprecated_member_use var response = waitFor(dispatcher.sendFunctionCallRequest(request)); try { switch (response.whichResult()) { diff --git a/lib/src/importer/file.dart b/lib/src/importer/file.dart index 19181963d..caa4290b3 100644 --- a/lib/src/importer/file.dart +++ b/lib/src/importer/file.dart @@ -2,6 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +// ignore: deprecated_member_use import 'dart:cli'; import 'package:sass_api/sass_api.dart' as sass; @@ -32,6 +33,7 @@ class FileImporter extends ImporterBase { Uri? canonicalize(Uri url) { if (url.scheme == 'file') return _filesystemImporter.canonicalize(url); + // ignore: deprecated_member_use return waitFor(() async { var response = await dispatcher .sendFileImportRequest(OutboundMessage_FileImportRequest() diff --git a/lib/src/importer/host.dart b/lib/src/importer/host.dart index e1a0f9734..33aaefffc 100644 --- a/lib/src/importer/host.dart +++ b/lib/src/importer/host.dart @@ -2,6 +2,7 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +// ignore: deprecated_member_use import 'dart:cli'; import 'package:sass_api/sass_api.dart' as sass; @@ -23,6 +24,7 @@ class HostImporter extends ImporterBase { : super(dispatcher); Uri? canonicalize(Uri url) { + // ignore: deprecated_member_use return waitFor(() async { var response = await dispatcher .sendCanonicalizeRequest(OutboundMessage_CanonicalizeRequest() @@ -45,6 +47,7 @@ class HostImporter extends ImporterBase { } sass.ImporterResult? load(Uri url) { + // ignore: deprecated_member_use return waitFor(() async { var response = await dispatcher.sendImportRequest(OutboundMessage_ImportRequest() diff --git a/lib/src/value.dart b/lib/src/value.dart index 246478035..1704b485f 100644 --- a/lib/src/value.dart +++ b/lib/src/value.dart @@ -87,7 +87,7 @@ sass.Value deprotofyValue(Dispatcher dispatcher, FunctionRegistry functions, int compilationId, Value value) { // Curry recursive calls to this function so we don't have to keep repeating // ourselves. - var deprotofy = (Value value) => + deprotofy(Value value) => deprotofyValue(dispatcher, functions, compilationId, value); try { diff --git a/pubspec.lock b/pubspec.lock index 798b2e0a9..bd0fd39cc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -190,6 +190,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.4.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" logging: dependency: transitive description: @@ -309,6 +316,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.48.0" + sass_analysis: + dependency: "direct dev" + description: + path: analysis + ref: HEAD + resolved-ref: "13099d497a6b6b6afd0b458e751eeab1661633ca" + url: "git://github.com/sass/dart-sass" + source: git + version: "0.0.0" sass_api: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1c2e1bd4e..1dd70a612 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,3 +30,5 @@ dev_dependencies: yaml: ^3.1.0 pubspec_parse: ^1.0.0 pub_semver: ^2.0.0 + sass_analysis: + git: {url: git://github.com/sass/dart-sass, path: analysis} diff --git a/test/embedded_process.dart b/test/embedded_process.dart index 75ca7897f..5265550ad 100644 --- a/test/embedded_process.dart +++ b/test/embedded_process.dart @@ -129,7 +129,7 @@ class EmbeddedProcess { } /// A callback that's run when the test completes. - Future _tearDown() async { + Future _tearDown() async { // If the process is already dead, do nothing. if (await _exitCodeOrNull != null) return; @@ -141,7 +141,7 @@ class EmbeddedProcess { } /// Formats the contents of [_log] and passes them to [printOnFailure]. - Future _logOutput() async { + Future _logOutput() async { if (_loggedOutput) return; _loggedOutput = true; @@ -149,7 +149,7 @@ class EmbeddedProcess { // Wait a timer tick to ensure that all available lines have been flushed to // [_log]. - await Future.delayed(Duration.zero); + await Future.delayed(Duration.zero); var buffer = StringBuffer(); buffer.write("Process `dart_sass_embedded` "); @@ -168,7 +168,7 @@ class EmbeddedProcess { /// future that completes once it's dead. /// /// If this is called after the process is already dead, it does nothing. - Future kill() async { + Future kill() async { _process.kill(ProcessSignal.sigkill); await exitCode; } @@ -178,7 +178,7 @@ class EmbeddedProcess { /// /// If this is called after the process is already dead, it verifies its /// existing exit code. - Future shouldExit([expectedExitCode]) async { + Future shouldExit([int? expectedExitCode]) async { var exitCode = await this.exitCode; if (expectedExitCode == null) return; expect(exitCode, expectedExitCode, diff --git a/test/file_importer_test.dart b/test/file_importer_test.dart index 16b9b2a5d..fcd0d4056 100644 --- a/test/file_importer_test.dart +++ b/test/file_importer_test.dart @@ -270,7 +270,8 @@ void main() { /// Asserts that [process] emits a [ProtocolError] params error with the given /// [message] on its protobuf stream and causes the compilation to fail. -Future _expectImportParamsError(EmbeddedProcess process, message) async { +Future _expectImportParamsError( + EmbeddedProcess process, Object message) async { await expectLater(process.outbound, emits(isProtocolError(errorId, ProtocolErrorType.PARAMS, message))); diff --git a/test/function_test.dart b/test/function_test.dart index 42393d1de..d2403664d 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -1820,7 +1820,7 @@ void main() { ..value = 2.0 ..numerators.add("s"))))))); - var failure = await getCompileFailure(await _process.outbound.next); + var failure = getCompileFailure(await _process.outbound.next); expect(failure.message, equals("1px and 2s are incompatible.")); expect(_process.kill(), completes); }); @@ -1842,7 +1842,7 @@ void main() { ..id = 1234 ..signature = signature)))); - var failure = await getCompileFailure(await _process.outbound.next); + var failure = getCompileFailure(await _process.outbound.next); expect(failure.message, message); expect(_process.kill(), completes); } @@ -1924,14 +1924,14 @@ Future _deprotofy(Value value, {bool inspect = false}) async { ..id = request.id ..success = value)); - var success = await getCompileSuccess(await _process.outbound.next); + var success = getCompileSuccess(await _process.outbound.next); expect(_process.kill(), completes); return RegExp(r" b: (.*);").firstMatch(success.css)![1]!; } /// Asserts that [value] causes a parameter error with a message matching /// [message] when deserializing it from a protocol buffer. -Future _expectDeprotofyError(Value value, message) async { +Future _expectDeprotofyError(Value value, Object message) async { _process.inbound.add(compileString("a {b: foo()}", functions: [r"foo()"])); var request = getFunctionCallRequest(await _process.outbound.next); diff --git a/test/importer_test.dart b/test/importer_test.dart index a553d958a..75d4173e3 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -512,7 +512,8 @@ Future _canonicalize(EmbeddedProcess process) async { /// Asserts that [process] emits a [ProtocolError] params error with the given /// [message] on its protobuf stream and causes the compilation to fail. -Future _expectImportParamsError(EmbeddedProcess process, message) async { +Future _expectImportParamsError( + EmbeddedProcess process, Object message) async { await expectLater(process.outbound, emits(isProtocolError(errorId, ProtocolErrorType.PARAMS, message))); diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 1b79f418a..580458169 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -130,7 +130,7 @@ void main() { process.inbound.add(compileString("a {b: 1px + 2px}", sourceMap: true)); await expectLater( process.outbound, - emits(isSuccess("a { b: 3px; }", sourceMap: (map) { + emits(isSuccess("a { b: 3px; }", sourceMap: (String map) { var mapping = source_maps.parse(map); var span = mapping.spanFor(2, 5)!; expect(span.start.line, equals(0)); diff --git a/test/utils.dart b/test/utils.dart index 67c37c633..87c388a1c 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -42,7 +42,7 @@ InboundMessage compileString(String css, /// Asserts that [process] emits a [ProtocolError] parse error with the given /// [message] on its protobuf stream and prints a notice on stderr. -Future expectParseError(EmbeddedProcess process, message) async { +Future expectParseError(EmbeddedProcess process, Object message) async { await expectLater(process.outbound, emits(isProtocolError(errorId, ProtocolErrorType.PARSE, message))); @@ -56,7 +56,8 @@ Future expectParseError(EmbeddedProcess process, message) async { /// Asserts that [process] emits a [ProtocolError] params error with the given /// [message] on its protobuf stream and prints a notice on stderr. -Future expectParamsError(EmbeddedProcess process, int id, message) async { +Future expectParamsError( + EmbeddedProcess process, int id, Object message) async { await expectLater(process.outbound, emits(isProtocolError(id, ProtocolErrorType.PARAMS, message))); @@ -71,7 +72,7 @@ Future expectParamsError(EmbeddedProcess process, int id, message) async { /// Asserts that an [OutboundMessage] is a [ProtocolError] with the given [id], /// [type], and optionally [message]. -Matcher isProtocolError(int id, ProtocolErrorType type, [message]) => +Matcher isProtocolError(int id, ProtocolErrorType type, [Object? message]) => predicate((value) { expect(value, isA()); var outboundMessage = value as OutboundMessage; @@ -85,7 +86,7 @@ Matcher isProtocolError(int id, ProtocolErrorType type, [message]) => /// Asserts that [message] is an [OutboundMessage] with a /// `CanonicalizeRequest` and returns it. -OutboundMessage_CanonicalizeRequest getCanonicalizeRequest(value) { +OutboundMessage_CanonicalizeRequest getCanonicalizeRequest(Object? value) { expect(value, isA()); var message = value as OutboundMessage; expect(message.hasCanonicalizeRequest(), isTrue, @@ -95,7 +96,7 @@ OutboundMessage_CanonicalizeRequest getCanonicalizeRequest(value) { /// Asserts that [message] is an [OutboundMessage] with a `ImportRequest` and /// returns it. -OutboundMessage_ImportRequest getImportRequest(value) { +OutboundMessage_ImportRequest getImportRequest(Object? value) { expect(value, isA()); var message = value as OutboundMessage; expect(message.hasImportRequest(), isTrue, @@ -105,7 +106,7 @@ OutboundMessage_ImportRequest getImportRequest(value) { /// Asserts that [message] is an [OutboundMessage] with a `FileImportRequest` /// and returns it. -OutboundMessage_FileImportRequest getFileImportRequest(value) { +OutboundMessage_FileImportRequest getFileImportRequest(Object? value) { expect(value, isA()); var message = value as OutboundMessage; expect(message.hasFileImportRequest(), isTrue, @@ -115,7 +116,7 @@ OutboundMessage_FileImportRequest getFileImportRequest(value) { /// Asserts that [message] is an [OutboundMessage] with a /// `FunctionCallRequest` and returns it. -OutboundMessage_FunctionCallRequest getFunctionCallRequest(value) { +OutboundMessage_FunctionCallRequest getFunctionCallRequest(Object? value) { expect(value, isA()); var message = value as OutboundMessage; expect(message.hasFunctionCallRequest(), isTrue, @@ -125,7 +126,8 @@ OutboundMessage_FunctionCallRequest getFunctionCallRequest(value) { /// Asserts that [message] is an [OutboundMessage] with a /// `CompileResponse.Failure` and returns it. -OutboundMessage_CompileResponse_CompileFailure getCompileFailure(value) { +OutboundMessage_CompileResponse_CompileFailure getCompileFailure( + Object? value) { var response = getCompileResponse(value); expect(response.hasFailure(), isTrue, reason: "Expected $response to be a failure"); @@ -134,7 +136,8 @@ OutboundMessage_CompileResponse_CompileFailure getCompileFailure(value) { /// Asserts that [message] is an [OutboundMessage] with a /// `CompileResponse.Success` and returns it. -OutboundMessage_CompileResponse_CompileSuccess getCompileSuccess(value) { +OutboundMessage_CompileResponse_CompileSuccess getCompileSuccess( + Object? value) { var response = getCompileResponse(value); expect(response.hasSuccess(), isTrue, reason: "Expected $response to be a success"); @@ -143,7 +146,7 @@ OutboundMessage_CompileResponse_CompileSuccess getCompileSuccess(value) { /// Asserts that [message] is an [OutboundMessage] with a `CompileResponse` and /// returns it. -OutboundMessage_CompileResponse getCompileResponse(value) { +OutboundMessage_CompileResponse getCompileResponse(Object? value) { expect(value, isA()); var message = value as OutboundMessage; expect(message.hasCompileResponse(), isTrue, @@ -153,7 +156,7 @@ OutboundMessage_CompileResponse getCompileResponse(value) { /// Asserts that [message] is an [OutboundMessage] with a `LogEvent` and /// returns it. -OutboundMessage_LogEvent getLogEvent(value) { +OutboundMessage_LogEvent getLogEvent(Object? value) { expect(value, isA()); var message = value as OutboundMessage; expect(message.hasLogEvent(), isTrue, @@ -169,7 +172,7 @@ OutboundMessage_LogEvent getLogEvent(value) { /// /// If [sourceMap] is a function, `response.success.sourceMap` is passed to it. /// Otherwise, it's treated as a matcher for `response.success.sourceMap`. -Matcher isSuccess(css, {sourceMap}) => predicate((value) { +Matcher isSuccess(Object css, {Object? sourceMap}) => predicate((value) { var success = getCompileSuccess(value); expect(success.css, css is String ? equalsIgnoringWhitespace(css) : css); if (sourceMap is void Function(String)) { diff --git a/tool/grind.dart b/tool/grind.dart index aac8c47f7..81a17d409 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -10,7 +10,7 @@ import 'package:yaml/yaml.dart'; import 'utils.dart'; -main(List args) { +void main(List args) { pkg.githubBearerToken.fn = () => Platform.environment["GH_BEARER_TOKEN"]!; pkg.environmentConstants.fn = () => { @@ -29,11 +29,11 @@ main(List args) { String get _implementationVersion { var lockfile = loadYaml(File('pubspec.lock').readAsStringSync(), sourceUrl: Uri(path: 'pubspec.lock')); - return lockfile['packages']['sass']['version']; + return lockfile['packages']['sass']['version'] as String; } @Task('Compile the protocol buffer definition to a Dart library.') -protobuf() async { +Future protobuf() async { Directory('build').createSync(recursive: true); // Make sure we use the version of protoc_plugin defined by our pubspec, From e12ef6f481254a49b7128fc7f302064757a59097 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 24 Jan 2022 18:29:11 -0800 Subject: [PATCH 068/162] Allow PRs to be linked to the Dart Sass and embedded protocol repos --- .github/workflows/ci.yml | 40 ++++++++++++++++++++++++++++++++++++++++ tool/grind.dart | 5 ++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac5dce359..b81280ce0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,8 +27,28 @@ jobs: with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 with: {sdk: "${{ matrix.dart_channel }}"} + + - name: Check out Dart Sass + uses: sass/clone-linked-repo@v1 + with: + repo: sass/dart-sass + path: build/dart-sass + default-ref: null + + - name: Add Dart Sass to pubspec + run: > + if [[ -d build/dart-sass ]]; then + echo "dependency_overrides: {sass: {path: build/dart-sass}}" >> pubspec.yaml + fi + shell: bash + + - name: Check out embedded Sass protocol + uses: sass/clone-linked-repo@v1 + with: {repo: sass/embedded-protocol, path: build/embedded-protocol} + - run: dart pub get - run: dart pub run grinder protobuf + env: {UPDATE_SASS_PROTOCOL: false} - run: dart pub run grinder pkg-standalone-dev - name: Run tests run: dart pub run test -r expanded @@ -42,8 +62,28 @@ jobs: - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 + + - name: Check out Dart Sass + uses: sass/clone-linked-repo@v1 + with: + repo: sass/dart-sass + path: build/dart-sass + default-ref: null + + - name: Add Dart Sass to pubspec + run: > + if [[ -d build/dart-sass ]]; then + echo "dependency_overrides: {sass: {path: build/dart-sass}}" >> pubspec.yaml + fi + shell: bash + + - name: Check out embedded Sass protocol + uses: sass/clone-linked-repo@v1 + with: {repo: sass/embedded-protocol, path: build/embedded-protocol} + - run: dart pub get - run: dart pub run grinder protobuf + env: {UPDATE_SASS_PROTOCOL: false} - name: Analyze dart run: dartanalyzer --fatal-warnings ./ diff --git a/tool/grind.dart b/tool/grind.dart index 81a17d409..c0930e8b0 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -50,7 +50,10 @@ dart pub run protoc_plugin %* run('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); } - await cloneOrPull("git://github.com/sass/embedded-protocol"); + if (Platform.environment['UPDATE_SASS_PROTOCOL'] != 'false') { + await cloneOrPull("git://github.com/sass/embedded-protocol"); + } + await runAsync("protoc", arguments: [ "-Ibuild/embedded-protocol", From 2b34ec0b1a8c4fe785920e9b4a0674fc335e8f8a Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 25 Jan 2022 17:15:37 -0800 Subject: [PATCH 069/162] Add a test that verifies the Dart Sass version This ensures it matches the version declared in the pubspec, so that we don't end up merging a different version than the PR tested. --- pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- test/dependencies_test.dart | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 test/dependencies_test.dart diff --git a/pubspec.lock b/pubspec.lock index bd0fd39cc..f5363710d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.48.0" + version: "1.49.0" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.28" + version: "1.0.0-beta.29" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1dd70a612..6736832fc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-beta.16 +version: 1.0.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: ^1.42.0 + sass: 1.49.0 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 diff --git a/test/dependencies_test.dart b/test/dependencies_test.dart new file mode 100644 index 000000000..bf2f2ca51 --- /dev/null +++ b/test/dependencies_test.dart @@ -0,0 +1,30 @@ +// Copyright 2022 Google LLC. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:io'; + +import 'package:pubspec_parse/pubspec_parse.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:test/test.dart'; + +/// This package's pubspec. +var _pubspec = Pubspec.parse(File('pubspec.yaml').readAsStringSync(), + sourceUrl: Uri.parse('pubspec.yaml')); + +void main() { + // Assert that our declared dependency on Dart Sass is either a Git dependency + // or the same version as the version we're testing against. + + test('depends on a compatible version of Dart Sass', () { + var sassDependency = _pubspec.dependencies['sass']; + if (sassDependency is GitDependency) return; + + var actualVersion = + (Process.runSync('dart', ['run', 'sass', '--version']).stdout as String) + .trim(); + expect(sassDependency, isA()); + expect(actualVersion, + equals((sassDependency as HostedDependency).version.toString())); + }); +} From f26ed515a51e496b2a21cbcf49703dd1257ff6ed Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 26 Jan 2022 17:13:10 -0800 Subject: [PATCH 070/162] Cut a release of the embedded host after the compiler releases (#68) Co-authored-by: Awjin Ahn --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 13 +++++++++++++ 2 files changed, 46 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b81280ce0..3f72352da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -147,3 +147,36 @@ jobs: - name: Deploy run: dart pub run grinder pkg-github-windows env: {GH_BEARER_TOKEN: "${{ github.token }}"} + + release_embedded_host: + name: "Release Embedded Host" + runs-on: ubuntu-latest + needs: [deploy_github_linux, deploy_github_macos, deploy_github_windows] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + with: + repository: sass/embedded-host-node + token: ${{ secrets.GH_TOKEN }} + + - name: Get version + id: version + run: echo "::set-output name=version::${GITHUB_REF##*/}" + + - name: Update version + run: > + cat package.json | + jq --arg version ${{ steps.version.outputs.version }} ' + .version |= $version | + ."compiler-version" |= $version + ' > package.json.tmp && + mv package.json.tmp package.json + shell: bash + + - uses: EndBug/add-and-commit@v8 + with: + author_name: Sass Bot + author_email: sass.bot.beep.boop@gmail.com + message: Update compiler version and release + tag: ${{ steps.version.outputs.version }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c980350f8..05fcc76aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,3 +21,16 @@ All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. + +## Release process + +Because this package's version remains in lockstep with the current version of +Dart Sass, it's not released manually from this repository. Instead, a release +commit is automatically generated once a new Dart Sass version has been +released. As such, manual commits should never: + +* Update the `pubspec.yaml`'s version to a non-`-dev` number. Changing it from + non-`-dev` to dev when adding a new feature is fine. + +* Update the `pubspec.yaml`'s dependency on `sass` to a non-Git dependency. + Changing it from non-Git to Git when using a new feature is fine. From 459d95b748e551911d7eddab45cb9f9f61482c3b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 27 Jan 2022 13:09:58 -0800 Subject: [PATCH 071/162] Add dependency_overrides on sass_api for linked PRs (#69) --- .github/workflows/ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f72352da..54b525afe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,11 @@ jobs: - name: Add Dart Sass to pubspec run: > if [[ -d build/dart-sass ]]; then - echo "dependency_overrides: {sass: {path: build/dart-sass}}" >> pubspec.yaml + ( + echo "dependency_overrides:" + echo " sass: {path: build/dart-sass}" + echo " sass_api: {path: build/dart-sass/pkg/sass_api}" + ) >> pubspec.yaml fi shell: bash @@ -73,7 +77,11 @@ jobs: - name: Add Dart Sass to pubspec run: > if [[ -d build/dart-sass ]]; then - echo "dependency_overrides: {sass: {path: build/dart-sass}}" >> pubspec.yaml + ( + echo "dependency_overrides:" + echo " sass: {path: build/dart-sass}" + echo " sass_api: {path: build/dart-sass/pkg/sass_api}" + ) >> pubspec.yaml fi shell: bash From 5509f1c754da4ff172393eb0f84f735c54d4fe1f Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 1 Feb 2022 00:15:23 +0100 Subject: [PATCH 072/162] Implement support for sourceMapIncludeSources (#62) --- bin/dart_sass_embedded.dart | 3 ++- test/protocol_test.dart | 42 +++++++++++++++++++++++++++++++++++++ test/utils.dart | 4 ++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 21c8ad6b5..03be2dc68 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -119,7 +119,8 @@ void main(List args) { var sourceMap = result.sourceMap; if (sourceMap != null) { - success.sourceMap = json.encode(sourceMap.toJson()); + success.sourceMap = json.encode(sourceMap.toJson( + includeSourceContents: request.sourceMapIncludeSources)); } return OutboundMessage_CompileResponse()..success = success; } on sass.SassException catch (error) { diff --git a/test/protocol_test.dart b/test/protocol_test.dart index 580458169..823e023f7 100644 --- a/test/protocol_test.dart +++ b/test/protocol_test.dart @@ -136,6 +136,48 @@ void main() { expect(span.start.line, equals(0)); expect(span.start.column, equals(3)); expect(span.end, equals(span.start)); + expect(mapping, isA()); + expect((mapping as source_maps.SingleMapping).files[0], isNull); + return true; + }))); + await process.kill(); + }); + + test( + "includes a source map without content if source_map is true and source_map_include_sources is false", + () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + sourceMap: true, sourceMapIncludeSources: false)); + await expectLater( + process.outbound, + emits(isSuccess("a { b: 3px; }", sourceMap: (String map) { + var mapping = source_maps.parse(map); + var span = mapping.spanFor(2, 5)!; + expect(span.start.line, equals(0)); + expect(span.start.column, equals(3)); + expect(span.end, equals(span.start)); + expect(mapping, isA()); + expect((mapping as source_maps.SingleMapping).files[0], isNull); + return true; + }))); + await process.kill(); + }); + + test( + "includes a source map with content if source_map is true and source_map_include_sources is true", + () async { + process.inbound.add(compileString("a {b: 1px + 2px}", + sourceMap: true, sourceMapIncludeSources: true)); + await expectLater( + process.outbound, + emits(isSuccess("a { b: 3px; }", sourceMap: (String map) { + var mapping = source_maps.parse(map); + var span = mapping.spanFor(2, 5)!; + expect(span.start.line, equals(0)); + expect(span.start.column, equals(3)); + expect(span.end, equals(span.start)); + expect(mapping, isA()); + expect((mapping as source_maps.SingleMapping).files[0], isNotNull); return true; }))); await process.kill(); diff --git a/test/utils.dart b/test/utils.dart index 87c388a1c..6fc8972a2 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -20,6 +20,7 @@ InboundMessage compileString(String css, OutputStyle? style, String? url, bool? sourceMap, + bool? sourceMapIncludeSources, Iterable? importers, InboundMessage_CompileRequest_Importer? importer, Iterable? functions}) { @@ -33,6 +34,9 @@ InboundMessage compileString(String css, if (importers != null) request.importers.addAll(importers); if (style != null) request.style = style; if (sourceMap != null) request.sourceMap = sourceMap; + if (sourceMapIncludeSources != null) { + request.sourceMapIncludeSources = sourceMapIncludeSources; + } if (functions != null) request.globalFunctions.addAll(functions); if (alertColor != null) request.alertColor = alertColor; if (alertAscii != null) request.alertAscii = alertAscii; From 15469fe1a00eee3162ceb6cd02cf091ea588fe64 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 31 Jan 2022 16:12:20 -0800 Subject: [PATCH 073/162] Use `|` rather than `>` in ci.yml (#72) The `|` character preserves newlines where `>` does not. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54b525afe..833fcc2df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: default-ref: null - name: Add Dart Sass to pubspec - run: > + run: | if [[ -d build/dart-sass ]]; then ( echo "dependency_overrides:" @@ -75,7 +75,7 @@ jobs: default-ref: null - name: Add Dart Sass to pubspec - run: > + run: | if [[ -d build/dart-sass ]]; then ( echo "dependency_overrides:" @@ -173,7 +173,7 @@ jobs: run: echo "::set-output name=version::${GITHUB_REF##*/}" - name: Update version - run: > + run: | cat package.json | jq --arg version ${{ steps.version.outputs.version }} ' .version |= $version | From d8c3096c1251583d3cabfaf062da87b596db1b58 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 1 Feb 2022 01:40:05 +0000 Subject: [PATCH 074/162] Update Dart Sass version and release --- pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index f5363710d..d3bc91866 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.0" + version: "1.49.4" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.29" + version: "1.0.0-beta.33" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6736832fc..152e498f3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.0.0-dev +version: 1.49.4 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.0 + sass: 1.49.4 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 301d94620b0ddb0012653eb75024735fc9c1f6ed Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 1 Feb 2022 20:32:35 +0000 Subject: [PATCH 075/162] Update Dart Sass version and release --- CHANGELOG.md | 2400 +++++++++++++++++++++++++++++++++++++++++++++++++- pubspec.lock | 4 +- pubspec.yaml | 4 +- 3 files changed, 2368 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46098447c..1d941373a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,61 +1,2389 @@ -## 1.0.0-beta.16 +## 1.49.5 -* Upgrade to Sass 1.48.0. +### Embedded Sass -* Fix a bug where the compiler could crash when an error was detected in a - stylesheet provided by string. +* First stable release the `sass-embedded` npm package that contains the Node.js + Embedded Host. -## 1.0.0-beta.15 +* First stable release of the `sass_embedded` pub package that contains the + Embedded Dart Sass compiler. -* Support version 1.0.0-beta.17 of the Sass embedded protocol: +## 1.49.4 - * Treat invalid host function signatures as function errors rather than - protocol errors. +* No user-visible changes. + +## 1.49.3 + +* No user-visible changes. + +## 1.49.2 + +* No user-visible changes. + +## 1.49.1 + +* Stop supporting non-LTS Node.js versions. + +## 1.49.0 + +* Fix a bug in `string.insert` with certain negative indices. + +### JS API + +* Add support for the `sourceMapIncludeSources` option in the new JS API. + +#### TypeScript Declarations + +* Fix a bug where `LegacyPluginThis.options.linefeed` was typed to return + abbreviations when it actually returned literal linefeed characters. + +## 1.48.0 + +### JS API + +* **Potentially breaking bug fix:** Match the specification of the new JS API by + setting `LegacyResult.map` to `undefined` rather than `null`. + +#### TypeScript Declarations + +* Add a declaration for the `NULL` constant. + +## 1.47.0 + +### JS API + +#### TypeScript Declarations + +* Add declarations for the `TRUE` and `FALSE` constants. + +## 1.46.0 + +### JS API + +* **Potentially breaking bug fix:** Match the specification of the new JS API by + passing `undefined` rather than `null` to `Logger.warn()` for an unset `span`. + +#### TypeScript Declarations + +* Add a declaration for the `LegacyPluginThis.options.context` field. + +* Update the definition of `LegacyAsyncFunction` to include explicit definitions + with zero through six arguments before the `done` parameter. This makes it + possible for TypeScript users to pass in callbacks that take a specific number + of arguments, rather than having to declare a callback that takes an arbitrary + number. + +* Add a declaration for `types.Error`, a legacy API class that can be returned + by asynchronous functions to signal asynchronous errors. + +* Add a `LegacyAsyncFunctionDone` type for the `done` callback that's passed to + `LegacyAsyncFunction`. + +## 1.45.2 + +### JS API + +* **Potentially breaking bug fix:** Change the default value of the `separator` + parameter for `new SassArgumentList()` to `','` rather than `null`. This + matches the API specification. + +## 1.45.1 + +* **Potentially breaking bug fix:** Properly parse custom properties in + `@supports` conditions. Note that this means that SassScript expressions on + the right-hand side of custom property `@supports` queries now need to be + interpolated, as per https://sass-lang.com/d/css-vars. + +* **Potentially breaking bug fix:** Fix a bug where `inspect()` was not + properly printing nested, empty, bracketed lists. + +## 1.45.0 + +### JS API + +This release includes an entirely new JavaScript API, designed to be more +idiomatic, performant, and usable. The old API will continue to be supported +until Dart Sass 2.0.0, but it is now considered deprecated and should be avoided +for new code. + +The new API includes: + +* `compile()` and `compileAsync()` functions that take Sass file paths and + return the result of compiling them to CSS. The async function returns a + `Promise` rather than using a callback-based API. + +* `compileString()` and `compileStringAsync()` functions that take a string of + Sass source and compiles it to CSS. As above, the async function returns a + `Promise`. + +* A new importer API that more closely matches the Sass specification's logic + for resolving loads. This makes it much easier for Sass to cache information + across `@import` and `@use` rules, which substantially improves performance + for applications that rely heavily on repeated `@import`s. + +* A new custom function API, including much more usable JS representations of + Sass value types complete with type-assertion functions, easy map and list + lookups, and compatibility with the [`immutable`] package. **Unlike in the + legacy API,** function callbacks now take one argument which contains an array + of Sass values (rather than taking a separate JS argument for each Sass + argument). + +[`immutable`]: https://immutable-js.com/ + +For full documentation of this API, please see [the Sass website][js-api]. + +[js-api]: https://sass-lang.com/documentation/js-api + +This release also adds TypeScript type definitions. + +## 1.44.0 + +* Suggest `calc()` as an alternative in `/`-as-division deprecation messages. + +### Dart API + +* Add `SassNumber.convert()` and `SassNumber.convertValue()`. These work like + `SassNumber.coerce()` and `SassNumber.coerceValue()`, except they don't treat + unitless numbers as universally compatible. + +* Fix a bug where `SassNumber.coerceToMatch()` and + `SassNumber.coerceValueToMatch()` wouldn't coerce single-unit numbers to + match unitless numbers. + +## 1.43.5 + +* Fix a bug where calculations with different operators were incorrectly + considered equal. + +* Properly parse attribute selectors with empty namespaces. + +### JS API + +* Print more detailed JS stack traces. This is mostly useful for the Sass team's + own debugging purposes. + +## 1.43.4 + +### JS API + +* Fix a bug where the `logger` option was ignored for the `render()` function. + +## 1.43.3 + +* Improve performance. + +## 1.43.2 + +* Improve the error message when the default namespace of a `@use` rule is not + a valid identifier. + +## 1.43.1 + +* No user-visible changes. + +## 1.43.0 + +### JS API + +* Add support for the `logger` option. This takes an object that can define + `warn` or `debug` methods to add custom handling for messages emitted by the + Sass compiler. See [the JS API docs] for details. + + [the JS API docs]: https://sass-lang.com/documentation/js-api/interfaces/Logger + +* Add a `Logger.silent` object that can be passed to the `logger` option to + silence all messages from the Sass compiler. + +## 1.42.1 + +* Fix a bug where Sass variables and function calls in calculations weren't + being resolved correctly if there was a parenthesized interpolation elsewhere + in the file. + +## 1.42.0 + +* `min()` and `max()` expressions are once again parsed as calculations as long + as they contain only syntax that's allowed in calculation expressions. To + avoid the backwards-compatibility issues that were present in 1.40.0, they now + allow unitless numbers to be mixed with numbers with units just like the + global `min()` and `max()` functions. Similarly, `+` and `-` operations within + `min()` and `max()` functions allow unitless numbers to be mixed with numbers + with units. + +## 1.41.1 + +* Preserve parentheses around `var()` functions in calculations, because they + could potentially be replaced with sub-expressions that might need to be + parenthesized. + +## 1.41.0 + +* Calculation values can now be combined with strings using the `+` operator. + This was an error in 1.40.0, but this broke stylesheets that were relying on + `$value + ""` expressions to generically convert values to strings. (Note that + the Sass team recommends the use of `"#{$value}"` or `inspect($value)` for + that use-case.) + +* The `selector.unify()` function now correctly returns `null` when one selector + is a `:host` or `:host-context` and the other is a selector that's guaranteed + to be within the current shadow DOM. The `@extend` logic has been updated + accordingly as well. + +* Fix a bug where extra whitespace in `min()`, `max()`, `clamp()`, and `calc()` + expressions could cause bogus parse errors. + +* Fix a bug where the right-hand operand of a `-` in a calculation could + incorrectly be stripped of parentheses. + +### Dart API + +* `SassCalculation.plus()` now allows `SassString` arguments. + +## 1.40.1 + +* **Potentially breaking bug fix:** `min()` and `max()` expressions outside of + calculations now behave the same way they did in 1.39.2, returning unquoted + strings if they contain no Sass-specific features and calling the global + `min()` and `max()` functions otherwise. Within calculations, they continue to + behave how they did in 1.40.0. + + This fixes an unintended breaking change added in 1.40.0, wherein passing a + unitless number and a number without units to `min()` or `max()` now produces + an error. Since this breakage affects a major Sass library, we're temporarily + reverting support for `min()` and `max()` calculations while we work on + designing a longer-term fix. + +## 1.40.0 + +* Add support for first-class `calc()` expressions (as well as `clamp()` and + plain-CSS `min()` and `max()`). This means: + + * `calc()` expressions will be parsed more thoroughly, and errors will be + highlighted where they weren't before. **This may break your stylesheets,** + but only if they were already producing broken CSS. + + * `calc()` expressions will be simplified where possible, and may even return + numbers if they can be simplified away entirely. + + * `calc()` expressions that can't be simplified to numbers return a new data + type known as "calculations". + + * Sass variables and functions can now be used in `calc()` expressions. + + * New functions `meta.calc-name()` and `meta.calc-args()` can now inspect + calculations. + +### Dart API + +* Add a new value type, `SassCalculation`, that represents calculations. + +* Add new `CalculationOperation`, `CalculationOperator`, and + `CalculationInterpolation` types to represent types of arguments that may + exist as part of a calculation. + +* Add a new `Value.assertCalculation()` method. + +* Add a new `Number.hasCompatibleUnits()` method. + +## 1.39.2 + +* Fix a bug where configuring with `@use ... with` would throw an error when + that variable was defined in a module that also contained `@forward ... with`. + +## 1.39.1 + +* Partial fix for a bug where `@at-root` does not work properly in nested + imports that contain `@use` rules. If the only `@use` rules in the nested + import are for built-in modules, `@at-root` should now work properly. + +## 1.39.0 + +### JS API + +* Add a `charset` option that controls whether or not Sass emits a + `@charset`/BOM for non-ASCII stylesheets. + +## 1.38.2 + +* No user-visible changes + +## 1.38.1 + +* No user-visible changes + +## 1.38.0 + +* In expanded mode, emit characters in Unicode private-use areas as escape + sequences rather than literal characters. + +* Fix a bug where quotes would be omitted for an attribute selector whose value + was a single backslash. + +* Properly consider numbers that begin with `.` as "plain CSS" for the purposes + of parsing plain-CSS `min()` and `max()` functions. + +* Allow `if` to be used as an unquoted string. + +* Properly parse backslash escapes within `url()` expressions. + +* Fix a couple bugs where `@extend`s could be marked as unsatisfied when + multiple identical `@extend`s extended selectors across `@use` rules. + +### Command Line Interface + +* Strip CRLF newlines from snippets of the original stylesheet that are included + in the output when an error occurs. + +### JS API + +* Don't crash when a Windows path is returned by a custom Node importer at the + same time as file contents. + +* Don't crash when an error occurs in a stylesheet loaded via a custom importer + with a custom URL scheme. + +### Dart API + +* Add a `SassArgumentList.keywordsWithoutMarking` getter to access the keyword + arguments of an argument list without marking them accessed. - * Allow `ImportResponse.result` to be null. +## 1.37.5 -* Fix a bug where the compiler could return a `CompileFailure` without a span. +* No user-visible changes. + +## 1.37.4 + +* No user-visible changes. + +## 1.37.3 + +* No user-visible changes. + +## 1.37.2 + +* No user-visible changes. + +## 1.37.1 + +* No user-visible changes. + +## 1.37.0 + +### Dart API + +* **Potentially breaking bug fix:** `SassNumber.asSlash`, + `SassNumber.withSlash()`, and `SassNumber.withoutSlash()` have been marked as + `@internal`. They were never intended to be used outside the `sass` package. + +* **Potentially breaking bug fix:** `SassException` has been marked as `@sealed` + to formally indicate that it's not intended to be extended outside of the + `sass` package. + +* Add a `Value.withListContents()` method that returns a new Sass list with the + same list separator and brackets as the current value, interpreted as a list. + +## 1.36.0 + +### Dart API + +* Added `compileToResult()`, `compileStringToResult()`, + `compileToResultAsync()`, and `compileStringToResultAsync()` methods. These + are intended to replace the existing `compile*()` methods, which are now + deprecated. Rather than returning a simple string, these return a + `CompileResult` object, which will allow us to add additional information + about the compilation without having to introduce further deprecations. + + * Instead of passing a `sourceMaps` callback to `compile*()`, pass + `sourceMaps: true` to `compile*ToResult()` and access + `CompileResult.sourceMap`. + + * The `CompileResult` object exposes a `loadedUrls` object which lists the + canonical URLs accessed during a compilation. This information was + previously unavailable except through the JS API. + +## 1.35.2 + +* **Potentially breaking bug fix**: Properly throw an error for Unicode ranges + that have too many `?`s after hexadecimal digits, such as `U+12345??`. + +* **Potentially breaking bug fix:** Fixed a bug where certain local variable + declarations nested within multiple `@if` statements would incorrectly + override a global variable. It's unlikely that any real stylesheets were + relying on this bug, but if so they can simply add `!global` to the variable + declaration to preserve the old behavior. + +* **Potentially breaking bug fix:** Fix a bug where imports of root-relative + URLs (those that begin with `/`) in `@import` rules would be passed to + both Dart and JS importers as `file:` URLs. + +* Properly support selector lists for the `$extendee` argument to + `selector.extend()` and `selector.replace()`. + +* Fix an edge case where `@extend` wouldn't affect a selector within a + pseudo-selector such as `:is()` that itself extended other selectors. + +* Fix a race condition where `meta.load-css()` could trigger an internal error + when running in asynchronous mode. + +### Dart API + +* Use the `@internal` annotation to indicate which `Value` APIs are available + for public use. + +## 1.35.1 + +* Fix a bug where the quiet dependency flag didn't silence warnings in some + stylesheets loaded using `@import`. + +## 1.35.0 + +* Fix a couple bugs that could prevent some members from being found in certain + files that use a mix of imports and the module system. + +* Fix incorrect recommendation for migrating division expressions that reference + namespaced variables. + +### JS API + +* Add a `quietDeps` option which silences compiler warnings from stylesheets + loaded through importers and load paths. + +* Add a `verbose` option which causes the compiler to emit all deprecation + warnings, not just 5 per feature. + +## 1.34.1 + +* Fix a bug where `--update` would always compile any file that depends on a + built-in module. + +* Fix the URL for the `@-moz-document` deprecation message. + +* Fix a bug with `@for` loops nested inside property declarations. + +## 1.34.0 + +* Don't emit the same warning in the same location multiple times. + +* Cap deprecation warnings at 5 per feature by default. + +### Command Line Interface + +* Add a `--quiet-deps` flag which silences compiler warnings from stylesheets + loaded through `--load-path`s. + +* Add a `--verbose` flag which causes the compiler to emit all deprecation + warnings, not just 5 per feature. + +### Dart API + +* Add a `quietDeps` argument to `compile()`, `compileString()`, + `compileAsync()`, and `compileStringAsync()` which silences compiler warnings + from stylesheets loaded through importers, load paths, and `package:` URLs. + +* Add a `verbose` argument to `compile()`, `compileString()`, `compileAsync()`, + and `compileStringAsync()` which causes the compiler to emit all deprecation + warnings, not just 5 per feature. + +## 1.33.0 + +* Deprecate the use of `/` for division. The new `math.div()` function should be + used instead. See [this page][] for details. + +[this page]: https://sass-lang.com/documentation/breaking-changes/slash-div + +* Add a `list.slash()` function that returns a slash-separated list. + +* **Potentially breaking bug fix:** The heuristics around when potentially + slash-separated numbers are converted to slash-free numbers—for example, when + `1/2` will be printed as `0.5` rather than `1/2`—have been slightly expanded. + Previously, a number would be made slash-free if it was passed as an argument + to a *user-defined function*, but not to a *built-in function*. Now it will be + made slash-free in both cases. This is a behavioral change, but it's unlikely + to affect any real-world stylesheets. + +* [`:is()`][] now behaves identically to `:matches()`. + +[`:is()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/:is + +* Fix a bug where non-integer numbers that were very close to integer + values would be incorrectly formatted in CSS. + +* Fix a bug where very small number and very large negative numbers would be + incorrectly formatted in CSS. + +### JS API + +* The `this` context for importers now has a `fromImport` field, which is `true` + if the importer is being invoked from an `@import` and `false` otherwise. + Importers should only use this to determine whether to load [import-only + files]. -## 1.0.0-beta.14 +[import-only files]: https://sass-lang.com/documentation/at-rules/import#import-only-files -* Support `FileImporter`s. +### Dart API -## 1.0.0-beta.13 +* Add an `Importer.fromImport` getter, which is `true` if the current + `Importer.canonicalize()` call comes from an `@import` rule and `false` + otherwise. Importers should only use this to determine whether to load + [import-only files]. -* Report a better error message for an empty `CompileRequest.Input.path`. +## 1.32.13 -## 1.0.0-beta.12 +* **Potentially breaking bug fix:** Null values in `@use` and `@forward` + configurations no longer override the `!default` variable, matching the + behavior of the equivalent code using `@import`. -* Support version 1.0.0-beta.14 of the Sass embedded protocol: - * Support `Value.Calculation`. +* Use the proper parameter names in error messages about `string.slice` -## 1.0.0-beta.11 +## 1.32.12 -* Support version 1.0.0-beta.13 of the Sass embedded protocol: - * Support `Value.HwbColor`. - * Emit colors as `Value.HslColor` if that internal representation is - available. +* Fix a bug that disallowed more than one module from extending the same + selector from a module if that selector itself extended a selector from + another upstream module. -* Add a `--version` flag that will print a `VersionResponse` as JSON, for ease - of human identification. +## 1.32.11 -## 1.0.0-beta.10 +* Fix a bug where bogus indented syntax errors were reported for lines that + contained only whitespace. -* Support version 1.0.0-beta.12 of the Sass embedded protocol: - * Support `Value.ArgumentList`. +## 1.32.10 -* Support slash-separated lists. +* No user-visible changes. + +## 1.32.9 + +* Fix a typo in a deprecation warning. + +### JavaScript API + +* Drop support for Chokidar 2.x. This version was incompatible with Node 14, but + due to shortcomings in npm's version resolver sometimes still ended up + installed anyway. Only declaring support for 3.0.0 should ensure compatibility + going forward. + +### Dart API + +* Allow the null safety release of args and watcher. + +### Command Line Interface + +* Add a `-w` shorthand for the `--watch` flag. + +## 1.32.8 + +* Update chokidar version for Node API tests. + +### JavaScript API + +* Allow a custom function to access the `render()` options object within its + local context, as `this.options`. + +## 1.32.7 + +* Allow the null safety release of stream_transform. + +* Allow `@forward...with` to take arguments that have a `!default` flag without + a trailing comma. -## 1.0.0-beta.9 +* Improve the performance of unitless and single-unit numbers. + +## 1.32.6 + +### Node JS API + +* Fix Electron support when `nodeIntegration` is disabled. + +### Dart API + +* All range checks for `SassColor` constructors now throw `RangeError`s with + `start` and `end` set. + +## 1.32.5 + +* **Potentially breaking bug fix:** When using `@for` with numbers that have + units, the iteration variable now matches the unit of the initial number. This + matches the behavior of Ruby Sass and LibSass. + +### Node JS API + +* Fix a few infrequent errors when calling `render()` with `fiber` multiple + times simultaneously. + +* Avoid possible mangled error messages when custom functions or importers throw + unexpected exceptions. + +* Fix Electron support when `nodeIntegration` is disabled. + +## 1.32.4 * No user-visible changes. -## 1.0.0-beta.8 +## 1.32.3 + +* Optimize `==` for numbers that have different units. + +## 1.32.2 + +* Print the actual number that was received in unit deprecation warnings for + color functions. + +## 1.32.1 + +* Don't emit permissions errors on Windows and OS X when trying to determine the + real case of path names. + +## 1.32.0 + +* Deprecate passing non-`%` numbers as lightness and saturation to `hsl()`, + `hsla()`, `color.adjust()`, and `color.change()`. This matches the CSS + specification, which also requires `%` for all lightness and saturation + parameters. See [the Sass website][color-units] for more details. + +* Deprecate passing numbers with units other than `deg` as the hue to `hsl()`, + `hsla()`, `adjust-hue()`, `color.adjust()`, and `color.change()`. Unitless + numbers *are* still allowed here, since they're allowed by CSS. See [the Sass + website][color-units] for more details. + +* Improve error messages about incompatible units. + +* Properly mark some warnings emitted by `sass:color` functions as deprecation + warnings. + +### Dart API + +* Rename `SassNumber.valueInUnits()` to `SassNumber.coerceValue()`. The old name + remains, but is now deprecated. + +* Rename `SassNumber.coerceValueToUnit()`, a shorthand for + `SassNumber.coerceValue()` that takes a single numerator unit. + +* Add `SassNumber.coerceToMatch()` and `SassNumber.coerceValueToMatch()`, which + work like `SassNumber.coerce()` and `SassNumber.coerceValue()` but take a + `SassNumber` whose units should be matched rather than taking the units + explicitly. These generate better error messages than `SassNumber.coerce()` + and `SassNumber.coerceValue()`. + +* Add `SassNumber.convertToMatch()` and `SassNumber.convertValueToMatch()`, + which work like `SassNumber.coerceToMatch()` and + `SassNumber.coerceValueToMatch()` except they throw exceptions when converting + unitless values to or from units. + +* Add `SassNumber.compatibleWithUnit()`, which returns whether the number can be + coerced to a single numerator unit. + +## 1.31.0 + +* Add support for parsing `clamp()` as a special math function, the same way + `calc()` is parsed. + +* Properly load files in case-sensitive Windows directories with upper-case + names. + +## 1.30.0 + +* Fix a bug where `@at-root (without: all)` wouldn't properly remove a + `@keyframes` context when parsing selectors. + +### Node JS API + +* The generated `main()` function in `sass.js` now returns a `Promise` that + completes when the executable is finished running. + +### Dart API + +* Fix a bug that prevented importers from returning null when loading from a + URL that they had already canonicalized. + +## 1.29.0 + +* Support a broader syntax for `@supports` conditions, based on the latest + [Editor's Draft of CSS Conditional Rules 3]. Almost all syntax will be allowed + (with interpolation) in the conditions' parentheses, as well as function + syntax such as `@supports selector(...)`. + +[Editor's Draft of CSS Conditional Rules 3]: https://drafts.csswg.org/css-conditional-3/#at-supports + +## 1.28.0 + +* Add a [`color.hwb()`] function to `sass:color` that can express colors in [HWB] format. + +[`color.hwb()`]: https://sass-lang.com/documentation/modules/color#hwb +[HWB]: https://en.wikipedia.org/wiki/HWB_color_model + +* Add [`color.whiteness()`] and [`color.blackness()`] functions to `sass:color` + to get a color's [HWB] whiteness and blackness components. + +[`color.whiteness()`]: https://sass-lang.com/documentation/modules/color#whiteness +[`color.blackness()`]: https://sass-lang.com/documentation/modules/color#blackness + +* Add `$whiteness` and `$blackness` parameters to [`color.adjust()`], + [`color.change()`], and [`color.scale()`] to modify a color's [HWB] whiteness + and blackness components. + +[`color.adjust()`]: https://sass-lang.com/documentation/modules/color#adjust +[`color.change()`]: https://sass-lang.com/documentation/modules/color#change +[`color.scale()`]: https://sass-lang.com/documentation/modules/color#scale + +### Dart API + +* Add [HWB] support to the `SassColor` class, including a `SassColor.hwb()` + constructor, `whiteness` and `blackness` getters, and a `changeHwb()` method. + +[HWB]: https://en.wikipedia.org/wiki/HWB_color_model + +## 1.27.2 + +* No user-visible changes. + +## 1.27.1 + +* **Potentially breaking bug fix:** `meta.load-css()` now correctly uses the + name `$url` for its first argument, rather than `$module`. + +* Don't crash when using `Infinity` or `NaN` as a key in a map. + +* Emit a proper parse error for a `=` with no right-hand side in a function. + +* Avoid going exponential on certain recursive `@extend` edge cases. + +## 1.27.0 + +* Adds an overload to `map.merge()` that supports merging a nested map. + + `map.merge($map1, $keys..., $map2)`: The `$keys` form a path to the nested map + in `$map1`, into which `$map2` gets merged. + + See [the Sass documentation][map-merge] for more details. + + [map-merge]: https://sass-lang.com/documentation/modules/map#merge + +* Adds an overloaded `map.set()` function. + + `map.set($map, $key, $value)`: Adds to or updates `$map` with the specified + `$key` and `$value`. + + `map.set($map, $keys..., $value)`: Adds to or updates a map that is nested + within `$map`. The `$keys` form a path to the nested map in `$map`, into + which `$value` is inserted. + + See [the Sass documentation][map-set] for more details. + + [map-set]: https://sass-lang.com/documentation/modules/map#set + +* Add support for nested maps to `map.get()`. + For example, `map.get((a: (b: (c: d))), a, b, c)` would return `d`. + See [the documentation][map-get] for more details. + + [map-get]: https://sass-lang.com/documentation/modules/map#get + +* Add support for nested maps in `map.has-key`. + For example, `map.has-key((a: (b: (c: d))), a, b, c)` would return true. + See [the documentation][map-has-key] for more details. + + [map-has-key]: https://sass-lang.com/documentation/modules/map#has-key + +* Add a `map.deep-merge()` function. This works like `map.merge()`, except that + nested map values are *also* recursively merged. For example: + + ``` + map.deep-merge( + (color: (primary: red, secondary: blue), + (color: (secondary: teal) + ) // => (color: (primary: red, secondary: teal)) + ``` + + See [the Sass documentation][map-deep-merge] for more details. + + [map-deep-merge]: https://sass-lang.com/documentation/modules/map#deep-merge + +* Add a `map.deep-remove()` function. This allows you to remove keys from + nested maps by passing multiple keys. For example: + + ``` + map.deep-remove( + (color: (primary: red, secondary: blue)), + color, primary + ) // => (color: (secondary: blue)) + ``` + + See [the Sass documentation][map-deep-remove] for more details. + + [map-deep-remove]: https://sass-lang.com/documentation/modules/map#deep-remove + +* Fix a bug where custom property values in plain CSS were being parsed as + normal property values. + +### Dart API + +* Add a `Value.tryMap()` function which returns the `Value` as a `SassMap` if + it's a valid map, or `null` otherwise. This allows function authors to safely + retrieve maps even if they're internally stored as empty lists, without having + to catch exceptions from `Value.assertMap()`. + +## 1.26.12 + +* Fix a bug where nesting properties beneath a Sass-syntax custom property + (written as `#{--foo}: ...`) would crash. + +## 1.26.11 + +* **Potentially breaking bug fix:** `selector.nest()` now throws an error + if the first arguments contains the parent selector `&`. + +* Fixes a parsing bug with inline comments in selectors. + +* Improve some error messages for edge-case parse failures. + +* Throw a proper error when the same built-in module is `@use`d twice. + +* Don't crash when writing `Infinity` in JS mode. + +* Produce a better error message for positional arguments following named + arguments. + +## 1.26.10 + +* Fixes a bug where two adjacent combinators could cause an error. + +## 1.26.9 + +* Use an updated version of `node_preamble` when compiling to JS. + +## 1.26.8 + +* Fixes an error when emitting source maps to stdout. + +## 1.26.7 + +* No user-visible changes. + +## 1.26.6 + +* Fix a bug where escape sequences were improperly recognized in `@else` rules. + +### JavaScript API + +* Add `sass.NULL`, `sass.TRUE`, and `sass.FALSE` constants to match Node Sass's + API. + +* If a custom Node importer returns both `file` and `contents`, don't attempt to + read the `file`. Instead, use the `contents` provided by the importer, with + `file` as the canonical url. + +## 1.26.5 + +* No user-visible changes. + +## 1.26.4 + +* Be more memory-efficient when handling `@forward`s through `@import`s. + +## 1.26.3 + +* Fix a bug where `--watch` mode could go into an infinite loop compiling CSS + files to themselves. + +## 1.26.2 + +* More aggressively eliminate redundant selectors in the `selector.extend()` and + `selector.replace()` functions. + +## 1.26.1 + +### Command Line Interface + +* Fix a longstanding bug where `--watch` mode could enter into a state where + recompilation would not occur after a syntax error was introduced into a + dependency and then fixed. + +## 1.26.0 + +* **Potentially breaking bug fix:** `@use` rules whose URLs' basenames begin + with `_` now correctly exclude that `_` from the rules' namespaces. + +* Fix a bug where imported forwarded members weren't visible in mixins and + functions that were defined before the `@import`. + +* Don't throw errors if the exact same member is loaded or forwarded from + multiple modules at the same time. + +## 1.25.2 + +* Fix a bug where, under extremely rare circumstances, a valid variable could + become unassigned. + +## 1.25.0 + +* Add functions to the built-in "sass:math" module. + + * `clamp($min, $number, $max)`. Clamps `$number` in between `$min` and `$max`. + + * `hypot($numbers...)`. Given *n* numbers, outputs the length of the + *n*-dimensional vector that has components equal to each of the inputs. + + * Exponential. All inputs must be unitless. + * `log($number)` or `log($number, $base)`. If no base is provided, performs + a natural log. + * `pow($base, $exponent)` + * `sqrt($number)` + + * Trigonometric. The input must be an angle. If no unit is given, the input is + assumed to be in `rad`. + * `cos($number)` + * `sin($number)` + * `tan($number)` + + * Inverse trigonometric. The output is in `deg`. + * `acos($number)`. Input must be unitless. + * `asin($number)`. Input must be unitless. + * `atan($number)`. Input must be unitless. + * `atan2($y, $x)`. `$y` and `$x` must have compatible units or be unitless. + +* Add the variables `$pi` and `$e` to the built-in "sass:math" module. + +### JavaScript API + +* `constructor.value` fields on value objects now match their Node Sass + equivalents. + +## 1.24.5 + +* Highlight contextually-relevant sections of the stylesheet in error messages, + rather than only highlighting the section where the error was detected. + +## 1.24.4 + +### JavaScript API + +* Fix a bug where source map generation would crash with an absolute source map + path and a custom importer that returns string file contents. + +## 1.24.3 + +### Command Line Interface + +* Fix a bug where `sass --version` would crash for certain executable + distributions. + +## 1.24.2 + +### JavaScript API + +* Fix a bug introduced in the previous release that prevented custom importers + in Node.js from loading import-only files. + +## 1.24.1 + +* Fix a bug where the wrong file could be loaded when the same URL is used by + both a `@use` rule and an `@import` rule. + +## 1.24.0 + +* Add an optional `with` clause to the `@forward` rule. This works like the + `@use` rule's `with` clause, except that `@forward ... with` can declare + variables as `!default` to allow downstream modules to reconfigure their + values. + +* Support configuring modules through `@import` rules. + +## 1.23.8 + +* **Potentially breaking bug fix:** Members loaded through a nested `@import` + are no longer ever accessible outside that nested context. + +* Don't throw an error when importing two modules that both forward members with + the same name. The latter name now takes precedence over the former, as per + the specification. + +### Dart API + +* `SassFormatException` now implements `SourceSpanFormatException` (and thus + `FormatException`). + +## 1.23.7 + +* No user-visible changes + +## 1.23.6 + +* No user-visible changes. + +## 1.23.5 + +* Support inline comments in the indented syntax. + +* When an overloaded function receives the wrong number of arguments, guess + which overload the user actually meant to invoke, and display the invalid + argument error for that overload. + +* When `@error` is used in a function or mixin, print the call site rather than + the location of the `@error` itself to better match the behavior of calling a + built-in function that throws an error. + +## 1.23.4 + +### Command-Line Interface + +* Fix a bug where `--watch` wouldn't watch files referred to by `@forward` + rules. + +## 1.23.3 + +* Fix a bug where selectors were being trimmed over-eagerly when `@extend` + crossed module boundaries. + +## 1.23.2 + +### Command-Line Interface + +* Fix a bug when compiling all Sass files in a directory where a CSS file could + be compiled to its own location, creating an infinite loop in `--watch` mode. + +* Properly compile CSS entrypoints in directories outside of `--watch` mode. + +## 1.23.1 + +* Fix a bug preventing built-in modules from being loaded within a configured + module. + +* Fix a bug preventing an unconfigured module from being loaded from within two + different configured modules. + +* Fix a bug when `meta.load-css()` was used to load some files that included + media queries. + +* Allow `saturate()` in plain CSS files, since it can be used as a plain CSS + filter function. + +* Improve the error messages for trying to access functions like `lighten()` + from the `sass:color` module. + +## 1.23.0 + +* **Launch the new Sass module system!** This adds: + + * The [`@use` rule][], which loads Sass files as *modules* and makes their + members available only in the current file, with automatic namespacing. + + [`@use` rule]: https://sass-lang.com/documentation/at-rules/use + + * The [`@forward` rule][], which makes members of another Sass file available + to stylesheets that `@use` the current file. + + [`@forward` rule]: https://sass-lang.com/documentation/at-rules/forward + + * Built-in modules named `sass:color`, `sass:list`, `sass:map`, `sass:math`, + `sass:meta`, `sass:selector`, and `sass:string` that provide access to all + the built-in Sass functions you know and love, with automatic module + namespaces. + + * The [`meta.load-css()` mixin][], which includes the CSS contents of a module + loaded from a (potentially dynamic) URL. + + [`meta.load-css()` mixin]: https://sass-lang.com/documentation/modules/meta#load-css + + * The [`meta.module-variables()` function][], which provides access to the + variables defined in a given module. + + [`meta.module-variables()` function]: https://sass-lang.com/documentation/modules/meta#module-variables + + * The [`meta.module-functions()` function][], which provides access to the + functions defined in a given module. + + [`meta.module-functions()` function]: https://sass-lang.com/documentation/modules/meta#module-functions + + Check out [the Sass blog][migrator blog] for more information on the new + module system. You can also use the new [Sass migrator][] to automatically + migrate your stylesheets to the new module system! + + [migrator blog]: https://sass-lang.com/blog/the-module-system-is-launched + [Sass migrator]: https://sass-lang.com/documentation/cli/migrator + +## 1.22.12 + +* **Potentially breaking bug fix:** character sequences consisting of two or + more hyphens followed by a number (such as `--123`), or two or more hyphens on + their own (such as `--`), are now parsed as identifiers [in accordance with + the CSS spec][ident-token-diagram]. + + [ident-token-diagram]: https://drafts.csswg.org/css-syntax-3/#ident-token-diagram + + The sequence `--` was previously parsed as multiple applications of the `-` + operator. Since this is unlikely to be used intentionally in practice, we + consider this bug fix safe. + +### Command-Line Interface + +* Fix a bug where changes in `.css` files would be ignored in `--watch` mode. + +### JavaScript API + +* Allow underscore-separated custom functions to be defined. + +* Improve the performance of Node.js compilation involving many `@import`s. + +## 1.22.11 + +* Don't try to load unquoted plain-CSS indented-syntax imports. + +* Fix a couple edge cases in `@extend` logic and related selector functions: + + * Recognize `:matches()` and similar pseudo-selectors as superselectors of + matching complex selectors. + + * Recognize `::slotted()` as a superselector of other `::slotted()` selectors. + + * Recognize `:current()` with a vendor prefix as a superselector. + +## 1.22.10 + +* Fix a bug in which `get-function()` would fail to find a dash-separated + function when passed a function name with underscores. + +## 1.22.9 + +* Include argument names when reporting range errors and selector parse errors. + +* Avoid double `Error:` headers when reporting selector parse errors. + +* Clarify the error message when the wrong number of positional arguments are + passed along with a named argument. + +### JavaScript API + +* Re-add support for Node Carbon (8.x). + +## 1.22.8 + +### JavaScript API + +* Don't crash when running in a directory whose name contains URL-sensitive + characters. + +* Drop support for Node Carbon (8.x), which doesn't support `url.pathToFileURL`. + +## 1.22.7 + +* Restrict the supported versions of the Dart SDK to `^2.4.0`. + +## 1.22.6 + +* **Potentially breaking bug fix:** The `keywords()` function now converts + underscore-separated argument names to hyphen-separated names. This matches + LibSass's behavior, but not Ruby Sass's. + +* Further improve performance for logic-heavy stylesheets. + +* Improve a few error messages. + +## 1.22.5 + +### JavaScript API + +* Improve performance for logic-heavy stylesheets. + +## 1.22.4 + +* Fix a bug where at-rules imported from within a style rule would appear within + that style rule rather than at the root of the document. + +## 1.22.3 + +* **Potentially breaking bug fix:** The argument name for the `saturate()` + function is now `$amount`, to match the name in LibSass and originally in Ruby + Sass. + +* **Potentially breaking bug fix:** The `invert()` function now properly returns + `#808080` when passed `$weight: 50%`. This matches the behavior in LibSass and + originally in Ruby Sass, as well as being consistent with other nearby values + of `$weight`. + +* **Potentially breaking bug fix:** The `invert()` function now throws an error + if it's used [as a plain CSS function][plain-CSS invert] *and* the Sass-only + `$weight` parameter is passed. This never did anything useful, so it's + considered a bug fix rather than a full breaking change. + + [plain-CSS invert]: https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/invert + +* **Potentially breaking bug fix**: The `str-insert()` function now properly + inserts at the end of the string if the `$index` is `-1`. This matches the + behavior in LibSass and originally in Ruby Sass. + +* **Potentially breaking bug fix**: An empty map returned by `map-remove()` is + now treated as identical to the literal value `()`, rather than being treated + as though it had a comma separator. This matches the original behavior in Ruby + Sass. + +* The `adjust-color()` function no longer throws an error when a large `$alpha` + value is combined with HSL adjustments. + +* The `alpha()` function now produces clearer error messages when the wrong + number of arguments are passed. + +* Fix a bug where the `str-slice()` function could produce invalid output when + passed a string that contains characters that aren't represented as a single + byte in UTF-16. + +* Improve the error message for an unknown separator name passed to the `join()` + or `append()` functions. + +* The `zip()` function no longer deadlocks if passed no arguments. + +* The `map-remove()` function can now take a `$key` named argument. This matches + the signature in LibSass and originally in Ruby Sass. + +## 1.22.2 + +### JavaScript API + +* Avoid re-assigning the `require()` function to make the code statically + analyzable by Webpack. + +## 1.22.1 + +### JavaScript API + +* Expand the dependency on `chokidar` to allow 3.x. + +## 1.22.0 + +* Produce better stack traces when importing a file that contains a syntax + error. + +* Make deprecation warnings for `!global` variable declarations that create new + variables clearer, especially in the case where the `!global` flag is + unnecessary because the variables are at the top level of the stylesheet. + +### Dart API + +* Add a `Value.realNull` getter, which returns Dart's `null` if the value is + Sass's null. + +## 1.21.0 + +### Dart API + +* Add a `sass` executable when installing the package through `pub`. + +* Add a top-level `warn()` function for custom functions and importers to print + warning messages. + +## 1.20.3 + +* No user-visible changes. + +## 1.20.2 + +* Fix a bug where numbers could be written using exponential notation in + Node.js. + +* Fix a crash that would appear when writing some very large integers to CSS. + +### Command-Line Interface + +* Improve performance for stand-alone packages on Linux and Mac OS. + +### JavaScript API + +* Pass imports to custom importers before resolving them using `includePaths` or + the `SASS_PATH` environment variable. This matches Node Sass's behavior, so + it's considered a bug fix. + +## 1.20.1 + +* No user-visible changes. + +## 1.20.0 + +* Support attribute selector modifiers, such as the `i` in `[title="test" i]`. + +### Command-Line Interface + +* When compilation fails, Sass will now write the error message to the CSS + output as a comment and as the `content` property of a `body::before` rule so + it will show up in the browser (unless compiling to standard output). This can + be disabled with the `--no-error-css` flag, or forced even when compiling to + standard output with the `--error-css` flag. + +### Dart API + +* Added `SassException.toCssString()`, which returns the contents of a CSS + stylesheet describing the error, as above. + +## 1.19.0 + +* Allow `!` in `url()`s without quotes. + +### Dart API + +* `FilesystemImporter` now doesn't change its effective directory if the working + directory changes, even if it's passed a relative argument. + +## 1.18.0 + +* Avoid recursively listing directories when finding the canonical name of a + file on case-insensitive filesystems. + +* Fix importing files relative to `package:`-imported files. + +* Don't claim that "package:" URLs aren't supported when they actually are. + +### Command-Line Interface + +* Add a `--no-charset` flag. If this flag is set, Sass will never emit a + `@charset` declaration or a byte-order mark, even if the CSS file contains + non-ASCII characters. + +### Dart API + +* Add a `charset` option to `compile()`, `compileString()`, `compileAsync()` and + `compileStringAsync()`. If this option is set to `false`, Sass will never emit + a `@charset` declaration or a byte-order mark, even if the CSS file contains + non-ASCII characters. + +* Explicitly require that importers' `canonicalize()` methods be able to take + paths relative to their outputs as valid inputs. This isn't considered a + breaking change because the importer infrastructure already required this in + practice. + +## 1.17.4 + +* Consistently parse U+000C FORM FEED, U+000D CARRIAGE RETURN, and sequences of + U+000D CARRIAGE RETURN followed by U+000A LINE FEED as individual newlines. + +### JavaScript API + +* Add a `sass.types.Error` constructor as an alias for `Error`. This makes our + custom function API compatible with Node Sass's. + +## 1.17.3 + +* Fix an edge case where slash-separated numbers were written to the stylesheet + with a slash even when they're used as part of another arithmetic operation, + such as being concatenated with a string. + +* Don't put style rules inside empty `@keyframes` selectors. + +## 1.17.2 + +* Deprecate `!global` variable assignments to variables that aren't yet defined. + This deprecation message can be avoided by assigning variables to `null` at + the top level before globally assigning values to them. + +### Dart API + +* Explicitly mark classes that were never intended to be subclassed or + implemented as "sealed". + +## 1.17.1 + +* Properly quote attribute selector values that start with identifiers but end + with a non-identifier character. + +## 1.17.0 + +* Improve error output, particularly for errors that cover multiple lines. + +* Improve source locations for some parse errors. Rather than pointing to the + next token that wasn't what was expected, they point *after* the previous + token. This should generally provide more context for the syntax error. + +* Produce a better error message for style rules that are missing the closing + `}`. + +* Produce a better error message for style rules and property declarations + within `@function` rules. + +### Command-Line Interface + +* Passing a directory on the command line now compiles all Sass source files in + the directory to CSS files in the same directory, as though `dir:dir` were + passed instead of just `dir`. + +* The new error output uses non-ASCII Unicode characters by default. Add a + `--no-unicode` flag to disable this. + +## 1.16.1 + +* Fix a performance bug where stylesheet evaluation could take a very long time + when many binary operators were used in sequence. + +## 1.16.0 + +* `rgb()` and `hsl()` now treat unquoted strings beginning with `env()`, + `min()`, and `max()` as special number strings like `calc()`. + +## 1.15.3 + +* Properly merge `all and` media queries. These queries were previously being + merged as though `all` referred to a specific media type, rather than all + media types. + +* Never remove units from 0 values in compressed mode. This wasn't safe in + general, since some properties (such as `line-height`) interpret `0` as a + `` rather than a `` which can break CSS transforms. It's + better to do this optimization in a dedicated compressor that's aware of CSS + property semantics. + +* Match Ruby Sass's behavior in some edge-cases involving numbers with many + significant digits. + +* Emit escaped tab characters in identifiers as `\9` rather than a backslash + followed by a literal tab. + +### Command-Line Interface + +* The source map generated for a stylesheet read from standard input now uses a + `data:` URL to include that stylesheet's contents in the source map. + +### Node JS API + +* `this.includePaths` for a running importer is now a `;`-separated string on + Windows, rather than `:`-separated. This matches Node Sass's behavior. + +### Dart API + +* The URL used in a source map to refer to a stylesheet loaded from an importer + is now `ImportResult.sourceMapUrl` as documented. + +## 1.15.2 + +### Node JS API + +* When `setValue()` is called on a Sass string object, make it unquoted even if + it was quoted originally, to match the behavior of Node Sass. + +## 1.15.1 + +* Always add quotes to attribute selector values that begin with `--`, since IE + 11 doesn't consider them to be identifiers. + +## 1.15.0 + +* Add support for passing arguments to `@content` blocks. See [the + proposal][content-args] for details. + +* Add support for the new `rgb()` and `hsl()` syntax introduced in CSS Colors + Level 4, such as `rgb(0% 100% 0% / 0.5)`. See [the proposal][color-4-rgb-hsl] + for more details. + +* Add support for interpolation in at-rule names. See [the + proposal][at-rule-interpolation] for details. + +* Add paths from the `SASS_PATH` environment variable to the load paths in the + command-line interface, Dart API, and JS API. These load paths are checked + just after the load paths explicitly passed by the user. + +* Allow saturation and lightness values outside of the `0%` to `100%` range in + the `hsl()` and `hsla()` functions. They're now clamped to be within that + range rather than producing an error if they're outside it. + +* Properly compile selectors that end in escaped whitespace. + +[content-args]: https://github.com/sass/language/blob/master/accepted/content-args.md +[color-4-rgb-hsl]: https://github.com/sass/language/blob/master/accepted/color-4-rgb-hsl.md +[at-rule-interpolation]: https://github.com/sass/language/blob/master/accepted/at-rule-interpolation.md + +### JavaScript API + +* Always include the error location in error messages. + +## 1.14.4 + +* Properly escape U+0009 CHARACTER TABULATION in unquoted strings. + +## 1.14.3 + +* Treat `:before`, `:after`, `:first-line`, and `:first-letter` as + pseudo-elements for the purposes of `@extend`. + +* When running in compressed mode, remove spaces around combinators in complex + selectors, so a selector like `a > b` is output as `a>b`. + +* Properly indicate the source span for errors involving binary operation + expressions whose operands are parenthesized. + +## 1.14.2 + +* Fix a bug where loading the same stylesheet from two different import paths + could cause its imports to fail to resolve. + +* Properly escape U+001F INFORMATION SEPARATOR ONE in unquoted strings. + +### Command-Line Interface + +* Don't crash when using `@debug` in a stylesheet passed on standard input. + +### Dart API + +* `AsyncImporter.canonicalize()` and `Importer.canonicalize()` must now return + absolute URLs. Relative URLs are still supported, but are deprecated and will + be removed in a future release. + +## 1.14.1 + +* Canonicalize escaped digits at the beginning of identifiers as hex escapes. + +* Properly parse property declarations that are both *in* content blocks and + written *after* content blocks. + +### Command-Line Interface + +* Print more readable paths in `--watch` mode. + +## 1.14.0 + +### BREAKING CHANGE + +In accordance with our [compatibility policy][], breaking changes made for CSS +compatibility reasons are released as minor version revision after a three-month +deprecation period. + +[compatibility policy]: README.md#compatibility-policy + +* Tokens such as `#abcd` that are now interpreted as hex colors with alpha + channels, rather than unquoted ID strings. + +## 1.13.4 + +### Node JS + +* Tweak JS compilation options to substantially improve performance. + +## 1.13.3 + +* Properly generate source maps for stylesheets that emit `@charset` + declarations. + +### Command-Line Interface + +* Don't error out when passing `--embed-source-maps` along with + `--embed-sources` for stylesheets that contain non-ASCII characters. + +## 1.13.2 + +* Properly parse `:nth-child()` and `:nth-last-child()` selectors with + whitespace around the argument. + +* Don't emit extra whitespace in the arguments for `:nth-child()` and + `:nth-last-child()` selectors. + +* Fix support for CSS hacks in plain CSS mode. + +## 1.13.1 + +* Allow an IE-style single equals operator in plain CSS imports. + +## 1.13.0 + +* Allow `@extend` to be used with multiple comma-separated simple selectors. + This is already supported by other implementations, but fell through the + cracks for Dart Sass until now. + +* Don't crash when a media rule contains another media rule followed by a style + rule. + +## 1.12.0 + +### Dart API + +* Add a `SassException` type that provides information about Sass compilation + failures. + +### Node JS API + +* Remove the source map comment from the compiled JS. We don't ship with the + source map, so this pointed to nothing. + +## 1.11.0 + +* Add support for importing plain CSS files. They can only be imported *without* + an extension—for example, `@import "style"` will import `style.css`. Plain CSS + files imported this way only support standard CSS features, not Sass + extensions. + + See [the proposal][css-import] for details. + +* Add support for CSS's `min()` and `max()` [math functions][]. A `min()` and + `max()` call will continue to be parsed as a Sass function if it involves any + Sass-specific features like variables or function calls, but if it's valid + plain CSS (optionally with interpolation) it will be emitted as plain CSS instead. + + See [the proposal][css-min-max] for details. + +* Add support for range-format media features like `(10px < width < 100px)`. See + [the proposal][media-ranges] for details. + +* Normalize escape codes in identifiers so that, for example, `éclair` and + `\E9clair` are parsed to the same value. See + [the proposal][identifier-escapes] for details. + +* Don't choke on a [byte-order mark][] at the beginning of a document when + running in JavaScript. + +[math functions]: https://drafts.csswg.org/css-values/#math-function +[css-import]: https://github.com/sass/language/blob/master/accepted/css-imports.md +[css-min-max]: https://github.com/sass/language/blob/master/accepted/min-max.md +[media-ranges]: https://github.com/sass/language/blob/master/accepted/media-ranges.md +[identifier-escapes]: https://github.com/sass/language/blob/master/accepted/identifier-escapes.md +[byte-order mark]: https://en.wikipedia.org/wiki/Byte_order_mark + +### Command-Line Interface + +* The `--watch` command now continues to recompile a file after a syntax error + has been detected. + +### Dart API + +* Added a `Syntax` enum to indicate syntaxes for Sass source files. + +* The `compile()` and `compileAsync()` functions now parse files with the `.css` + extension as plain CSS. + +* Added a `syntax` parameter to `compileString()` and `compileStringAsync()`. + +* Deprecated the `indented` parameter to `compileString()` and `compileStringAsync()`. + +* Added a `syntax` parameter to `new ImporterResult()` and a + `ImporterResult.syntax` getter to set the syntax of the source file. + +* Deprecated the `indented` parameter to `new ImporterResult()` and the + `ImporterResult.indented` getter in favor of `syntax`. + +## 1.10.4 + +### Command-Line Interface + +* Fix a Homebrew installation failure. + +## 1.10.3 + +### Command-Line Interface + +* Run the Chocolatey script with the correct arguments so it doesn't crash. + +## 1.10.2 + +* No user-visible changes. + +## 1.10.1 + +### Node JS API + +* Don't crash when passing both `includePaths` and `importer`. + +## 1.10.0 + +* When two `@media` rules' queries can't be merged, leave nested rules in place + for browsers that support them. + +* Fix a typo in an error message. + +## 1.9.2 + +### Node JS API + +* Produce more readable filesystem errors, such as when a file doesn't exist. + +## 1.9.1 + +### Command-Line Interface + +* Don't emit ANSI codes to Windows terminals that don't support them. + +* Fix a bug where `--watch` crashed on Mac OS. + +## 1.9.0 + +### Node API + +* Add support for `new sass.types.Color(argb)` for creating colors from ARGB hex + numbers. This was overlooked when initially adding support for Node Sass's + JavaScript API. + +## 1.8.0 + +### Command-Line Interface + +* Add a `--poll` flag to make `--watch` mode repeatedly check the filesystem for + updates rather than relying on native filesystem notifications. + +* Add a `--stop-on-error` flag to stop compiling additional files once an error + is encountered. + +## 1.7.3 + +* No user-visible changes. + +## 1.7.2 + +* Add a deprecation warning for `@-moz-document`, except for cases where only an + empty `url-prefix()` is used. Support is [being removed from Firefox][] and + will eventually be removed from Sass as well. + +[being removed from Firefox]: https://www.fxsitecompat.com/en-CA/docs/2018/moz-document-support-has-been-dropped-except-for-empty-url-prefix/ + +* Fix a bug where `@-moz-document` functions with string arguments weren't being + parsed. + +### Command-Line Interface + +* Don't crash when a syntax error is added to a watched file. + +## 1.7.1 + +* Fix crashes in released binaries. + +## 1.7.0 + +* Emit deprecation warnings for tokens such as `#abcd` that are ambiguous + between ID strings and hex colors with alpha channels. These will be + interpreted as colors in a release on or after 19 September 2018. + +* Parse unambiguous hex colors with alpha channels as colors. + +* Fix a bug where relative imports from files on the load path could look in the + incorrect location. + +## 1.6.2 + +### Command-Line Interface + +* Fix a bug where the source map comment in the generated CSS could refer to the + source map file using an incorrect URL. + +## 1.6.1 + +* No user-visible changes. + +## 1.6.0 + +* Produce better errors when expected tokens are missing before a closing brace. + +* Avoid crashing when compiling a non-partial stylesheet that exists on the + filesystem next to a partial with the same name. + +### Command-Line Interface + +* Add support for the `--watch`, which watches for changes in Sass files on the + filesystem and ensures that the compiled CSS is up-to-date. + +* When using `--update`, surface errors when an import doesn't exist even if the + file containing the import hasn't been modified. + +* When compilation fails, delete the output file rather than leaving an outdated + version. + +## 1.5.1 + +* Fix a bug where an absolute Windows path would be considered an `input:output` + pair. + +* Forbid custom properties that have no values, like `--foo:;`, since they're + forbidden by the CSS spec. + +## 1.5.0 + +* Fix a bug where an importer would be passed an incorrectly-resolved URL when + handling a relative import. + +* Throw an error when an import is ambiguous due to a partial and a non-partial + with the same name, or multiple files with different extensions. This matches + the standard Sass behavior. + +### Command-Line Interface + +* Add an `--interactive` flag that supports interactively running Sass + expressions (thanks to [Jen Thakar][]!). + +[Jen Thakar]: https://github.com/jathak + +## 1.4.0 + +* Improve the error message for invalid semicolons in the indented syntax. + +* Properly disallow semicolons after declarations in the indented syntax. + +### Command-Line Interface + +* Add support for compiling multiple files at once by writing + `sass input.scss:output.css`. Note that unlike Ruby Sass, this *always* + compiles files by default regardless of when they were modified. + + This syntax also supports compiling entire directories at once. For example, + `sass templates/stylesheets:public/css` compiles all non-partial Sass files + in `templates/stylesheets` to CSS files in `public/css`. + +* Add an `--update` flag that tells Sass to compile only stylesheets that have + been (transitively) modified since the CSS file was generated. + +### Dart API + +* Add `Importer.modificationTime()` and `AsyncImporter.modificationTime()` which + report the last time a stylesheet was modified. + +### Node API + +* Generate source maps when the `sourceMaps` option is set to a string and the + `outFile` option is not set. + +## 1.3.2 + +* Add support for `@elseif` as an alias of `@else if`. This is not an + intentional feature, so using it will cause a deprecation warning. It will be + removed at some point in the future. + +## 1.3.1 + +### Node API + +* Fix loading imports relative to stylesheets that were themselves imported + though relative include paths. + +## 1.3.0 + +### Command-Line Interface + +* Generate source map files by default when writing to disk. This can be + disabled by passing `--no-source-map`. + +* Add a `--source-map-urls` option to control whether the source file URLs in + the generated source map are relative or absolute. + +* Add an `--embed-sources` option to embed the contents of all source files in + the generated source map. + +* Add an `--embed-source-map` option to embed the generated source map as a + `data:` URL in the generated CSS. + +### Dart API + +* Add a `sourceMap` parameter to `compile()`, `compileString()`, + `compileAsync()`, and `compileStringAsync()`. This takes a callback that's + called with a [`SingleMapping`][] that contains the source map information for + the compiled CSS file. + +[`SingleMapping`]: https://www.dartdocs.org/documentation/source_maps/latest/source_maps.parser/SingleMapping-class.html + +### Node API + +* Added support for the `sourceMap`, `omitSourceMapUrl`, `outFile`, + `sourceMapContents`, `sourceMapEmbed`, and `sourceMapRoot` options to + `render()` and `renderSync()`. + +* Fix a bug where passing a relative path to `render()` or `renderSync()` would + cause relative imports to break. + +* Fix a crash when printing warnings in stylesheets compiled using `render()` or + `renderSync()`. + +* Fix a bug where format errors were reported badly on Windows. + +## 1.2.1 + +* Always emit units in compressed mode for `0` dimensions other than lengths and + angles. + +## 1.2.0 + +* The command-line executable will now create the directory for the resulting + CSS if that directory doesn't exist. + +* Properly parse `#{$var} -#{$var}` as two separate values in a list rather than + one value being subtracted from another. + +* Improve the error message for extending compound selectors. + +## 1.1.1 + +* Add a commit that was accidentally left out of 1.1.0. + +## 1.1.0 + +* The command-line executable can now be used to write an output file to disk + using `sass input.scss output.css`. + +* Use a POSIX-shell-compatible means of finding the location of the `sass` shell + script. + +## 1.0.0 + +**Initial stable release.** + +### Changes Since 1.0.0-rc.1 + +* Allow `!` in custom property values ([#260][]). + +[#260]: https://github.com/sass/dart-sass/issues/260 + +#### Dart API + +* Remove the deprecated `render()` function. + +#### Node API + +* Errors are now subtypes of the `Error` type. + +* Allow both the `data` and `file` options to be passed to `render()` and + `renderSync()` at once. The `data` option will be used as the contents of the + stylesheet, and the `file` option will be used as the path for error reporting + and relative imports. This matches Node Sass's behavior. + +## 1.0.0-rc.1 + +* Add support for importing an `_index.scss` or `_index.sass` file when + importing a directory. + +* Add a `--load-path` command-line option (alias `-I`) for passing additional + paths to search for Sass files to import. + +* Add a `--quiet` command-line option (alias `-q`) for silencing warnings. + +* Add an `--indented` command-line option for using the indented syntax with a + stylesheet from standard input. + +* Don't merge the media queries `not type` and `(feature)`. We had previously + been generating `not type and (feature)`, but that's not actually the + intersection of the two queries. + +* Don't crash on `$x % 0`. + +* The standalone executable distributed on GitHub is now named `sass` rather + than `dart-sass`. The `dart-sass` executable will remain, with a deprecation + message, until 1.0.0 is released. + +### Dart API + +* Add a `Logger` class that allows users to control how messages are printed by + stylesheets. + +* Add a `logger` parameter to `compile()`, `compileAsync()`, `compileString()`, + and `compileStringAsync()`. + +### Node JS API + +* Import URLs passed to importers are no longer normalized. For example, if a + stylesheet contains `@import "./foo.scss"`, importers will now receive + `"./foo.scss"` rather than `"foo.scss"`. + +## 1.0.0-beta.5.3 + +* Support hard tabs in the indented syntax. + +* Improve the formatting of comments that don't start on the same line as the + opening `/*`. + +* Preserve whitespace after `and` in media queries in compressed mode. + +### Indented Syntax + +* Properly parse multi-line selectors. + +* Don't deadlock on `/*` comments. + +* Don't add an extra `*/` to comments that already have it. + +* Preserve empty lines in `/*` comments. + +## 1.0.0-beta.5.2 + +* Fix a bug where some colors would crash `compressed` mode. + +## 1.0.0-beta.5.1 + +* Add a `compressed` output style. + +* Emit a warning when `&&` is used, since it's probably not what the user means. + +* `round()` now returns the correct results for negative numbers that should + round down. + +* `var()` may now be passed in place of multiple arguments to `rgb()`, `rgba()`, + `hsl()` and `hsla()`. + +* Fix some cases where equivalent numbers wouldn't count as the same keys in + maps. + +* Fix a bug where multiplication like `(1/1px) * (1px/1)` wouldn't properly + cancel out units. + +* Fix a bug where dividing by a compatible unit would produce an invalid + result. + +* Remove a non-`sh`-compatible idiom from the standalone shell script. + +### Dart API + +* Add a `functions` parameter to `compile()`, `compleString()`, + `compileAsync()`, and `compileStringAsync()`. This allows users to define + custom functions in Dart that can be invoked from Sass stylesheets. + +* Expose the `Callable` and `AsyncCallable` types, which represent functions + that can be invoked from Sass. + +* Expose the `Value` type and its subclasses, as well as the top-level + `sassTrue`, `sassFalse`, and `sassNull` values, which represent Sass values + that may be passed into or returned from custom functions. + +* Expose the `OutputStyle` enum, and add a `style` parameter to `compile()`, + `compleString()`, `compileAsync()`, and `compileStringAsync()` that allows + users to control the output style. + +### Node JS API + +* Support the `functions` option. + +* Support the `"compressed"` value for the `outputStyle` option. + +## 1.0.0-beta.4 + +* Support unquoted imports in the indented syntax. + +* Fix a crash when `:not(...)` extends a selector that appears in + `:not(:not(...))`. + +### Node JS API + +* Add support for asynchronous importers to `render()` and `renderSync()`. + +### Dart API + +* Add `compileAsync()` and `compileStringAsync()` methods. These run + asynchronously, which allows them to take asynchronous importers (see below). + +* Add an `AsyncImporter` class. This allows imports to be resolved + asynchronously in case no synchronous APIs are available. `AsyncImporter`s are + only compatible with `compileAysnc()` and `compileStringAsync()`. + +## 1.0.0-beta.3 + +* Properly parse numbers with exponents. + +* Don't crash when evaluating CSS variables whose names are entirely + interpolated (for example, `#{--foo}: ...`). + +### Node JS API + +* Add support for the `importer` option to `render()` and `renderSync()`. + Only synchronous importers are currently supported. + +### Dart API + +* Added an `Importer` class. This can be extended by users to provide support + for custom resolution for `@import` rules. + +* Added built-in `FilesystemImporter` and `PackageImporter` implementations that + support resolving `file:` and `package:` URLs, respectively. + +* Added an `importers` argument to the `compile()` and `compileString()` + functions that provides `Importer`s to use when resolving `@import` rules. + +* Added a `loadPaths` argument to the `compile()` and `compileString()` + functions that provides paths to search for stylesheets when resolving + `@import` rules. This is a shorthand for passing `FilesystemImporter`s to the + `importers` argument. + +## 1.0.0-beta.2 + +* Add support for the `::slotted()` pseudo-element. + +* Generated transparent colors will now be emitted as `rgba(0, 0, 0, 0)` rather + than `transparent`. This works around a bug wherein IE incorrectly handles the + latter format. + +### Command-Line Interface + +* Improve the logic for whether to use terminal colors by default. + +### Node JS API + +* Add support for `data`, `includePaths`, `indentedSyntax`, `lineFeed`, + `indentWidth`, and `indentType` options to `render()` and `renderSync()`. + +* The result object returned by `render()` and `renderSync()` now includes the + `stats` object which provides metadata about the compilation process. + +* The error object thrown by `render()` and `renderSync()` now includes `line`, + `column`, `file`, `status`, and `formatted` fields. The `message` field and + `toString()` also provide more information. + +### Dart API + +* Add a `renderString()` method for rendering Sass source that's not in a file + on disk. + +## 1.0.0-beta.1 + +* Drop support for the reference combinator. This has been removed from the + spec, and will be deprecated and eventually removed in other implementations. + +* Trust type annotations when compiling to JavaScript, which makes it + substantially faster. + +* Compile to minified JavaScript, which decreases the code size substantially + and makes startup a little faster. + +* Fix a crash when inspecting a string expression that ended in "\a". + +* Fix a bug where declarations and `@extend` were allowed outside of a style + rule in certain circumstances. + +* Fix `not` in parentheses in `@supports` conditions. + +* Allow `url` as an identifier name. + +* Properly parse `/***/` in selectors. + +* Properly parse unary operators immediately after commas. + +* Match Ruby Sass's rounding behavior for all functions. + +* Allow `\` at the beginning of a selector in the indented syntax. + +* Fix a number of `@extend` bugs: + + * `selector-extend()` and `selector-replace()` now allow compound selector + extendees. + + * Remove the universal selector `*` when unifying with other selectors. + + * Properly unify the result of multiple simple selectors in the same compound + selector being extended. + + * Properly handle extensions being extended. + + * Properly follow the [first law of `@extend`][laws]. + + * Fix selector specificity tracking to follow the + [second law of `@extend`][laws]. + + * Allow extensions that match selectors but fail to unify. + + * Partially-extended selectors are no longer used as parent selectors. + + * Fix an edge case where both the extender and the extended selector + have invalid combinator sequences. + + * Don't crash with a "Bad state: no element" error in certain edge cases. + +[laws]: https://github.com/sass/sass/issues/324#issuecomment-4607184 + +## 1.0.0-alpha.9 + +* Elements without a namespace (such as `div`) are no longer unified with + elements with the empty namespace (such as `|div`). This unification didn't + match the results returned by `is-superselector()`, and was not guaranteed to + be valid. + +* Support `&` within `@at-root`. + +* Properly error when a compound selector is followed immediately by `&`. + +* Properly handle variable scoping in `@at-root` and nested properties. + +* Properly handle placeholder selectors in selector pseudos. + +* Properly short-circuit the `or` and `and` operators. + +* Support `--$variable`. + +* Don't consider unitless numbers equal to numbers with units. + +* Warn about using named colors in interpolation. + +* Don't emit loud comments in functions. + +* Detect import loops. + +* Fix `@import` with a `supports()` clause. + +* Forbid functions named "and", "or", and "not". + +* Fix `type-of()` with a function. + +* Emit a nicer error for invalid tokens in a selector. + +* Fix `invert()` with a `$weight` parameter. + +* Fix a unit-parsing edge-cases. + +* Always parse imports with queries as plain CSS imports. + +* Support `&` followed by a non-identifier. + +* Properly handle split media queries. + +* Properly handle a placeholder selector that isn't at the beginning of a + compound selector. + +* Fix more `str-slice()` bugs. + +* Fix the `%` operator. + +* Allow whitespace between `=` and the mixin name in the indented syntax. + +* Fix some slash division edge cases. + +* Fix `not` when used like a function. + +* Fix attribute selectors with single-character values. + +* Fix some bugs with the `call()` function. + +* Properly handle a backslash followed by a CRLF sequence in a quoted string. + +* Fix numbers divided by colors. + +* Support slash-separated numbers in arguments to plain CSS functions. + +* Error out if a function is passed an unknown named parameter. + +* Improve the speed of loading large files on Node. + +* Don't consider browser-prefixed selector pseudos to be superselectors of + differently- or non-prefixed selector pseudos with the same base name. + +* Fix an `@extend` edge case involving multiple combinators in a row. + +* Fix a bug where a `@content` block could get incorrectly passed to a mixin. + +* Properly isolate the lexical environments of different calls to the same mixin + and function. + +## 1.0.0-alpha.8 + +* Add the `content-exists()` function. + +* Support interpolation in loud comments. + +* Fix a bug where even valid semicolons and exclamation marks in custom property + values were disallowed. + +* Disallow invalid function names. + +* Disallow extending across media queries. + +* Properly parse whitespace after `...` in argument declaration lists. + +* Support terse mixin syntax in the indented syntax. + +* Fix `@at-root` query parsing. + +* Support special functions in `@-moz-document`. + +* Support `...` after a digit. + +* Fix some bugs when treating a map as a list of pairs. + +## 1.0.0-alpha.7 + +* Fix `function-exists()`, `variable-exists()`, and `mixin-exists()` to use the + lexical scope rather than always using the global scope. + +* `str-index()` now correctly inserts at negative indices. + +* Properly parse `url()`s that contain comment-like text. + +* Fix a few more small `@extend` bugs. + +* Fix a bug where interpolation in a quoted string was being dropped in some + circumstances. + +* Properly handle `@for` rules where each bound has a different unit. + +* Forbid mixins and functions from being defined in control directives. + +* Fix a superselector-computation edge case involving `:not()`. + +* Gracefully handle input files that are invalid UTF-8. + +* Print a Sass stack trace when a file fails to load. + +## 1.0.0-alpha.6 + +* Allow `var()` to be passed to `rgb()`, `rgba()`, `hsl()`, and `hsla()`. + +* Fix conversions between numbers with `dpi`, `dpcm`, and `dppx` units. + Previously these conversions were inverted. + +* Don't crash when calling `str-slice()` with an `$end-at` index lower than the + `$start-at` index. + +* `str-slice()` now correctly returns `""` when `$end-at` is negative and points + before the beginning of the string. + +* Interpolation in quoted strings now properly preserves newlines. + +* Don't crash when passing only `$hue` or no keyword arguments to + `adjust-color()`, `scale-color()`, or `change-color()`. + +* Preserve escapes in identifiers. This used to only work for identifiers in + SassScript. + +* Fix a few small `@extend` bugs. + +## 1.0.0-alpha.5 + +* Fix bounds-checking for `opacify()`, `fade-in()`, `transparentize()`, and + `fade-out()`. + +* Fix a bug with `@extend` superselector calculations. + +* Fix some cases where `#{...}--` would fail to parse in selectors. + +* Allow a single number to be passed to `saturate()` for use in filter contexts. + +* Fix a bug where `**/` would fail to close a loud comment. + +* Fix a bug where mixin and function calls could set variables incorrectly. + +* Move plain CSS `@import`s to the top of the document. + +## 1.0.0-alpha.4 + +* Add support for bracketed lists. + +* Add support for Unicode ranges. + +* Add support for the Microsoft-style `=` operator. + +* Print the filename for `@debug` rules. + +* Fix a bug where `1 + - 2` and similar constructs would crash the parser. + +* Fix a bug where `@extend` produced the wrong result when used with + selector combinators. + +* Fix a bug where placeholder selectors were not allowed to be unified. + +* Fix the `mixin-exists()` function. + +* Fix `:nth-child()` and `:nth-last-child()` parsing when they contain `of + selector`. + +## 1.0.0-alpha.3 + +* Fix a bug where color equality didn't take the alpha channel into account. + +* Fix a bug with converting some RGB colors to HSL. + +* Fix a parent selector resolution bug. + +* Properly declare the arguments for `opacify()` and related functions. + +* Add a missing dependency on the `stack_trace` package. + +* Fix broken Windows archives. + +* Emit colors using their original representation if possible. + +* Emit colors without an original representation as names if possible. + +## 1.0.0-alpha.2 + +* Fix a bug where variables, functions, and mixins were broken in imported + files. -* Support version 1.0.0-beta.11 of the Sass embedded protocol: - * Support `VersionRequest` and `VersionResponse`. - * Support `CompileRequest.quiet_deps` and `.verbose`. - * Set `CanonicalizeRequest.from_import`. - * Set `CompileSuccess.loaded_urls`. +## 1.0.0-alpha.1 -* Properly throw errors for range checks for colors. +* Initial alpha release. diff --git a/pubspec.lock b/pubspec.lock index d3bc91866..0f7f2e2b8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.4" + version: "1.49.5" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.33" + version: "1.0.0-beta.34" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 152e498f3..e945db255 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.4 +version: 1.49.5 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.4 + sass: 1.49.5 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From b295292d2a28c5d4f7e8315eb8ccefb2fb74bbd6 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 1 Feb 2022 21:13:12 +0000 Subject: [PATCH 076/162] Update Dart Sass version and release --- CHANGELOG.md | 6 +++++- pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d941373a..0405108d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.49.5 +## 1.49.6 ### Embedded Sass @@ -8,6 +8,10 @@ * First stable release of the `sass_embedded` pub package that contains the Embedded Dart Sass compiler. +## 1.49.5 + +* No user-visible changes. + ## 1.49.4 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index 0f7f2e2b8..3bb324ff7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.5" + version: "1.49.6" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.34" + version: "1.0.0-beta.35" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e945db255..7116eacaf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.5 +version: 1.49.6 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.5 + sass: 1.49.6 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 1b072bdedb53c261d278005afeff590dbcc8ef01 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 1 Feb 2022 13:46:38 -0800 Subject: [PATCH 077/162] Update the CHANGELOG for embedded-host-node before releasing it (#73) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 833fcc2df..c5a47b059 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -180,6 +180,7 @@ jobs: ."compiler-version" |= $version ' > package.json.tmp && mv package.json.tmp package.json + curl https://raw.githubusercontent.com/sass/dart-sass/${{ steps.version.outputs.version }}/CHANGELOG.md > CHANGELOG.md shell: bash - uses: EndBug/add-and-commit@v8 From 2b5c7d562f492d704b728744c84a7848008c0f2e Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 1 Feb 2022 22:06:47 +0000 Subject: [PATCH 078/162] Update Dart Sass version and release --- CHANGELOG.md | 6 +++++- pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0405108d4..294e3d442 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.49.6 +## 1.49.7 ### Embedded Sass @@ -8,6 +8,10 @@ * First stable release of the `sass_embedded` pub package that contains the Embedded Dart Sass compiler. +## 1.49.6 + +* No user-visible changes. + ## 1.49.5 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index 3bb324ff7..629d2aad3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.6" + version: "1.49.7" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.35" + version: "1.0.0-beta.36" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7116eacaf..4a12251df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.6 +version: 1.49.7 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.6 + sass: 1.49.7 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 2cc136022f6b5bedc473290bc74f08b0e919c89b Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 9 Feb 2022 22:09:30 +0100 Subject: [PATCH 079/162] Use dart analyze instead of the old dartanalyzer (#70) The old dartanalyzer does not take exclude rules into account properly for linting rules if the excluded file is also imported from a non-excluded file (which is the case for the files generated by protobuf). The new tool does not suffer from this issue. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5a47b059..c407081e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,7 +93,7 @@ jobs: - run: dart pub run grinder protobuf env: {UPDATE_SASS_PROTOCOL: false} - name: Analyze dart - run: dartanalyzer --fatal-warnings ./ + run: dart analyze --fatal-warnings ./ format: name: Code formatting From 565318f47f39fab348d864a572259beb5ac3bdf2 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 9 Feb 2022 22:09:47 +0100 Subject: [PATCH 080/162] Remove an unused import (#71) --- test/dependencies_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/test/dependencies_test.dart b/test/dependencies_test.dart index bf2f2ca51..abee7be34 100644 --- a/test/dependencies_test.dart +++ b/test/dependencies_test.dart @@ -5,7 +5,6 @@ import 'dart:io'; import 'package:pubspec_parse/pubspec_parse.dart'; -import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; /// This package's pubspec. From 366a9f4c5bc087e7fbcf1654b45fc2647d5edf7a Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 17 Feb 2022 21:36:10 +0000 Subject: [PATCH 081/162] Update Dart Sass version and release --- CHANGELOG.md | 14 ++++++++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 294e3d442..a7bd5f485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 1.49.8 + +* Fixed a bug where some plain CSS imports would not be emitted. + +### JS API + +* Fix a bug where inspecting the Sass module in the Node.js console crashed on + Node 17. + +### Embedded Sass + +* Fix a bug where source map URLs were incorrectly generated when passing + importers to the legacy API. + ## 1.49.7 ### Embedded Sass diff --git a/pubspec.lock b/pubspec.lock index 629d2aad3..5217976fd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.7" + version: "1.49.8" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.36" + version: "1.0.0-beta.37" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4a12251df..f9d014046 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.7 +version: 1.49.8 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.7 + sass: 1.49.8 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 31d0eb695e01ba061deeb8767196d3d967f9569c Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 24 Feb 2022 20:40:23 +0000 Subject: [PATCH 082/162] Update Dart Sass version and release --- CHANGELOG.md | 7 +++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7bd5f485..b20597e22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.49.9 + +### Embedded Sass + +* Fixed a bug where the legacy API could crash when passed an empty importer + list. + ## 1.49.8 * Fixed a bug where some plain CSS imports would not be emitted. diff --git a/pubspec.lock b/pubspec.lock index 5217976fd..1f3f677a8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.8" + version: "1.49.9" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.37" + version: "1.0.0-beta.38" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f9d014046..b3656d207 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.8 +version: 1.49.9 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.8 + sass: 1.49.9 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 38451a4f9a55c2854ff641a1389e2f2b6a2e09d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Mon, 28 Mar 2022 15:04:05 -0700 Subject: [PATCH 083/162] Deploy linux arm64 release to github (#77) --- .github/workflows/ci.yml | 55 ++++++++++++++++++++++++++++++++-------- pubspec.yaml | 4 +-- tool/grind.dart | 2 +- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c407081e0..bcf19348e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,11 +51,11 @@ jobs: with: {repo: sass/embedded-protocol, path: build/embedded-protocol} - run: dart pub get - - run: dart pub run grinder protobuf + - run: dart run grinder protobuf env: {UPDATE_SASS_PROTOCOL: false} - - run: dart pub run grinder pkg-standalone-dev + - run: dart run grinder pkg-standalone-dev - name: Run tests - run: dart pub run test -r expanded + run: dart run test -r expanded static_analysis: name: Static analysis @@ -90,7 +90,7 @@ jobs: with: {repo: sass/embedded-protocol, path: build/embedded-protocol} - run: dart pub get - - run: dart pub run grinder protobuf + - run: dart run grinder protobuf env: {UPDATE_SASS_PROTOCOL: false} - name: Analyze dart run: dart analyze --fatal-warnings ./ @@ -117,9 +117,42 @@ jobs: with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 - run: dart pub get - - run: dart pub run grinder protobuf + - run: dart run grinder protobuf - name: Deploy - run: dart pub run grinder pkg-github-release pkg-github-linux + run: dart run grinder pkg-github-release pkg-github-linux-ia32 pkg-github-linux-x64 + env: {GH_BEARER_TOKEN: "${{ github.token }}"} + + deploy_github_linux_qemu: + name: "Deploy Github: Linux" + runs-on: ubuntu-latest + strategy: + matrix: + include: + # https://github.com/dart-lang/sdk/pull/48665 + # - arch: arm + # platform: linux/arm/v7 + - arch: arm64 + platform: linux/arm64 + needs: [deploy_github_linux] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: dart-lang/setup-dart@v1 + - run: dart pub get + - run: dart run grinder protobuf + - uses: docker/setup-qemu-action@v1 + - name: Deploy + run: | + docker run --rm \ + --env "GH_BEARER_TOKEN=$GH_BEARER_TOKEN" \ + --platform ${{ matrix.platform }} \ + --volume "$PWD:$PWD" \ + --workdir "$PWD" \ + docker.io/library/dart:latest \ + /bin/sh -c "dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_macos: @@ -134,9 +167,9 @@ jobs: with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 - run: dart pub get - - run: dart pub run grinder protobuf + - run: dart run grinder protobuf - name: Deploy - run: dart pub run grinder pkg-github-macos + run: dart run grinder pkg-github-macos env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_windows: @@ -151,15 +184,15 @@ jobs: with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 - run: dart pub get - - run: dart pub run grinder protobuf + - run: dart run grinder protobuf - name: Deploy - run: dart pub run grinder pkg-github-windows + run: dart run grinder pkg-github-windows env: {GH_BEARER_TOKEN: "${{ github.token }}"} release_embedded_host: name: "Release Embedded Host" runs-on: ubuntu-latest - needs: [deploy_github_linux, deploy_github_macos, deploy_github_windows] + needs: [deploy_github_linux, deploy_github_linux_qemu, deploy_github_macos, deploy_github_windows] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" steps: diff --git a/pubspec.yaml b/pubspec.yaml index b3656d207..d895b8168 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: typed_data: ^1.1.0 dev_dependencies: - cli_pkg: ^1.4.0 + cli_pkg: ^2.1.0 grinder: ^0.9.0 protoc_plugin: ^20.0.0 test: ^1.0.0 @@ -31,4 +31,4 @@ dev_dependencies: pubspec_parse: ^1.0.0 pub_semver: ^2.0.0 sass_analysis: - git: {url: git://github.com/sass/dart-sass, path: analysis} + git: {url: https://github.com/sass/dart-sass.git, path: analysis} diff --git a/tool/grind.dart b/tool/grind.dart index c0930e8b0..e4a7290cb 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -51,7 +51,7 @@ dart pub run protoc_plugin %* } if (Platform.environment['UPDATE_SASS_PROTOCOL'] != 'false') { - await cloneOrPull("git://github.com/sass/embedded-protocol"); + await cloneOrPull("https://github.com/sass/embedded-protocol.git"); } await runAsync("protoc", From 6143a586f3263854099464a7a2ffca46f4e15259 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 30 Mar 2022 22:26:38 +0000 Subject: [PATCH 084/162] Update Dart Sass version and release --- CHANGELOG.md | 23 +++++++++++++++++++++++ pubspec.lock | 10 +++++----- pubspec.yaml | 4 ++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b20597e22..1ec672be0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## 1.49.10 + +* Quiet deps mode now silences compiler warnings in mixins and functions that + are defined in dependencies even if they're invoked from application + stylesheets. + +* In expanded mode, Sass will now emit colors using `rgb()`, `rbga()`, `hsl()`, + and `hsla()` function notation if they were defined using the corresponding + notation. As per our browser support policy, this change was only done once + 95% of browsers were confirmed to support this output format, and so is not + considered a breaking change. + + Note that this output format is intended for human readability and not for + interoperability with other tools. As always, Sass targets the CSS + specification, and any tool that consumes Sass's output should parse all + colors that are supported by the CSS spec. + +* Fix a bug in which a color written using the four- or eight-digit hex format + could be emitted as a hex color rather than a format with higher browser + compatibility. + +* Calculations are no longer simplified within supports declarations + ## 1.49.9 ### Embedded Sass diff --git a/pubspec.lock b/pubspec.lock index 1f3f677a8..e5bb9a7eb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -63,7 +63,7 @@ packages: name: cli_pkg url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "2.1.0" cli_repl: dependency: transitive description: @@ -315,14 +315,14 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.9" + version: "1.49.10" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "13099d497a6b6b6afd0b458e751eeab1661633ca" - url: "git://github.com/sass/dart-sass" + resolved-ref: "6652001f19710f96947ad02341d67e522a1739ac" + url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" sass_api: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.38" + version: "1.0.0-beta.39" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d895b8168..89657fb2e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.9 +version: 1.49.10 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.9 + sass: 1.49.10 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From d0e4e6ca18eec34291c9d35eb12fdf7442cc061d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 30 Mar 2022 17:45:17 -0700 Subject: [PATCH 085/162] Set id on all OutboundMessage with id field (#80) Co-authored-by: Natalie Weizenbaum --- lib/src/dispatcher.dart | 8 +++++++- pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/src/dispatcher.dart b/lib/src/dispatcher.dart index e215c779a..12fe4033b 100644 --- a/lib/src/dispatcher.dart +++ b/lib/src/dispatcher.dart @@ -227,11 +227,17 @@ class Dispatcher { case OutboundMessage_Message.importRequest: message.importRequest.id = id; break; + case OutboundMessage_Message.fileImportRequest: + message.fileImportRequest.id = id; + break; case OutboundMessage_Message.functionCallRequest: message.functionCallRequest.id = id; break; - default: + case OutboundMessage_Message.versionResponse: + message.versionResponse.id = id; break; + default: + throw ArgumentError("Unknown message type: ${message.toDebugString()}"); } } diff --git a/pubspec.yaml b/pubspec.yaml index 89657fb2e..9b53864eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.10 +version: 1.49.11-dev description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded From a5d370c50e1f616fd419f8f68203a7be1e968a63 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 1 Apr 2022 22:48:36 +0000 Subject: [PATCH 086/162] Update Dart Sass version and release --- CHANGELOG.md | 9 +++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ec672be0..7581b3d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.49.11 + +* Add support for 64-bit ARM releases on Linux. + +### Embedded Sass + +* The embedded compiler now correctly sets the `id` field for all + `OutboundMessage`s. + ## 1.49.10 * Quiet deps mode now silences compiler warnings in mixins and functions that diff --git a/pubspec.lock b/pubspec.lock index e5bb9a7eb..2ee121b40 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.10" + version: "1.49.11" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.39" + version: "1.0.0-beta.40" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9b53864eb..8e727532a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.11-dev +version: 1.49.11 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.10 + sass: 1.49.11 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 39500727d9b1d2ebdc497f6d717a9c124ba5960c Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 7 Apr 2022 02:31:35 +0000 Subject: [PATCH 087/162] Update Dart Sass version and release --- CHANGELOG.md | 19 +++++++++++++++++++ pubspec.lock | 6 +++--- pubspec.yaml | 4 ++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7581b3d73..446259fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## 1.50.0 + +* `@extend` now treats [`:where()`] the same as `:is()`. + +[`:where()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/:where + +### Command Line Interface + +* Closing the standard input stream will now cause the `--watch` command to stop + running. + +### Embedded Sass + +* Fix a bug where the JS embedded host crashed when invoking a legacy importer + after resolving a relative filesystem import. + +* Improve error messages when returning non-`Object` values from legacy + importers. + ## 1.49.11 * Add support for 64-bit ARM releases on Linux. diff --git a/pubspec.lock b/pubspec.lock index 2ee121b40..e14fc1cf6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -35,7 +35,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.49.11" + version: "1.50.0" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.40" + version: "1.0.0-beta.41" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8e727532a..8cff6e581 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.49.11 +version: 1.50.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.49.11 + sass: 1.50.0 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From f2053d7018ec061c0bebc52fa4e88a4dedc7a7af Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 8 Apr 2022 16:08:26 -0700 Subject: [PATCH 088/162] Run JS API tests for the Node embedded host (#84) Since this provides a substantial amount of the Node embedded implementation, it's sometimes necessary to test that updates continue to pass (or begin to pass) the JS API tests, as for example in #83. --- .github/workflows/ci.yml | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcf19348e..64b2e9c32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,6 +57,90 @@ jobs: - name: Run tests run: dart run test -r expanded + # The versions should be kept up-to-date with the latest LTS Node releases. + # They next need to be rotated October 2021. See + # https://github.com/nodejs/Release. + sass_spec: + name: 'JS API Tests | Node ${{ matrix.node_version }} | ${{ matrix.os }}' + runs-on: ${{ matrix.os }}-latest + + strategy: + fail-fast: false + matrix: + os: [ubuntu, windows, macos] + node_version: [16] + include: + # Include LTS versions on Ubuntu + - os: ubuntu + node_version: 14 + - os: ubuntu + node_version: 12 + + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + with: {sdk: stable} + - uses: actions/setup-node@v2 + with: {node-version: "${{ matrix.node_version }}"} + - uses: arduino/setup-protoc@v1 + with: + version: ${{ env.PROTOC_VERSION }} + repo-token: '${{ github.token }}' + + - name: Check out Dart Sass + uses: sass/clone-linked-repo@v1 + with: {repo: sass/dart-sass, default-ref: null} + + - name: Add Dart Sass to pubspec + run: | + if [[ -d build/dart-sass ]]; then + ( + echo "dependency_overrides:" + echo " sass: {path: build/dart-sass}" + echo " sass_api: {path: build/dart-sass/pkg/sass_api}" + ) >> pubspec.yaml + fi + shell: bash + + - name: Check out embedded Sass protocol + uses: sass/clone-linked-repo@v1 + with: {repo: sass/embedded-protocol, path: build/embedded-protocol} + + - name: Check out the embedded host + uses: sass/clone-linked-repo@v1 + with: {repo: sass/embedded-host-node} + + - name: Check out the JS API definition + uses: sass/clone-linked-repo@v1 + with: {repo: sass/sass, path: language} + + - name: "Embedded host: npm install" + run: npm install + working-directory: embedded-host-node + - name: "Embedded host: npm run init" + run: | + npm run init -- --protocol-path=../build/embedded-protocol --compiler-path=.. --api-path=../language + working-directory: embedded-host-node + + - name: Check out sass-spec + uses: sass/clone-linked-repo@v1 + with: {repo: sass/sass-spec} + + - name: Install sass-spec dependencies + run: npm install + working-directory: sass-spec + + - name: Compile embedded host + run: | + npm run compile + ln -s {`pwd`/,dist/}lib/src/vendor/dart-sass-embedded + shell: bash + working-directory: embedded-host-node + + - name: Run tests + run: npm run js-api-spec -- --sassPackage ../embedded-host-node --sassSassRepo ../language + working-directory: sass-spec + static_analysis: name: Static analysis runs-on: ubuntu-latest From 615f6ed70a60ab7f94afeb9e310757db0a58f794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Mon, 11 Apr 2022 17:09:20 -0700 Subject: [PATCH 089/162] Treat null importer as noOp if url is not a file: url (#83) --- bin/dart_sass_embedded.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 03be2dc68..5e425c582 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -71,7 +71,8 @@ void main(List args) { color: request.alertColor, logger: logger, importers: importers, - importer: _decodeImporter(dispatcher, request, input.importer), + importer: _decodeImporter(dispatcher, request, input.importer) ?? + (input.url.startsWith("file:") ? null : sass.Importer.noOp), functions: globalFunctions, syntax: syntaxToSyntax(input.syntax), style: style, From 85735c4b4b6ed4c4e1ddd521d0a58685e9ebd90e Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 19 Apr 2022 00:59:18 +0000 Subject: [PATCH 090/162] Update Dart Sass version and release --- CHANGELOG.md | 11 +++++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 446259fec..53e6dfaeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## 1.50.1 + +### Embedded Sass + +* The JS embedded host and the embedded compiler will now properly avoid + resolving imports relative to the current working directory unless `'.'` is + passed as a load path. + +* Fix a bug in the JS embedded host's implementation of the legacy JS API where + imports that began with `/` could crash on Windows. + ## 1.50.0 * `@extend` now treats [`:where()`] the same as `:is()`. diff --git a/pubspec.lock b/pubspec.lock index e14fc1cf6..fd632a38b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.50.0" + version: "1.50.1" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.41" + version: "1.0.0-beta.42" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8cff6e581..bdfe47fcc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.50.0 +version: 1.50.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.50.0 + sass: 1.50.1 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 8e907ab92df51fa720aff58a882d32f4678cf2d4 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 26 Apr 2022 02:32:43 +0000 Subject: [PATCH 091/162] Update Dart Sass version and release --- CHANGELOG.md | 9 +++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53e6dfaeb..b09de7e8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.51.0 + +* **Potentially breaking change**: Change the order of maps returned by + `map.deep-merge()` to match those returned by `map.merge()`. All keys that + appeared in the first map will now be listed first in the same order they + appeared in that map, followed by any new keys added from the second map. + +* Improve the string output of some AST nodes in error messages. + ## 1.50.1 ### Embedded Sass diff --git a/pubspec.lock b/pubspec.lock index fd632a38b..5611e9e68 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.50.1" + version: "1.51.0" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.42" + version: "1.0.0-beta.43" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bdfe47fcc..94bf569ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.50.1 +version: 1.51.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.50.1 + sass: 1.51.0 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 5917e5ef3ce436ea88262a3cdc0dc009e9193628 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 20 May 2022 22:15:29 +0000 Subject: [PATCH 092/162] Update Dart Sass version and release --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b09de7e8b..0821c016f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +## 1.52.1 + +### Command Line Interface + +* Fix a bug where `--watch` mode would close immediately in TTY mode. This was + caused by our change to close `--watch` when stdin was closed *outside of* TTY + mode, which has been reverted for now while we work on a fix. + +## 1.52.0 + +* Add support for arbitrary modifiers at the end of plain CSS imports, in + addition to the existing `supports()` and media queries. Sass now allows any + sequence of identifiers of functions after the URL of an import for forwards + compatibility with future additions to the CSS spec. + +* Fix an issue where source locations tracked through variable references could + potentially become incorrect. + +* Fix a bug where a loud comment in the source can break the source map when + embedding the sources, when using the command-line interface or the legacy JS + API. + +### JS API + +* `SassNumber.assertUnit()` and `SassNumber.assertNoUnits()` now correctly + return the number called on when it passes the assertion. + ## 1.51.0 * **Potentially breaking change**: Change the order of maps returned by diff --git a/pubspec.lock b/pubspec.lock index 5611e9e68..d73518c25 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.51.0" + version: "1.52.1" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.43" + version: "1.0.0-beta.46" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 94bf569ee..94c76b746 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.51.0 +version: 1.52.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.51.0 + sass: 1.52.1 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 3d442b402b27f6c6224f28ed08e13fc24bff36fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Tue, 31 May 2022 17:56:42 -0700 Subject: [PATCH 093/162] Run qemu with tmpfs (#89) --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64b2e9c32..3693f294d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,10 +233,12 @@ jobs: docker run --rm \ --env "GH_BEARER_TOKEN=$GH_BEARER_TOKEN" \ --platform ${{ matrix.platform }} \ - --volume "$PWD:$PWD" \ + --mount type=bind,source="$PWD",target="$PWD" \ + --mount type=tmpfs,destination=/root/.pub-cache \ + --mount type=tmpfs,destination=/tmp \ --workdir "$PWD" \ docker.io/library/dart:latest \ - /bin/sh -c "dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" + /bin/sh -c "cp -R . /tmp/workspace && cd /tmp/workspace && dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_macos: From 5a70b24c7029360d331f10f00af22d6988b8c188 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 3 Jun 2022 02:32:38 +0000 Subject: [PATCH 094/162] Update Dart Sass version and release --- CHANGELOG.md | 5 +++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0821c016f..f4d6dabb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.52.2 + +* Preserve location of trailing loud comments (`/* ... */`) instead of pushing + the comment to the next line. + ## 1.52.1 ### Command Line Interface diff --git a/pubspec.lock b/pubspec.lock index d73518c25..d822be1e0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.52.1" + version: "1.52.2" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.46" + version: "1.0.0-beta.47" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 94c76b746..e7dee60dc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.52.1 +version: 1.52.2 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.52.1 + sass: 1.52.2 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From a4545258cc6ad4523450f57a72ec258872f6baa7 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 9 Jun 2022 00:00:38 +0000 Subject: [PATCH 095/162] Update Dart Sass version and release --- CHANGELOG.md | 5 +++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4d6dabb6..0d59d043b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.52.3 + +* Fix crash when trailing loud comments (`/* ... */`) appear twice in a row + across two different imports which themselves imported the same file each. + ## 1.52.2 * Preserve location of trailing loud comments (`/* ... */`) instead of pushing diff --git a/pubspec.lock b/pubspec.lock index d822be1e0..945223556 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.52.2" + version: "1.52.3" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.47" + version: "1.0.0-beta.48" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e7dee60dc..3c0ca6521 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.52.2 +version: 1.52.3 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.52.2 + sass: 1.52.3 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From be23a74d7dd420d8ba2e3924f4b96098ddbba539 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 22 Jun 2022 19:37:08 +0000 Subject: [PATCH 096/162] Update Dart Sass version and release --- CHANGELOG.md | 14 ++++++++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d59d043b..da3a540a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 1.53.0 + +* Add support for calling `var()` with an empty second argument, such as + `var(--side, )`. + +### JS API + +* Fix a bug where `meta.load-css()` would sometimes resolve relative URLs + incorrectly when called from a mixin using the legacy JS API. + +### Embedded Sass + +* Respect npm's proxy settings when downloading the embedded Sass compiler. + ## 1.52.3 * Fix crash when trailing loud comments (`/* ... */`) appear twice in a row diff --git a/pubspec.lock b/pubspec.lock index 945223556..eff07adab 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.52.3" + version: "1.53.0" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0-beta.48" + version: "1.0.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3c0ca6521..acbcdc141 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.52.3 +version: 1.53.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.52.3 + sass: 1.53.0 sass_api: ^1.0.0-beta.5 source_span: ^1.1.0 stack_trace: ^1.6.0 From 112394326854e656495646907766408f5e45780b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Fri, 24 Jun 2022 15:22:49 -0700 Subject: [PATCH 097/162] Add charset option --- bin/dart_sass_embedded.dart | 6 ++++-- pubspec.yaml | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 5e425c582..0f762c157 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -79,7 +79,8 @@ void main(List args) { url: input.url.isEmpty ? null : input.url, quietDeps: request.quietDeps, verbose: request.verbose, - sourceMap: request.sourceMap); + sourceMap: request.sourceMap, + charset: request.charset); break; case InboundMessage_CompileRequest_Input.path: @@ -96,7 +97,8 @@ void main(List args) { style: style, quietDeps: request.quietDeps, verbose: request.verbose, - sourceMap: request.sourceMap); + sourceMap: request.sourceMap, + charset: request.charset); } on FileSystemException catch (error) { return OutboundMessage_CompileResponse() ..failure = (OutboundMessage_CompileResponse_CompileFailure() diff --git a/pubspec.yaml b/pubspec.yaml index acbcdc141..3b631434e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.53.0 +version: 1.54.0-dev description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,8 +14,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.53.0 - sass_api: ^1.0.0-beta.5 + sass: 1.54.0-dev + sass_api: ^1.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 50ade3023f2e3cec8ae231bfff2987925fd90353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Fri, 1 Jul 2022 16:34:20 -0700 Subject: [PATCH 098/162] Fix linked repo clone path --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3693f294d..9ab8b2a49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,10 @@ jobs: - name: Check out Dart Sass uses: sass/clone-linked-repo@v1 - with: {repo: sass/dart-sass, default-ref: null} + with: + repo: sass/dart-sass + path: build/dart-sass + default-ref: null - name: Add Dart Sass to pubspec run: | From fa972c9e0302f2fe18afa289dece69f7c0ace03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Fri, 1 Jul 2022 17:29:55 -0700 Subject: [PATCH 099/162] Use mv instead of ln -s --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ab8b2a49..e3a0b0f88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,7 +136,7 @@ jobs: - name: Compile embedded host run: | npm run compile - ln -s {`pwd`/,dist/}lib/src/vendor/dart-sass-embedded + mv {`pwd`/,dist/}lib/src/vendor/dart-sass-embedded shell: bash working-directory: embedded-host-node From 6f5e1f17eb9301d93bc2be19acdc16836ef9ba77 Mon Sep 17 00:00:00 2001 From: Goodwine <2022649+Goodwine@users.noreply.github.com> Date: Mon, 11 Jul 2022 23:10:48 -0700 Subject: [PATCH 100/162] Fix CI when declaring -dev dependencies (#92) * Clone dart-sass from github when using "-dev" deps Co-authored-by: Natalie Weizenbaum --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3a0b0f88..30f314474 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,14 +28,22 @@ jobs: - uses: dart-lang/setup-dart@v1 with: {sdk: "${{ matrix.dart_channel }}"} - - name: Check out Dart Sass + - name: Check out Dart Sass only if linked in the PR description uses: sass/clone-linked-repo@v1 with: repo: sass/dart-sass path: build/dart-sass default-ref: null - - name: Add Dart Sass to pubspec + - name: Check out Dart Sass from main HEAD when using -dev dependency + run: | + if [[ ! -d build/dart-sass ]] && grep --quiet -E '\bsass:\s*.*-dev["'"'"']?$' pubspec.yaml; then + git clone https://github.com/sass/dart-sass.git \ + --depth 1 build/dart-sass + fi + shell: bash + + - name: Override dart-sass dependency only if repo was cloned a priori run: | if [[ -d build/dart-sass ]]; then ( @@ -87,14 +95,22 @@ jobs: version: ${{ env.PROTOC_VERSION }} repo-token: '${{ github.token }}' - - name: Check out Dart Sass + - name: Check out Dart Sass only if linked in the PR description uses: sass/clone-linked-repo@v1 with: repo: sass/dart-sass path: build/dart-sass default-ref: null - - name: Add Dart Sass to pubspec + - name: Check out Dart Sass from main HEAD when using -dev dependency + run: | + if [[ ! -d build/dart-sass ]] && grep --quiet -E '\bsass:\s*.*-dev["'"'"']?$' pubspec.yaml; then + git clone https://github.com/sass/dart-sass.git \ + --depth 1 build/dart-sass + fi + shell: bash + + - name: Override dart-sass dependency only if repo was cloned a priori run: | if [[ -d build/dart-sass ]]; then ( @@ -154,14 +170,22 @@ jobs: with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 - - name: Check out Dart Sass + - name: Check out Dart Sass only if linked in the PR description uses: sass/clone-linked-repo@v1 with: repo: sass/dart-sass path: build/dart-sass default-ref: null - - name: Add Dart Sass to pubspec + - name: Check out Dart Sass from main HEAD when using -dev dependency + run: | + if [[ ! -d build/dart-sass ]] && grep --quiet -E '\bsass:\s*.*-dev["'"'"']?$' pubspec.yaml; then + git clone https://github.com/sass/dart-sass.git \ + --depth 1 build/dart-sass + fi + shell: bash + + - name: Override dart-sass dependency only if repo was cloned a priori run: | if [[ -d build/dart-sass ]]; then ( From 95caed45335e118753540cbb6b6be61f422e4c77 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Jul 2022 14:58:14 -0700 Subject: [PATCH 101/162] Use the latest version of sass_api --- pubspec.lock | 4 ++-- pubspec.yaml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index eff07adab..646f32d62 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.53.0" + version: "1.54.0" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "2.0.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3b631434e..d15e2a287 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.0-dev +version: 1.54.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,8 +14,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.0-dev - sass_api: ^1.0.0 + sass: 1.54.0 + sass_api: ^2.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 1894fc686825d34a8868c8e78afaf70e5e9ce3ef Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Jul 2022 15:14:32 -0700 Subject: [PATCH 102/162] Try building native ARM64 executables for Mac OS --- .github/workflows/ci.yml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30f314474..b3cc4d69a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -268,8 +268,8 @@ jobs: /bin/sh -c "cp -R . /tmp/workspace && cd /tmp/workspace && dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" env: {GH_BEARER_TOKEN: "${{ github.token }}"} - deploy_github_macos: - name: "Deploy Github: Mac OS" + deploy_github_macos_x64: + name: "Deploy Github: Mac OS (x64)" runs-on: macos-latest needs: [deploy_github_linux] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" @@ -282,7 +282,24 @@ jobs: - run: dart pub get - run: dart run grinder protobuf - name: Deploy - run: dart run grinder pkg-github-macos + run: dart run grinder pkg-github-macos-x64 + env: {GH_BEARER_TOKEN: "${{ github.token }}"} + + deploy_github_macos_arm64: + name: "Deploy Github: Mac OS (arm64)" + runs-on: self-hosted + needs: [deploy_github_linux] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + - uses: arduino/setup-protoc@v1 + with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: dart-lang/setup-dart@v1 + - run: dart pub get + - run: dart run grinder protobuf + - name: Deploy + run: dart run grinder pkg-github-macos-arm64 env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_windows: From 4c98e0d4c63c632a19653d02994bcecafd82d9ea Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Jul 2022 15:32:23 -0700 Subject: [PATCH 103/162] Consolidate repeated deploy jobs into a matrix --- .github/workflows/ci.yml | 57 +++++++++++----------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3cc4d69a..bc6c13f49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -217,7 +217,7 @@ jobs: - run: git diff --exit-code deploy_github_linux: - name: "Deploy Github: Linux" + name: "Deploy Github: linux-ia32, linux-x64" runs-on: ubuntu-latest needs: [dart_tests, static_analysis] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" @@ -234,7 +234,7 @@ jobs: env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github_linux_qemu: - name: "Deploy Github: Linux" + name: "Deploy Github: linux-${{ matrix.arch }}" runs-on: ubuntu-latest strategy: matrix: @@ -268,45 +268,20 @@ jobs: /bin/sh -c "cp -R . /tmp/workspace && cd /tmp/workspace && dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" env: {GH_BEARER_TOKEN: "${{ github.token }}"} - deploy_github_macos_x64: - name: "Deploy Github: Mac OS (x64)" - runs-on: macos-latest - needs: [deploy_github_linux] - if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" - - steps: - - uses: actions/checkout@v2 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: dart-lang/setup-dart@v1 - - run: dart pub get - - run: dart run grinder protobuf - - name: Deploy - run: dart run grinder pkg-github-macos-x64 - env: {GH_BEARER_TOKEN: "${{ github.token }}"} - - deploy_github_macos_arm64: - name: "Deploy Github: Mac OS (arm64)" - runs-on: self-hosted - needs: [deploy_github_linux] - if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" - - steps: - - uses: actions/checkout@v2 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: dart-lang/setup-dart@v1 - - run: dart pub get - - run: dart run grinder protobuf - - name: Deploy - run: dart run grinder pkg-github-macos-arm64 - env: {GH_BEARER_TOKEN: "${{ github.token }}"} - - deploy_github_windows: - name: "Deploy Github: Windows" - runs-on: windows-latest + deploy_github: + name: "Deploy Github: ${{ matrix.platform }})" + runs-on: ${{ matrix.runner }} needs: [deploy_github_linux] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + strategy: + matrix: + include: + - runner: macos-latest + platform: macos-x64 + - runner: self-hosted + platform: macos-arm64 + - runner: windows-latest + platform: windows steps: - uses: actions/checkout@v2 @@ -316,13 +291,13 @@ jobs: - run: dart pub get - run: dart run grinder protobuf - name: Deploy - run: dart run grinder pkg-github-windows + run: dart run grinder pkg-github-${{ matrix.platform }} env: {GH_BEARER_TOKEN: "${{ github.token }}"} release_embedded_host: name: "Release Embedded Host" runs-on: ubuntu-latest - needs: [deploy_github_linux, deploy_github_linux_qemu, deploy_github_macos, deploy_github_windows] + needs: [deploy_github_linux, deploy_github_linux_qemu, deploy_github] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" steps: From 3f1ecebcef080b81c3e48fc7e08b7ac9aacab232 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Jul 2022 16:05:02 -0700 Subject: [PATCH 104/162] Block releasing on successfully running _all_ tests (#94) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc6c13f49..e5488458f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -219,7 +219,7 @@ jobs: deploy_github_linux: name: "Deploy Github: linux-ia32, linux-x64" runs-on: ubuntu-latest - needs: [dart_tests, static_analysis] + needs: [dart_tests, sass_spec, static_analysis, format] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" steps: From 59ba6eaa5a7718af81022139ac0687caac526bc4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 22 Jul 2022 16:07:35 -0700 Subject: [PATCH 105/162] Add the changelog entry for 1.54.0 (#95) --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da3a540a9..734f2cbd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,40 @@ +## 1.54.0 + +* Deprecate selectors with leading or trailing combinators, or with multiple + combinators in a row. If they're included in style rules after nesting is + resolved, Sass will now produce a deprecation warning and, in most cases, omit + the selector. Leading and trailing combinators can still be freely used for + nesting purposes. + + See https://sass-lang.com/d/bogus-combinators for more details. + +* Add partial support for new media query syntax from Media Queries Level 4. The + only exception are logical operations nested within parentheses, as these were + previously interpreted differently as SassScript expressions. + + A parenthesized media condition that begins with `not` or an opening + parenthesis now produces a deprecation warning. In a future release, these + will be interpreted as plain CSS instead. + +* Deprecate passing non-`deg` units to `color.hwb()`'s `$hue` argument. + +* Fix a number of bugs when determining whether selectors with pseudo-elements + are superselectors. + +* Treat `*` as a superselector of all selectors. + +### Dart API + +* Add a top-level `fakeFromImport()` function for testing custom importers + that use `AsyncImporter.fromImport`. + +### JS API + +* Add a `charset` option that controls whether or not Sass emits a + `@charset`/BOM for non-ASCII stylesheets. + +* Fix Sass npm package types for TS 4.7+ Node16 and NodeNext module resolution. + ## 1.53.0 * Add support for calling `var()` with an empty second argument, such as From d1ab9e69140778a5ec993140853c959bfc7b2685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Fri, 22 Jul 2022 16:26:55 -0700 Subject: [PATCH 106/162] Revert "Run qemu with tmpfs (#89)" (#96) This reverts commit 3d442b402b27f6c6224f28ed08e13fc24bff36fa. --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5488458f..4374c287d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -260,12 +260,10 @@ jobs: docker run --rm \ --env "GH_BEARER_TOKEN=$GH_BEARER_TOKEN" \ --platform ${{ matrix.platform }} \ - --mount type=bind,source="$PWD",target="$PWD" \ - --mount type=tmpfs,destination=/root/.pub-cache \ - --mount type=tmpfs,destination=/tmp \ + --volume "$PWD:$PWD" \ --workdir "$PWD" \ docker.io/library/dart:latest \ - /bin/sh -c "cp -R . /tmp/workspace && cd /tmp/workspace && dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" + /bin/sh -c "dart pub get && dart run grinder pkg-github-linux-${{ matrix.arch }}" env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github: From 3d2c92750600adc52027521dd136ba013045aa82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Tue, 2 Aug 2022 16:36:47 -0700 Subject: [PATCH 107/162] Re-use protobuf artifact instead of building on macos arm64 (#101) Co-authored-by: Natalie Weizenbaum --- .github/workflows/ci.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4374c287d..91f27b7e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -229,6 +229,15 @@ jobs: - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart run grinder protobuf + # We need to upload the compiled protobuf rather than recompiling it on + # other platforms because arduino/setup-protoc currently) requires Node 12 + # which doesn't support ARM. + - uses: actions/upload-artifact@v3 + with: + name: embedded-protocol + path: | + build/embedded-protocol + lib/src/embedded_sass.*.dart - name: Deploy run: dart run grinder pkg-github-release pkg-github-linux-ia32 pkg-github-linux-x64 env: {GH_BEARER_TOKEN: "${{ github.token }}"} @@ -249,11 +258,9 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - - uses: dart-lang/setup-dart@v1 - - run: dart pub get - - run: dart run grinder protobuf + - uses: actions/download-artifact@v3 + with: + name: embedded-protocol - uses: docker/setup-qemu-action@v1 - name: Deploy run: | @@ -283,11 +290,11 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: actions/download-artifact@v3 + with: + name: embedded-protocol - uses: dart-lang/setup-dart@v1 - run: dart pub get - - run: dart run grinder protobuf - name: Deploy run: dart run grinder pkg-github-${{ matrix.platform }} env: {GH_BEARER_TOKEN: "${{ github.token }}"} From cf1cc4eb9e1c22a88604d5ac136aac81b5842e04 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 2 Aug 2022 23:52:36 +0000 Subject: [PATCH 108/162] Update Dart Sass version and release --- CHANGELOG.md | 6 ++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 734f2cbd2..cd7b27449 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.54.1 + +* When unifying selectors for `@extend` and `selector.unify()`, ensure that + `:root`, `:scope`, `:host`, and `:host-context` only appear at the beginning + of complex selectors. + ## 1.54.0 * Deprecate selectors with leading or trailing combinators, or with multiple diff --git a/pubspec.lock b/pubspec.lock index 646f32d62..492888adf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.0" + version: "1.54.1" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d15e2a287..1edaf599b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.0 +version: 1.54.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.0 + sass: 1.54.1 sass_api: ^2.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From 24575f2cbb82cbc62b94b2780ce7d9d0f6c7de9e Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 2 Aug 2022 18:18:12 -0700 Subject: [PATCH 109/162] Update GitHub actions dependency versions (#99) --- .github/workflows/ci.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91f27b7e0..67c9fcca4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: include: [{os: ubuntu-latest, dart_channel: dev}] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 @@ -85,11 +85,9 @@ jobs: node_version: 12 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: dart-lang/setup-dart@v1 with: {sdk: stable} - - uses: actions/setup-node@v2 - with: {node-version: "${{ matrix.node_version }}"} - uses: arduino/setup-protoc@v1 with: version: ${{ env.PROTOC_VERSION }} @@ -165,7 +163,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 @@ -211,7 +209,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: dart-lang/setup-dart@v1 - run: dart format --fix . - run: git diff --exit-code @@ -223,7 +221,7 @@ jobs: if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 @@ -257,11 +255,11 @@ jobs: if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/download-artifact@v3 with: name: embedded-protocol - - uses: docker/setup-qemu-action@v1 + - uses: docker/setup-qemu-action@v2 - name: Deploy run: | docker run --rm \ @@ -289,7 +287,7 @@ jobs: platform: windows steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/download-artifact@v3 with: name: embedded-protocol @@ -306,7 +304,7 @@ jobs: if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: repository: sass/embedded-host-node token: ${{ secrets.GH_TOKEN }} From 82a8b8f2e7e283ca403e9a98832ae10a69c7bf71 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 2 Aug 2022 18:18:16 -0700 Subject: [PATCH 110/162] Remove a leftover parenthesis (#98) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67c9fcca4..f1c1e9f99 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -272,7 +272,7 @@ jobs: env: {GH_BEARER_TOKEN: "${{ github.token }}"} deploy_github: - name: "Deploy Github: ${{ matrix.platform }})" + name: "Deploy Github: ${{ matrix.platform }}" runs-on: ${{ matrix.runner }} needs: [deploy_github_linux] if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" From 9bc9f49e2d8252ac8956bd10f05eb93976d86af5 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 3 Aug 2022 16:30:03 -0700 Subject: [PATCH 111/162] Specify architectures when installing Dart (#103) Workaround for dart-lang/setup-dart#59 --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1c1e9f99..5ba9a1167 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,10 +281,13 @@ jobs: include: - runner: macos-latest platform: macos-x64 + architecture: x64 - runner: self-hosted platform: macos-arm64 + architecture: arm64 - runner: windows-latest platform: windows + architecture: x64 steps: - uses: actions/checkout@v3 @@ -292,6 +295,9 @@ jobs: with: name: embedded-protocol - uses: dart-lang/setup-dart@v1 + # Workaround for dart-lang/setup-dart#59 + with: + architecture: ${{ matrix.architecture }} - run: dart pub get - name: Deploy run: dart run grinder pkg-github-${{ matrix.platform }} From a20673acb16b16de95fdcc2e3f95125b7f3281b0 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 3 Aug 2022 23:52:13 +0000 Subject: [PATCH 112/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7b27449..acb32aeca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.54.2 + +* No user-visible changes. + ## 1.54.1 * When unifying selectors for `@extend` and `selector.unify()`, ensure that diff --git a/pubspec.lock b/pubspec.lock index 492888adf..fd73c31f4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.1" + version: "1.54.2" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1edaf599b..4de4ed915 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.1 +version: 1.54.2 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.1 + sass: 1.54.2 sass_api: ^2.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From fb12d87226c1fb74e6bd14ca8f02dd61ad22b575 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 4 Aug 2022 20:48:23 +0000 Subject: [PATCH 113/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acb32aeca..fad8863bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.54.3 + +* Release a native ARM64 executable for Mac OS. + ## 1.54.2 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index fd73c31f4..6d160ac2f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.2" + version: "1.54.3" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4de4ed915..3eb7b7ca5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.2 +version: 1.54.3 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.2 + sass: 1.54.3 sass_api: ^2.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From 6faac1f6f08de08874301ca5d8e76d05d86f1b06 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 10 Aug 2022 00:58:13 +0000 Subject: [PATCH 114/162] Update Dart Sass version and release --- CHANGELOG.md | 5 +++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fad8863bc..4b10c2333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.54.4 + +* Improve error messages when passing incorrect units that are also + out-of-bounds to various color functions. + ## 1.54.3 * Release a native ARM64 executable for Mac OS. diff --git a/pubspec.lock b/pubspec.lock index 6d160ac2f..c0e8e211d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.3" + version: "1.54.4" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3eb7b7ca5..46ca6f1b8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.3 +version: 1.54.4 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.3 + sass: 1.54.4 sass_api: ^2.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From eaceb48e83272f5743179f468233d2c2fecda8a0 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 19 Aug 2022 15:30:17 -0700 Subject: [PATCH 115/162] Update optional dependency versions in embedded-host-node (#107) Co-authored-by: Goodwine <2022649+Goodwine@users.noreply.github.com> --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ba9a1167..d8f8eeb38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -324,7 +324,8 @@ jobs: cat package.json | jq --arg version ${{ steps.version.outputs.version }} ' .version |= $version | - ."compiler-version" |= $version + ."compiler-version" |= $version | + .optionalDependencies = (.optionalDependencies | .[] |= $version) ' > package.json.tmp && mv package.json.tmp package.json curl https://raw.githubusercontent.com/sass/dart-sass/${{ steps.version.outputs.version }}/CHANGELOG.md > CHANGELOG.md From b7d92dcf0d60f71125a4ecbbf9e1b8369cbf7a44 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 19 Aug 2022 16:12:33 -0700 Subject: [PATCH 116/162] Release 1.54.5 (#108) --- CHANGELOG.md | 25 ++++++++++++++++++++++++- pubspec.lock | 8 ++++---- pubspec.yaml | 6 +++--- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b10c2333..2535b049f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## 1.54.5 + +* Properly consider `a ~ c` to be a superselector of `a ~ b ~ c` and `a + b + + c`. + +* Properly consider `b > c` to be a superselector of `a > b > c`, and similarly + for other combinators. + +* Properly calculate specificity for selector pseudoclasses. + +* Deprecate use of `random()` when `$limit` has units to make it explicit that + `random()` currently ignores units. A future version will no longer ignore + units. + +* Don't throw an error when the same module is `@forward`ed multiple times + through a configured module. + +### Embedded Sass + +* Rather than downloading the embedded compiler for the local platform on + install, the `sass-embedded` npm package now declares optional dependencies on + platform-specific embedded compiler packages. + ## 1.54.4 * Improve error messages when passing incorrect units that are also @@ -30,7 +53,7 @@ * Add partial support for new media query syntax from Media Queries Level 4. The only exception are logical operations nested within parentheses, as these were previously interpreted differently as SassScript expressions. - + A parenthesized media condition that begins with `not` or an opening parenthesis now produces a deprecation warning. In a future release, these will be interpreted as plain CSS instead. diff --git a/pubspec.lock b/pubspec.lock index c0e8e211d..9e65db905 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -84,7 +84,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" convert: dependency: transitive description: @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.4" + version: "1.54.5" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "3.0.0" shelf: dependency: transitive description: @@ -508,4 +508,4 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=2.17.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 46ca6f1b8..cf9985b54 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.4 +version: 1.54.5 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,8 +14,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.4 - sass_api: ^2.0.0 + sass: 1.54.5 + sass_api: ^3.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 5202161bf85abb580faa23bb02d07ac8d90cefdc Mon Sep 17 00:00:00 2001 From: Ahab Date: Tue, 30 Aug 2022 04:32:55 +0800 Subject: [PATCH 117/162] fix: update optional dependencies version in CI (#109) Co-authored-by: Natalie Weizenbaum --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8f8eeb38..c6cc81892 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -321,6 +321,16 @@ jobs: - name: Update version run: | + # Update binary package versions + for dir in $(ls npm); do + cat "npm/$dir/package.json" | + jq --arg version ${{ steps.version.outputs.version }} ' + .version |= $version + ' > package.json.tmp && + mv package.json.tmp ""npm/$dir/package.json" + done + + # Update main package version and dependencies on binary packages cat package.json | jq --arg version ${{ steps.version.outputs.version }} ' .version |= $version | From 5821df1c2ddee29ab8e79664698b445d35a62b7b Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Mon, 29 Aug 2022 23:27:48 +0000 Subject: [PATCH 118/162] Update Dart Sass version and release --- CHANGELOG.md | 6 ++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2535b049f..42e01c3d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.54.6 + +* Fix a bug where a `@media` query could be incorrectly omitted from a + stylesheet if it had multiple levels of nested `@media` queries within it + *and* the inner queries were mergeable but the outer query was not. + ## 1.54.5 * Properly consider `a ~ c` to be a superselector of `a ~ b ~ c` and `a + b + diff --git a/pubspec.lock b/pubspec.lock index 9e65db905..39c9b2b93 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.5" + version: "1.54.6" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cf9985b54..0d00ef3b2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.5 +version: 1.54.6 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.5 + sass: 1.54.6 sass_api: ^3.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From bec175e835b2a4c40998a323a24dc7d1cc3c1780 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 30 Aug 2022 15:24:56 -0700 Subject: [PATCH 119/162] Remove an extra quote in the deploy script (#110) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6cc81892..aa2389a47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -327,7 +327,7 @@ jobs: jq --arg version ${{ steps.version.outputs.version }} ' .version |= $version ' > package.json.tmp && - mv package.json.tmp ""npm/$dir/package.json" + mv package.json.tmp "npm/$dir/package.json" done # Update main package version and dependencies on binary packages From 7019efcbbefd71d8e4d4feb579633d67af259822 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Tue, 30 Aug 2022 16:46:34 -0700 Subject: [PATCH 120/162] Release 32-bit ARM on Linux (#88) --- .github/workflows/ci.yml | 5 +- pubspec.lock | 105 ++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa2389a47..e488eb9ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -246,9 +246,8 @@ jobs: strategy: matrix: include: - # https://github.com/dart-lang/sdk/pull/48665 - # - arch: arm - # platform: linux/arm/v7 + - arch: arm + platform: linux/arm/v7 - arch: arm64 platform: linux/arm64 needs: [deploy_github_linux] diff --git a/pubspec.lock b/pubspec.lock index 39c9b2b93..c7ea449cd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,28 +7,28 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "22.0.0" + version: "46.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.7.2" + version: "4.6.0" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.8" + version: "3.3.1" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" async: dependency: "direct main" description: @@ -63,7 +63,7 @@ packages: name: cli_pkg url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.4" cli_repl: dependency: transitive description: @@ -91,84 +91,84 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" coverage: dependency: transitive description: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.5.0" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "1.3.14" + version: "2.2.3" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.2" + version: "6.1.4" fixnum: dependency: transitive description: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" frontend_server_client: dependency: transitive description: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "3.0.0" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" grinder: dependency: "direct dev" description: name: grinder url: "https://pub.dartlang.org" source: hosted - version: "0.9.0" + version: "0.9.2" http: dependency: transitive description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.4" + version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.2.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" io: dependency: transitive description: @@ -182,14 +182,14 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: transitive description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.6.0" lints: dependency: transitive description: @@ -210,21 +210,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" meta: dependency: "direct main" description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" mime: dependency: transitive description: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" node_interop: dependency: transitive description: @@ -245,70 +245,63 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" path: dependency: "direct main" description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" + version: "1.8.2" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "5.0.0" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.5.0" + version: "1.5.1" protobuf: dependency: "direct main" description: name: protobuf url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" protoc_plugin: dependency: "direct dev" description: name: protoc_plugin url: "https://pub.dartlang.org" source: hosted - version: "20.0.0" + version: "20.0.1" pub_semver: dependency: "direct dev" description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" pubspec_parse: dependency: "direct dev" description: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" quiver: dependency: transitive description: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "3.0.1+1" + version: "3.1.0" sass: dependency: "direct main" description: @@ -321,7 +314,7 @@ packages: description: path: analysis ref: HEAD - resolved-ref: "6652001f19710f96947ad02341d67e522a1739ac" + resolved-ref: "016ab24ebd69d83547e545a1eaf160d05b21a98a" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -338,28 +331,28 @@ packages: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.2" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" shelf_static: dependency: transitive description: name: shelf_static url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" source_map_stack_trace: dependency: transitive description: @@ -380,7 +373,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.1" stack_trace: dependency: "direct main" description: @@ -408,35 +401,35 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test: dependency: "direct dev" description: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.18.1" + version: "1.21.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.5" + version: "0.4.13" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.4" + version: "0.4.17" test_descriptor: dependency: "direct dev" description: @@ -464,14 +457,14 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" vm_service: dependency: transitive description: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "7.5.0" + version: "9.3.0" watcher: dependency: transitive description: @@ -485,27 +478,27 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" xml: dependency: transitive description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.3.1" + version: "5.4.1" yaml: dependency: "direct dev" description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0-146.0.dev <3.0.0" From cecb1a97114375d7513892c2f560c306aae47a59 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 31 Aug 2022 00:03:14 +0000 Subject: [PATCH 121/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e01c3d0..d4bd9d421 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.54.7 + +* Add support for 32-bit ARM releases on Linux. + ## 1.54.6 * Fix a bug where a `@media` query could be incorrectly omitted from a diff --git a/pubspec.lock b/pubspec.lock index c7ea449cd..8b8b589d8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -308,7 +308,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.6" + version: "1.54.7" sass_analysis: dependency: "direct dev" description: @@ -324,7 +324,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0d00ef3b2..bc4b273c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.6 +version: 1.54.7 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.6 + sass: 1.54.7 sass_api: ^3.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From dbc015b54ad33b7ff0f0fb48c76475888fb8809c Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 31 Aug 2022 21:57:05 +0000 Subject: [PATCH 122/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4bd9d421..14900de80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.54.8 + +* No user-visible changes. + ## 1.54.7 * Add support for 32-bit ARM releases on Linux. diff --git a/pubspec.lock b/pubspec.lock index 8b8b589d8..9e3db29f2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -308,7 +308,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.7" + version: "1.54.8" sass_analysis: dependency: "direct dev" description: @@ -324,7 +324,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.0.3" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bc4b273c2..19679a1ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.7 +version: 1.54.8 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.7 + sass: 1.54.8 sass_api: ^3.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From 8056d55f2ce239e55038ff47e1cdef30c7e7fe58 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 7 Sep 2022 21:37:26 +0000 Subject: [PATCH 123/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14900de80..566d20f85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.54.9 + +* Fix an incorrect span in certain `@media` query deprecation warnings. + ## 1.54.8 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index 9e3db29f2..029da8ad0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -308,7 +308,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.8" + version: "1.54.9" sass_analysis: dependency: "direct dev" description: @@ -324,7 +324,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "3.0.3" + version: "3.0.4" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 19679a1ce..a204a5b5c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.8 +version: 1.54.9 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.8 + sass: 1.54.9 sass_api: ^3.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From dd4db56fb86e6d97312e064e509e5362329642e0 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 21 Sep 2022 16:07:17 -0700 Subject: [PATCH 124/162] Update dependencies and release (#113) --- pubspec.lock | 38 +++++++++++++++++++------------------- pubspec.yaml | 7 ++++--- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 029da8ad0..b225c54d1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "46.0.0" + version: "48.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.6.0" + version: "5.0.0" archive: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: cli_repl url: "https://pub.dartlang.org" source: hosted - version: "0.2.2" + version: "0.2.3" cli_util: dependency: transitive description: @@ -98,7 +98,7 @@ packages: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "1.5.0" + version: "1.6.1" crypto: dependency: transitive description: @@ -112,7 +112,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.3" + version: "2.2.4" file: dependency: transitive description: @@ -189,14 +189,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.6.0" + version: "4.7.0" lints: dependency: transitive description: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" logging: dependency: transitive description: @@ -308,13 +308,13 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.54.9" + version: "1.55.0" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "016ab24ebd69d83547e545a1eaf160d05b21a98a" + resolved-ref: a65e504b484eeacfff5219a24ad4b89e5ee1f87f url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -324,14 +324,14 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "3.0.4" + version: "4.0.0" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.4.0" shelf_packages_handler: dependency: transitive description: @@ -387,7 +387,7 @@ packages: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" stream_transform: dependency: transitive description: @@ -403,7 +403,7 @@ packages: source: hosted version: "1.1.1" term_glyph: - dependency: transitive + dependency: "direct main" description: name: term_glyph url: "https://pub.dartlang.org" @@ -415,21 +415,21 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.21.5" + version: "1.21.6" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.13" + version: "0.4.14" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.17" + version: "0.4.18" test_descriptor: dependency: "direct dev" description: @@ -464,7 +464,7 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "9.3.0" + version: "9.4.0" watcher: dependency: transitive description: @@ -485,7 +485,7 @@ packages: name: webkit_inspection_protocol url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" xml: dependency: transitive description: @@ -501,4 +501,4 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0-146.0.dev <3.0.0" + dart: ">=2.18.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index a204a5b5c..1ab175908 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.54.9 +version: 1.55.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,11 +14,12 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.54.9 - sass_api: ^3.0.0 + sass: 1.55.0 + sass_api: ^4.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" + term_glyph: ^1.0.0 typed_data: ^1.1.0 dev_dependencies: From 905fe50a491fe13fe10dcb2e7ad3e0a81df6a6ec Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 22 Sep 2022 15:34:56 -0700 Subject: [PATCH 125/162] Add CHANGELOG entry for 1.55.0 (#114) --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 566d20f85..f70edd917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,45 @@ +## 1.55.0 + +* **Potentially breaking bug fix:** Sass numbers are now universally stored as + 64-bit floating-point numbers, rather than sometimes being stored as integers. + This will generally make arithmetic with very large numbers more reliable and + more consistent across platforms, but it does mean that numbers between nine + quadrillion and nine quintillion will no longer be represented with full + accuracy when compiling Sass on the Dart VM. + +* **Potentially breaking bug fix:** Sass equality is now properly [transitive]. + Two numbers are now considered equal (after doing unit conversions) if they + round to the same `1e-11`th. Previously, numbers were considered equal if they + were within `1e-11` of one another, which led to some circumstances where `$a + == $b` and `$b == $c` but `$a != $b`. + +[transitive]: https://en.wikipedia.org/wiki/Transitive_property + +* **Potentially breaking bug fix:** Various functions in `sass:math` no longer + treat floating-point numbers that are very close (but not identical) to + integers as integers. Instead, these functions now follow the floating-point + specification exactly. For example, `math.pow(0.000000000001, -1)` now returns + `1000000000000` instead of `Infinity`. + +* Emit a deprecation warning for `$a -$b` and `$a +$b`, since these look like + they could be unary operations but they're actually parsed as binary + operations. Either explicitly write `$a - $b` or `$a (-$b)`. See + https://sass-lang.com/d/strict-unary for more details. + +### Dart API + +* Add an optional `argumentName` parameter to `SassScriptException()` to make it + easier to throw exceptions associated with particular argument names. + +* Most APIs that previously returned `num` now return `double`. All APIs + continue to _accept_ `num`, although in Dart 2.0.0 these APIs will be changed + to accept only `double`. + +### JS API + +* Fix a bug in which certain warning spans would not have their properties + accessible by the JS API. + ## 1.54.9 * Fix an incorrect span in certain `@media` query deprecation warnings. From 522dac95a4071df96df606c9756a7f0c115f8cae Mon Sep 17 00:00:00 2001 From: cmahnke Date: Thu, 13 Oct 2022 03:27:47 +0200 Subject: [PATCH 126/162] Update README.md (#116) Changed the name of the executable to the name of the file found in release archives. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e534c0fcb..9fe89f7b0 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ and importers. ### Usage -- `dart_sass_embedded` starts the compiler and listens on stdin. -- `dart_sass_embedded --version` prints `versionResponse` with `id = 0` in JSON and exits. +- `dart-sass-embedded` starts the compiler and listens on stdin. +- `dart-sass-embedded --version` prints `versionResponse` with `id = 0` in JSON and exits. ### Releases From d52222c7b4e098bf5db20812111b966af8bff0ad Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 4 Nov 2022 00:19:21 +0000 Subject: [PATCH 127/162] Update Dart Sass version and release --- CHANGELOG.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f70edd917..4813a7e83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,71 @@ +## 1.56.0 + +* **Potentially breaking change:** To match the CSS spec, SassScript expressions + beginning with `not` or `(` are no longer supported at the beginning of + parenthesized sections of media queries. For example, + + ```scss + @media (width >= 500px) and (not (grid)) + ``` + + will now be emitted unchanged, instead of producing + + ```scss + @media (width >= 500px) and (false) + ``` + + See [the Sass website](https://sass-lang.com/d/media-logic) for details. + +* **Potentially breaking bug fix:** Angle units like `rad` or `turn` are now + properly converted to equivalent `deg` values for `hsl()`, `hsla()`, + `adjust-hue()`, `color.adjust()`, and `color.change()`. + + See [the Sass website](https://sass-lang.com/d/function-units#hue) for + details. + +* Fix indentation for selectors that span multiple lines in a `@media` query. + +* Emit a deprecation warning when passing `$alpha` values with units to + `color.adjust()` or `color.change()`. This will be an error in Dart Sass + 2.0.0. + + See [the Sass website](https://sass-lang.com/d/function-units#alpha) for + details. + +* Emit a deprecation warning when passing a `$weight` value with no units or + with units other than `%` to `color.mix()`. This will be an error in Dart Sass + 2.0.0. + + See [the Sass website](https://sass-lang.com/d/function-units#weight) for + details. + +* Emit a deprecation warning when passing `$n` values with units to `list.nth()` + or `list.set-nth()`. This will be an error in Dart Sass 2.0.0. + + See [the Sass website](https://sass-lang.com/d/function-units#index) for + details. + +* Improve existing deprecation warnings to wrap `/`-as-division suggestions in + `calc()` expressions. + +* Properly mark the warning for passing numbers with units to `random()` as a + deprecation warning. + +* Fix a bug where `@extend` could behave unpredicatably when used along with + `meta.load-css()` and shared modules that contained no CSS themselves but + loaded CSS from other modules. + +### Dart API + +* Emit a deprecation warning when passing a `sassIndex` with units to + `Value.sassIndexToListIndex()`. This will be an error in Dart Sass 2.0.0. + +### JS API + +* Importer results now validate whether `contents` is actually a string type. + +* Importer result argument errors are now rendered correctly. + ## 1.55.0 * **Potentially breaking bug fix:** Sass numbers are now universally stored as diff --git a/pubspec.lock b/pubspec.lock index b225c54d1..cc0157a60 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -308,7 +308,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.55.0" + version: "1.56.0" sass_analysis: dependency: "direct dev" description: @@ -324,7 +324,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.1.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1ab175908..89a4d883c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.55.0 +version: 1.56.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.55.0 + sass: 1.56.0 sass_api: ^4.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From 14264bcf66d47e0cdb97b811e2819e8402a22bfd Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Wed, 9 Nov 2022 01:59:49 +0000 Subject: [PATCH 128/162] Update Dart Sass version and release --- CHANGELOG.md | 7 +++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4813a7e83..523a1a7cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.56.1 + +### Embedded Sass + +* Importer results now validate that `contents` is actually a string and whether + `sourceMapUrl` is an absolute URL. + ## 1.56.0 * **Potentially breaking change:** To match the CSS spec, SassScript expressions diff --git a/pubspec.lock b/pubspec.lock index cc0157a60..e1c827ea2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -308,7 +308,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.56.0" + version: "1.56.1" sass_analysis: dependency: "direct dev" description: @@ -324,7 +324,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.1.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 89a4d883c..03f2dd52a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.56.0 +version: 1.56.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.56.0 + sass: 1.56.1 sass_api: ^4.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From 46f42cb5275e68aea20767587952e828a502e8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 30 Nov 2022 18:50:24 -0800 Subject: [PATCH 129/162] Reformat pubspec.yaml (#121) --- pubspec.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 03f2dd52a..1f673f616 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,4 +32,6 @@ dev_dependencies: pubspec_parse: ^1.0.0 pub_semver: ^2.0.0 sass_analysis: - git: {url: https://github.com/sass/dart-sass.git, path: analysis} + git: + url: https://github.com/sass/dart-sass.git + path: analysis From bec6b3da6784d585d9bb5a52825a1983626a9731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 8 Dec 2022 12:07:54 -0800 Subject: [PATCH 130/162] Do not throw ProtocolErrorType.PARAMS for custom functions and importers (#118) --- bin/dart_sass_embedded.dart | 9 +--- lib/src/host_callable.dart | 21 ++-------- lib/src/importer/base.dart | 18 ++------ lib/src/importer/file.dart | 7 +--- lib/src/importer/host.dart | 6 +-- test/file_importer_test.dart | 34 +++++++++------ test/function_test.dart | 80 +++++++++++++----------------------- test/importer_test.dart | 28 +++++-------- 8 files changed, 75 insertions(+), 128 deletions(-) diff --git a/bin/dart_sass_embedded.dart b/bin/dart_sass_embedded.dart index 0f762c157..90b55248f 100644 --- a/bin/dart_sass_embedded.dart +++ b/bin/dart_sass_embedded.dart @@ -55,13 +55,8 @@ void main(List args) { _decodeImporter(dispatcher, request, importer) ?? (throw mandatoryError("Importer.importer"))); - var globalFunctions = request.globalFunctions.map((signature) { - try { - return hostCallable(dispatcher, functions, request.id, signature); - } on sass.SassException catch (error) { - throw paramsError('CompileRequest.global_functions: $error'); - } - }); + var globalFunctions = request.globalFunctions.map((signature) => + hostCallable(dispatcher, functions, request.id, signature)); late sass.CompileResult result; switch (request.whichInput()) { diff --git a/lib/src/host_callable.dart b/lib/src/host_callable.dart index 203ca750f..7f274efd5 100644 --- a/lib/src/host_callable.dart +++ b/lib/src/host_callable.dart @@ -7,7 +7,6 @@ import 'dart:cli'; import 'dart:io'; import 'package:sass_api/sass_api.dart' as sass; -import 'package:source_span/source_span.dart'; import 'dispatcher.dart'; import 'embedded_sass.pb.dart'; @@ -26,21 +25,8 @@ import 'utils.dart'; sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, int compilationId, String signature, {int? id}) { - var openParen = signature.indexOf('('); - if (openParen == -1) { - throw sass.SassException('"$signature" is missing "("', - SourceFile.fromString(signature).span(0)); - } - - if (!signature.endsWith(")")) { - throw sass.SassException('"$signature" doesn\'t end with ")"', - SourceFile.fromString(signature).span(signature.length)); - } - - var name = signature.substring(0, openParen); - return sass.Callable.function( - name, signature.substring(openParen + 1, signature.length - 1), - (arguments) { + late sass.Callable callable; + callable = sass.Callable.fromSignature(signature, (arguments) { var protofier = Protofier(dispatcher, functions, compilationId); var request = OutboundMessage_FunctionCallRequest() ..compilationId = compilationId @@ -50,7 +36,7 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, if (id != null) { request.functionId = id; } else { - request.name = name; + request.name = callable.name; } // ignore: deprecated_member_use @@ -74,4 +60,5 @@ sass.Callable hostCallable(Dispatcher dispatcher, FunctionRegistry functions, throw error.message; } }); + return callable; } diff --git a/lib/src/importer/base.dart b/lib/src/importer/base.dart index b1a6ae603..2e08a99b5 100644 --- a/lib/src/importer/base.dart +++ b/lib/src/importer/base.dart @@ -6,8 +6,6 @@ import 'package:meta/meta.dart'; import 'package:sass_api/sass_api.dart' as sass; import '../dispatcher.dart'; -import '../embedded_sass.pb.dart' hide SourceSpan; -import '../utils.dart'; /// An abstract base class for importers that communicate with the host in some /// way. @@ -21,25 +19,17 @@ abstract class ImporterBase extends sass.Importer { /// Parses [url] as a [Uri] and throws an error if it's invalid or relative /// (including root-relative). /// - /// The [field] name is used in the error message if one is thrown. + /// The [source] name is used in the error message if one is thrown. @protected - Uri parseAbsoluteUrl(String field, String url) { + Uri parseAbsoluteUrl(String source, String url) { Uri parsedUrl; try { parsedUrl = Uri.parse(url); } on FormatException catch (error) { - sendAndThrow(paramsError("$field is invalid: $error")); + throw '$source must return a URL, was "$url"'; } if (parsedUrl.scheme.isNotEmpty) return parsedUrl; - sendAndThrow(paramsError('$field must be absolute, was "$parsedUrl"')); - } - - /// Sends [error] to the remote endpoint, and also throws it so that the Sass - /// compilation fails. - @protected - Never sendAndThrow(ProtocolError error) { - dispatcher.sendError(error); - throw "Protocol error: ${error.message}"; + throw '$source must return an absolute URL, was "$parsedUrl"'; } } diff --git a/lib/src/importer/file.dart b/lib/src/importer/file.dart index caa4290b3..22b1b9824 100644 --- a/lib/src/importer/file.dart +++ b/lib/src/importer/file.dart @@ -9,7 +9,6 @@ import 'package:sass_api/sass_api.dart' as sass; import '../dispatcher.dart'; import '../embedded_sass.pb.dart' hide SourceSpan; -import '../utils.dart'; import 'base.dart'; /// A filesystem importer to use for most implementation details of @@ -44,11 +43,9 @@ class FileImporter extends ImporterBase { switch (response.whichResult()) { case InboundMessage_FileImportResponse_Result.fileUrl: - var url = - parseAbsoluteUrl("FileImportResponse.file_url", response.fileUrl); + var url = parseAbsoluteUrl("The file importer", response.fileUrl); if (url.scheme != 'file') { - sendAndThrow(paramsError( - 'FileImportResponse.file_url must be a file: URL, was "$url"')); + throw 'The file importer must return a file: URL, was "$url"'; } return _filesystemImporter.canonicalize(url); diff --git a/lib/src/importer/host.dart b/lib/src/importer/host.dart index 33aaefffc..925a77a1f 100644 --- a/lib/src/importer/host.dart +++ b/lib/src/importer/host.dart @@ -35,7 +35,7 @@ class HostImporter extends ImporterBase { switch (response.whichResult()) { case InboundMessage_CanonicalizeResponse_Result.url: - return parseAbsoluteUrl("CanonicalizeResponse.url", response.url); + return parseAbsoluteUrl("The importer", response.url); case InboundMessage_CanonicalizeResponse_Result.error: throw response.error; @@ -60,8 +60,8 @@ class HostImporter extends ImporterBase { return sass.ImporterResult(response.success.contents, sourceMapUrl: response.success.sourceMapUrl.isEmpty ? null - : parseAbsoluteUrl("ImportResponse.success.source_map_url", - response.success.sourceMapUrl), + : parseAbsoluteUrl( + "The importer", response.success.sourceMapUrl), syntax: syntaxToSyntax(response.success.syntax)); case InboundMessage_ImportResponse_Result.error: diff --git a/test/file_importer_test.dart b/test/file_importer_test.dart index fcd0d4056..194b63fe9 100644 --- a/test/file_importer_test.dart +++ b/test/file_importer_test.dart @@ -54,6 +54,18 @@ void main() { "InboundMessage_CanonicalizeResponse."); await process.kill(); }); + }); + + group("emits a compile failure", () { + late OutboundMessage_FileImportRequest request; + + setUp(() async { + process.inbound.add(compileString("@import 'other'", importers: [ + InboundMessage_CompileRequest_Importer()..fileImporterId = 1 + ])); + + request = getFileImportRequest(await process.outbound.next); + }); group("for a FileImportResponse with a URL", () { test("that's empty", () async { @@ -62,8 +74,8 @@ void main() { ..id = request.id ..fileUrl = "")); - await _expectImportParamsError( - process, 'FileImportResponse.file_url must be absolute, was ""'); + await _expectImportError( + process, 'The file importer must return an absolute URL, was ""'); await process.kill(); }); @@ -73,8 +85,8 @@ void main() { ..id = request.id ..fileUrl = "foo")); - await _expectImportParamsError( - process, 'FileImportResponse.file_url must be absolute, was "foo"'); + await _expectImportError(process, + 'The file importer must return an absolute URL, was "foo"'); await process.kill(); }); @@ -84,8 +96,8 @@ void main() { ..id = request.id ..fileUrl = "other:foo")); - await _expectImportParamsError(process, - 'FileImportResponse.file_url must be a file: URL, was "other:foo"'); + await _expectImportError(process, + 'The file importer must return a file: URL, was "other:foo"'); await process.kill(); }); }); @@ -268,14 +280,10 @@ void main() { }); } -/// Asserts that [process] emits a [ProtocolError] params error with the given +/// Asserts that [process] emits a [CompileFailure] result with the given /// [message] on its protobuf stream and causes the compilation to fail. -Future _expectImportParamsError( - EmbeddedProcess process, Object message) async { - await expectLater(process.outbound, - emits(isProtocolError(errorId, ProtocolErrorType.PARAMS, message))); - +Future _expectImportError(EmbeddedProcess process, Object message) async { var failure = getCompileFailure(await process.outbound.next); - expect(failure.message, equals('Protocol error: $message')); + expect(failure.message, equals(message)); expect(failure.span.text, equals("'other'")); } diff --git a/test/function_test.dart b/test/function_test.dart index d2403664d..26e5e80ec 100644 --- a/test/function_test.dart +++ b/test/function_test.dart @@ -21,74 +21,39 @@ void main() { _process = await EmbeddedProcess.start(); }); - group("emits a protocol error for a custom function with a signature", () { + group("emits a compile failure for a custom function with a signature", () { test("that's empty", () async { _process.inbound.add(compileString("a {b: c}", functions: [r""])); - await expectParamsError( - _process, - 0, - 'CompileRequest.global_functions: Error: "" is missing "("\n' - ' ╷\n' - '1 │ \n' - ' │ ^\n' - ' ╵\n' - ' - 1:1 root stylesheet'); + await _expectFunctionError( + _process, r'Invalid signature "": Expected identifier.'); await _process.kill(); }); test("that's just a name", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo"])); - await expectParamsError( - _process, - 0, - 'CompileRequest.global_functions: Error: "foo" is missing "("\n' - ' ╷\n' - '1 │ foo\n' - ' │ ^^^\n' - ' ╵\n' - ' - 1:1 root stylesheet'); + await _expectFunctionError( + _process, r'Invalid signature "foo": expected "(".'); await _process.kill(); }); test("without a closing paren", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo($bar"])); - await expectParamsError( - _process, - 0, - 'CompileRequest.global_functions: Error: "foo(\$bar" doesn\'t end with ")"\n' - ' ╷\n' - '1 │ foo(\$bar\n' - ' │ ^\n' - ' ╵\n' - ' - 1:9 root stylesheet'); + await _expectFunctionError( + _process, r'Invalid signature "foo($bar": expected ")".'); await _process.kill(); }); test("with text after the closing paren", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo() "])); - await expectParamsError( - _process, - 0, - 'CompileRequest.global_functions: Error: "foo() " doesn\'t end with ")"\n' - ' ╷\n' - '1 │ foo() \n' - ' │ ^\n' - ' ╵\n' - ' - 1:7 root stylesheet'); + await _expectFunctionError( + _process, r'Invalid signature "foo() ": expected no more input.'); await _process.kill(); }); test("with invalid arguments", () async { _process.inbound.add(compileString("a {b: c}", functions: [r"foo($)"])); - await expectParamsError( - _process, - 0, - 'CompileRequest.global_functions: Error: Expected identifier.\n' - ' ╷\n' - '1 │ @function foo(\$) {\n' - ' │ ^\n' - ' ╵\n' - ' - 1:16 root stylesheet'); + await _expectFunctionError( + _process, r'Invalid signature "foo($)": Expected identifier.'); await _process.kill(); }); }); @@ -1848,25 +1813,28 @@ void main() { } test("that's empty", () async { - await expectSignatureError("", '"" is missing "("'); + await expectSignatureError( + "", r'Invalid signature "": Expected identifier.'); }); test("that's just a name", () async { - await expectSignatureError("foo", '"foo" is missing "("'); + await expectSignatureError( + "foo", r'Invalid signature "foo": expected "(".'); }); test("without a closing paren", () async { await expectSignatureError( - r"foo($bar", '"foo(\$bar" doesn\'t end with ")"'); + r"foo($bar", r'Invalid signature "foo($bar": expected ")".'); }); test("with text after the closing paren", () async { - await expectSignatureError( - r"foo() ", '"foo() " doesn\'t end with ")"'); + await expectSignatureError(r"foo() ", + r'Invalid signature "foo() ": expected no more input.'); }); test("with invalid arguments", () async { - await expectSignatureError(r"foo($)", 'Expected identifier.'); + await expectSignatureError( + r"foo($)", r'Invalid signature "foo($)": Expected identifier.'); }); }); }); @@ -1989,3 +1957,11 @@ Value _hsl(num hue, num saturation, num lightness, double alpha) => Value() ..saturation = saturation * 1.0 ..lightness = lightness * 1.0 ..alpha = alpha); + +/// Asserts that [process] emits a [CompileFailure] result with the given +/// [message] on its protobuf stream and causes the compilation to fail. +Future _expectFunctionError( + EmbeddedProcess process, Object message) async { + var failure = getCompileFailure(await process.outbound.next); + expect(failure.message, equals(message)); +} diff --git a/test/importer_test.dart b/test/importer_test.dart index 75d4173e3..384ceee8e 100644 --- a/test/importer_test.dart +++ b/test/importer_test.dart @@ -64,7 +64,7 @@ void main() { }); group("canonicalization", () { - group("emits a protocol error", () { + group("emits a compile failure", () { test("for a canonicalize response with an empty URL", () async { process.inbound.add(compileString("@import 'other'", importers: [ InboundMessage_CompileRequest_Importer()..importerId = 1 @@ -76,8 +76,8 @@ void main() { ..id = request.id ..url = "")); - await _expectImportParamsError( - process, 'CanonicalizeResponse.url must be absolute, was ""'); + await _expectImportError( + process, 'The importer must return an absolute URL, was ""'); await process.kill(); }); @@ -92,8 +92,8 @@ void main() { ..id = request.id ..url = "relative")); - await _expectImportParamsError(process, - 'CanonicalizeResponse.url must be absolute, was "relative"'); + await _expectImportError(process, + 'The importer must return an absolute URL, was "relative"'); await process.kill(); }); }); @@ -216,7 +216,7 @@ void main() { }); group("importing", () { - group("emits a protocol error", () { + group("emits a compile failure", () { test("for an import result with a relative sourceMapUrl", () async { process.inbound.add(compileString("@import 'other'", importers: [ InboundMessage_CompileRequest_Importer()..importerId = 1 @@ -230,10 +230,8 @@ void main() { ..success = (InboundMessage_ImportResponse_ImportSuccess() ..sourceMapUrl = "relative"))); - await _expectImportParamsError( - process, - 'ImportResponse.success.source_map_url must be absolute, was ' - '"relative"'); + await _expectImportError(process, + 'The importer must return an absolute URL, was "relative"'); await process.kill(); }); }); @@ -510,14 +508,10 @@ Future _canonicalize(EmbeddedProcess process) async { ..url = "custom:other")); } -/// Asserts that [process] emits a [ProtocolError] params error with the given +/// Asserts that [process] emits a [CompileFailure] result with the given /// [message] on its protobuf stream and causes the compilation to fail. -Future _expectImportParamsError( - EmbeddedProcess process, Object message) async { - await expectLater(process.outbound, - emits(isProtocolError(errorId, ProtocolErrorType.PARAMS, message))); - +Future _expectImportError(EmbeddedProcess process, Object message) async { var failure = getCompileFailure(await process.outbound.next); - expect(failure.message, equals('Protocol error: $message')); + expect(failure.message, equals(message)); expect(failure.span.text, equals("'other'")); } From dfd4432f5d4cd025013c4c1ddc1ce0a28b0562fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 8 Dec 2022 12:21:48 -0800 Subject: [PATCH 131/162] Auto-update homebrew formula on release (#122) Co-authored-by: Natalie Weizenbaum --- .github/workflows/ci.yml | 16 ++++++++++++++++ tool/grind.dart | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e488eb9ad..d69db27a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -302,6 +302,22 @@ jobs: run: dart run grinder pkg-github-${{ matrix.platform }} env: {GH_BEARER_TOKEN: "${{ github.token }}"} + deploy_homebrew: + name: "Deploy Homebrew" + runs-on: ubuntu-latest + needs: [dart_tests, sass_spec, static_analysis, format] + if: "startsWith(github.ref, 'refs/tags/') && github.repository == 'sass/dart-sass-embedded'" + + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v1 + - run: dart pub get + - name: Deploy + run: dart pub run grinder pkg-homebrew-update + env: + GH_TOKEN: "${{ secrets.GH_TOKEN }}" + GH_USER: sassbot + release_embedded_host: name: "Release Embedded Host" runs-on: ubuntu-latest diff --git a/tool/grind.dart b/tool/grind.dart index e4a7290cb..91477a98d 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -11,7 +11,15 @@ import 'package:yaml/yaml.dart'; import 'utils.dart'; void main(List args) { + pkg.humanName.value = "Dart Sass Embedded"; + pkg.botName.value = "Sass Bot"; + pkg.botEmail.value = "sass.bot.beep.boop@gmail.com"; + pkg.homebrewRepo.value = "sass/homebrew-sass"; + pkg.homebrewFormula.value = "dart-sass-embedded.rb"; + pkg.githubBearerToken.fn = () => Platform.environment["GH_BEARER_TOKEN"]!; + pkg.githubUser.fn = () => Platform.environment["GH_USER"]; + pkg.githubPassword.fn = () => Platform.environment["GH_TOKEN"]; pkg.environmentConstants.fn = () => { ...pkg.environmentConstants.defaultValue, @@ -22,6 +30,7 @@ void main(List args) { }; pkg.addGithubTasks(); + pkg.addHomebrewTasks(); grind(args); } From 1e88f05bd7610ae29a693f09b173089ee9cdca5b Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 8 Dec 2022 21:43:29 +0000 Subject: [PATCH 132/162] Update Dart Sass version and release --- CHANGELOG.md | 7 +++++++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 523a1a7cd..c7e3a4a2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.56.2 + +### Embedded Sass + +* The embedded compiler now supports version 1.2.0 of [the embedded + protocol](https://github.com/sass/embedded-protocol). + ## 1.56.1 ### Embedded Sass diff --git a/pubspec.lock b/pubspec.lock index e1c827ea2..76b91f0f8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -308,7 +308,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.56.1" + version: "1.56.2" sass_analysis: dependency: "direct dev" description: @@ -324,7 +324,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "4.1.1" + version: "4.1.2" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1f673f616..a671fb633 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.56.1 +version: 1.56.2 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded @@ -14,7 +14,7 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.56.1 + sass: 1.56.2 sass_api: ^4.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 From 71960dabc17d003b4531864f62c66bddbf0a85f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 8 Dec 2022 15:14:58 -0800 Subject: [PATCH 133/162] Use latest version of cli_pkg (#124) --- pubspec.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index 76b91f0f8..3d1993a5f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -63,7 +63,7 @@ packages: name: cli_pkg url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.6" cli_repl: dependency: transitive description: From 8bde248ce9383579b8e4512200874005d4ff9117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Fri, 16 Dec 2022 19:14:00 -0800 Subject: [PATCH 134/162] Create dependabot.yml (#127) --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..d24aa6443 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "pub" + directory: "/" + schedule: + interval: "weekly" From ac2a348f7ed7d2b09d9d4120d229dac1c2f7f9af Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 19 Dec 2022 15:36:23 -0800 Subject: [PATCH 135/162] Cherry-pick CI changes from feature.color-4 --- .github/workflows/ci.yml | 89 +++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d69db27a4..a0cfa9cf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ name: CI +defaults: + run: {shell: bash} + env: protoc_version: '3.x' @@ -23,6 +26,8 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: frenck/action-setup-yq@v1 + with: {version: v4.30.5} # frenck/action-setup-yq#35 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 @@ -35,22 +40,13 @@ jobs: path: build/dart-sass default-ref: null - - name: Check out Dart Sass from main HEAD when using -dev dependency - run: | - if [[ ! -d build/dart-sass ]] && grep --quiet -E '\bsass:\s*.*-dev["'"'"']?$' pubspec.yaml; then - git clone https://github.com/sass/dart-sass.git \ - --depth 1 build/dart-sass - fi - shell: bash - - - name: Override dart-sass dependency only if repo was cloned a priori + - name: Link the embedded compiler to Dart Sass run: | if [[ -d build/dart-sass ]]; then - ( - echo "dependency_overrides:" - echo " sass: {path: build/dart-sass}" - echo " sass_api: {path: build/dart-sass/pkg/sass_api}" - ) >> pubspec.yaml + yq -i ' + .dependency_overrides.sass = {"path": "build/dart-sass"} | + .dependency_overrides.sass_api = {"path": "build/dart-sass/pkg/sass_api"} + ' pubspec.yaml fi shell: bash @@ -88,6 +84,8 @@ jobs: - uses: actions/checkout@v3 - uses: dart-lang/setup-dart@v1 with: {sdk: stable} + - uses: frenck/action-setup-yq@v1 + with: {version: v4.30.5} # frenck/action-setup-yq#35 - uses: arduino/setup-protoc@v1 with: version: ${{ env.PROTOC_VERSION }} @@ -100,22 +98,13 @@ jobs: path: build/dart-sass default-ref: null - - name: Check out Dart Sass from main HEAD when using -dev dependency - run: | - if [[ ! -d build/dart-sass ]] && grep --quiet -E '\bsass:\s*.*-dev["'"'"']?$' pubspec.yaml; then - git clone https://github.com/sass/dart-sass.git \ - --depth 1 build/dart-sass - fi - shell: bash - - - name: Override dart-sass dependency only if repo was cloned a priori + - name: Link the embedded compiler to Dart Sass run: | if [[ -d build/dart-sass ]]; then - ( - echo "dependency_overrides:" - echo " sass: {path: build/dart-sass}" - echo " sass_api: {path: build/dart-sass/pkg/sass_api}" - ) >> pubspec.yaml + yq -i ' + .dependency_overrides.sass = {"path": "build/dart-sass"} | + .dependency_overrides.sass_api = {"path": "build/dart-sass/pkg/sass_api"} + ' pubspec.yaml fi shell: bash @@ -131,12 +120,13 @@ jobs: uses: sass/clone-linked-repo@v1 with: {repo: sass/sass, path: language} - - name: "Embedded host: npm install" - run: npm install - working-directory: embedded-host-node - - name: "Embedded host: npm run init" + - name: Initialize embedded host run: | - npm run init -- --protocol-path=../build/embedded-protocol --compiler-path=.. --api-path=../language + npm install + npm run init -- --protocol-path=../build/embedded-protocol \ + --compiler-path=.. --api-path=../language + npm run compile + mv {`pwd`/,dist/}lib/src/vendor/dart-sass-embedded working-directory: embedded-host-node - name: Check out sass-spec @@ -147,12 +137,14 @@ jobs: run: npm install working-directory: sass-spec - - name: Compile embedded host + - name: Version info run: | - npm run compile - mv {`pwd`/,dist/}lib/src/vendor/dart-sass-embedded - shell: bash - working-directory: embedded-host-node + path=embedded-host-node/dist/lib/src/vendor/dart-sass-embedded/dart-sass-embedded + if [[ -f "$path.cmd" ]]; then "./$path.cmd" --version + elif [[ -f "$path.bat" ]]; then "./$path.bat" --version + elif [[ -f "$path.exe" ]]; then "./$path.exe" --version + else "./$path" --version + fi - name: Run tests run: npm run js-api-spec -- --sassPackage ../embedded-host-node --sassSassRepo ../language @@ -164,6 +156,8 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: frenck/action-setup-yq@v1 + with: {version: v4.30.5} # frenck/action-setup-yq#35 - uses: arduino/setup-protoc@v1 with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } - uses: dart-lang/setup-dart@v1 @@ -175,22 +169,13 @@ jobs: path: build/dart-sass default-ref: null - - name: Check out Dart Sass from main HEAD when using -dev dependency - run: | - if [[ ! -d build/dart-sass ]] && grep --quiet -E '\bsass:\s*.*-dev["'"'"']?$' pubspec.yaml; then - git clone https://github.com/sass/dart-sass.git \ - --depth 1 build/dart-sass - fi - shell: bash - - - name: Override dart-sass dependency only if repo was cloned a priori + - name: Link the embedded compiler to Dart Sass run: | if [[ -d build/dart-sass ]]; then - ( - echo "dependency_overrides:" - echo " sass: {path: build/dart-sass}" - echo " sass_api: {path: build/dart-sass/pkg/sass_api}" - ) >> pubspec.yaml + yq -i ' + .dependency_overrides.sass = {"path": "build/dart-sass"} | + .dependency_overrides.sass_api = {"path": "build/dart-sass/pkg/sass_api"} + ' pubspec.yaml fi shell: bash From 890fbcb8ed9ba83cb32446b759b1777abf1a36d2 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 19 Dec 2022 15:38:07 -0800 Subject: [PATCH 136/162] Run sass-spec tests against the latest Dart Sass by default --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0cfa9cf1..c2e6ed307 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,7 +96,10 @@ jobs: with: repo: sass/dart-sass path: build/dart-sass - default-ref: null + # Unless we're cutting a release, run the main branch of Dart Sass + # against the main branch of sass-spec so that we don't need to make + # an empty commit to this repo every time we update those two. + default-ref: ${{ !startsWith(github.ref, 'refs/tags/') && 'main' || null }} - name: Link the embedded compiler to Dart Sass run: | From d426ab837ef16e2ef2bbba0ab749b4135b2a4eff Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Mon, 19 Dec 2022 23:53:43 +0000 Subject: [PATCH 137/162] Update Dart Sass version and release --- CHANGELOG.md | 24 ++++++++++++++++ pubspec.lock | 81 ++++++++++++++++++++++++++++------------------------ pubspec.yaml | 8 ++---- 3 files changed, 70 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e3a4a2a..9f530226d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +## 1.57.1 + +* No user-visible changes. + +## 1.57.0 + +* Add a `split($string, $separator, $limit: null)` function to `sass:string` + that splits a string into separate substrings based on a separator string. + +### JavaScript API + +* **Potentially breaking bug fix**: Custom functions in both the modern and + legacy API now properly reject signatures with whitespace between the function + name and parentheses. + +* Custom functions in the legacy API now allow signatures with whitespace before + the function name, to match a bug in Node Sass. + +### Dart API + +* **Potentially breaking bug fix**: `Callable.fromSignature()` and + `AsyncCallable.fromSignature()` now reject signatures with whitespace between + the function name and parentheses. + ## 1.56.2 ### Embedded Sass diff --git a/pubspec.lock b/pubspec.lock index 3d1993a5f..afb890285 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "48.0.0" + version: "51.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.3.1" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.3.1" + version: "3.3.5" args: dependency: transitive description: @@ -35,14 +35,14 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" charcode: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: cli_pkg url: "https://pub.dartlang.org" source: hosted - version: "2.1.6" + version: "2.1.9" cli_repl: dependency: transitive description: @@ -84,14 +84,14 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.1" coverage: dependency: transitive description: @@ -133,14 +133,14 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.2.0" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" grinder: dependency: "direct dev" description: @@ -168,7 +168,7 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.0.2" io: dependency: transitive description: @@ -182,7 +182,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.6.5" json_annotation: dependency: transitive description: @@ -196,21 +196,21 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.1.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.12" + version: "0.12.14" meta: dependency: "direct main" description: @@ -224,7 +224,7 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" node_interop: dependency: transitive description: @@ -252,14 +252,21 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.8.3" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.0" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.2" pool: dependency: transitive description: @@ -287,7 +294,7 @@ packages: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" pubspec_parse: dependency: "direct dev" description: @@ -295,10 +302,10 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" - quiver: + retry: dependency: transitive description: - name: quiver + name: retry url: "https://pub.dartlang.org" source: hosted version: "3.1.0" @@ -308,13 +315,13 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.56.2" + version: "1.57.1" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: a65e504b484eeacfff5219a24ad4b89e5ee1f87f + resolved-ref: "5522c17a7bf88f07ddef02ae97caf15c779196de" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -324,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "4.1.2" + version: "4.2.1" shelf: dependency: transitive description: @@ -352,21 +359,21 @@ packages: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" source_maps: dependency: transitive description: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.10" + version: "0.10.11" source_span: dependency: "direct main" description: @@ -380,7 +387,7 @@ packages: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: "direct main" description: @@ -394,14 +401,14 @@ packages: name: stream_transform url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: "direct main" description: @@ -415,42 +422,42 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.21.6" + version: "1.22.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.14" + version: "0.4.17" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.18" + version: "0.4.21" test_descriptor: dependency: "direct dev" description: name: test_descriptor url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" test_process: dependency: transitive description: name: test_process url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" tuple: dependency: transitive description: name: tuple url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" typed_data: dependency: "direct main" description: @@ -471,7 +478,7 @@ packages: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" web_socket_channel: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a671fb633..c650ae727 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,27 +1,23 @@ name: sass_embedded -version: 1.56.2 +version: 1.57.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded - environment: sdk: '>=2.12.0 <3.0.0' - executables: dart-sass-embedded: dart_sass_embedded - dependencies: async: ">=1.13.0 <3.0.0" meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.56.2 + sass: 1.57.1 sass_api: ^4.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" term_glyph: ^1.0.0 typed_data: ^1.1.0 - dev_dependencies: cli_pkg: ^2.1.0 grinder: ^0.9.0 From 288bbddea0eaca67b76d09dcc374c736c70c0ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Tue, 27 Dec 2022 16:21:41 -0800 Subject: [PATCH 138/162] Fix dart analyze issues (#135) --- lib/src/importer/base.dart | 2 +- pubspec.lock | 2 +- pubspec.yaml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/importer/base.dart b/lib/src/importer/base.dart index 2e08a99b5..d8ecd277d 100644 --- a/lib/src/importer/base.dart +++ b/lib/src/importer/base.dart @@ -25,7 +25,7 @@ abstract class ImporterBase extends sass.Importer { Uri parsedUrl; try { parsedUrl = Uri.parse(url); - } on FormatException catch (error) { + } on FormatException { throw '$source must return a URL, was "$url"'; } diff --git a/pubspec.lock b/pubspec.lock index afb890285..10db95571 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -368,7 +368,7 @@ packages: source: hosted version: "2.1.1" source_maps: - dependency: transitive + dependency: "direct dev" description: name: source_maps url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index c650ae727..eaf675107 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,3 +31,4 @@ dev_dependencies: git: url: https://github.com/sass/dart-sass.git path: analysis + source_maps: ^0.10.10 From 436185adc9c21934bd60209a846d9fdfcecb284c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 21:42:28 +0000 Subject: [PATCH 139/162] Bump test from 1.22.1 to 1.22.2 (#138) Bumps [test](https://github.com/dart-lang/test/tree/master/pkgs) from 1.22.1 to 1.22.2. - [Release notes](https://github.com/dart-lang/test/releases) - [Commits](https://github.com/dart-lang/test/commits/HEAD/pkgs) --- updated-dependencies: - dependency-name: test dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 10db95571..406d19e89 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -422,21 +422,21 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.22.1" + version: "1.22.2" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.17" + version: "0.4.18" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.21" + version: "0.4.22" test_descriptor: dependency: "direct dev" description: From 8680e05b22e58f52c78f600de8002fcce03e6699 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 23:32:02 +0000 Subject: [PATCH 140/162] Bump cli_pkg from 2.1.9 to 2.2.0 (#140) Bumps [cli_pkg](https://github.com/google/dart_cli_pkg) from 2.1.9 to 2.2.0. - [Release notes](https://github.com/google/dart_cli_pkg/releases) - [Changelog](https://github.com/google/dart_cli_pkg/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/dart_cli_pkg/compare/2.1.9...2.2.0) --- updated-dependencies: - dependency-name: cli_pkg dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index 406d19e89..75081d6fd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -63,7 +63,7 @@ packages: name: cli_pkg url: "https://pub.dartlang.org" source: hosted - version: "2.1.9" + version: "2.2.0" cli_repl: dependency: transitive description: From 34a34c0e5245a95878a19fba501d43d15b8def4f Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Tue, 24 Jan 2023 16:04:39 -0800 Subject: [PATCH 141/162] Update CI Node versions to 18/16/14 (#139) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2e6ed307..d2f470353 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,13 +72,13 @@ jobs: fail-fast: false matrix: os: [ubuntu, windows, macos] - node_version: [16] + node_version: [18] include: # Include LTS versions on Ubuntu - os: ubuntu - node_version: 14 + node_version: 16 - os: ubuntu - node_version: 12 + node_version: 14 steps: - uses: actions/checkout@v3 From 487753ebe47696a4dfc3943e2c7b9424694b2e36 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 1 Feb 2023 15:44:20 -0800 Subject: [PATCH 142/162] Release 1.58.0 (#142) --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ pubspec.yaml | 6 +++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f530226d..b64a1a8de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +## 1.58.0 + +* Remove sourcemap comments from Sass sources. The generated sourcemap comment + for the compiled CSS output remains unaffected. + +* Fix a bug in `@extend` logic where certain selectors with three or more + combinators were incorrectly considered superselectors of similar selectors + with fewer combinators, causing them to be incorrectly trimmed from the + output. + +* Produce a better error message for a number with a leading `+` or `-`, a + decimal point, but no digits. + +* Produce a better error message for a nested property whose name starts with + `--`. + +* Fix a crash when a selector ends in an escaped backslash. + +* Add the relative length units from CSS Values 4 and CSS Contain 3 as known + units to validate bad computation in `calc`. + +### Command Line Interface + +* The `--watch` flag will now track loads through calls to `meta.load-css()` as + long as their URLs are literal strings without any interpolation. + ## 1.57.1 * No user-visible changes. diff --git a/pubspec.yaml b/pubspec.yaml index eaf675107..8840976d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.57.1 +version: 1.58.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.57.1 - sass_api: ^4.0.0 + sass: 1.58.0 + sass_api: ^5.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From f50a3f0da381d5237887369adc08822e76258b05 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 8 Feb 2023 17:30:05 -0800 Subject: [PATCH 143/162] Use buf instead of protoc to compile protobufs (#146) This is more consistent with the embedded host, and avoids relying on the seldom-maintaned arduino/setup-protoc GitHub action. --- .github/workflows/ci.yml | 43 ++++++++++++++-------------------------- README.md | 16 +++++++++++++++ buf.gen.yaml | 4 ++++ buf.work.yaml | 2 ++ tool/grind.dart | 16 +++++++-------- 5 files changed, 44 insertions(+), 37 deletions(-) create mode 100644 buf.gen.yaml create mode 100644 buf.work.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2f470353..c2bc8f29b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,9 +3,6 @@ name: CI defaults: run: {shell: bash} -env: - protoc_version: '3.x' - on: push: branches: [main, feature.*] @@ -28,8 +25,8 @@ jobs: - uses: actions/checkout@v3 - uses: frenck/action-setup-yq@v1 with: {version: v4.30.5} # frenck/action-setup-yq#35 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: bufbuild/buf-setup-action@v1.13.1 + with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 with: {sdk: "${{ matrix.dart_channel }}"} @@ -86,10 +83,8 @@ jobs: with: {sdk: stable} - uses: frenck/action-setup-yq@v1 with: {version: v4.30.5} # frenck/action-setup-yq#35 - - uses: arduino/setup-protoc@v1 - with: - version: ${{ env.PROTOC_VERSION }} - repo-token: '${{ github.token }}' + - uses: bufbuild/buf-setup-action@v1.13.1 + with: {github_token: "${{ github.token }}"} - name: Check out Dart Sass only if linked in the PR description uses: sass/clone-linked-repo@v1 @@ -161,8 +156,8 @@ jobs: - uses: actions/checkout@v3 - uses: frenck/action-setup-yq@v1 with: {version: v4.30.5} # frenck/action-setup-yq#35 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: bufbuild/buf-setup-action@v1.13.1 + with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 - name: Check out Dart Sass only if linked in the PR description @@ -210,20 +205,11 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: arduino/setup-protoc@v1 - with: { version: "${{ env.protoc_version }}", repo-token: "${{ github.token }}" } + - uses: bufbuild/buf-setup-action@v1.13.1 + with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart run grinder protobuf - # We need to upload the compiled protobuf rather than recompiling it on - # other platforms because arduino/setup-protoc currently) requires Node 12 - # which doesn't support ARM. - - uses: actions/upload-artifact@v3 - with: - name: embedded-protocol - path: | - build/embedded-protocol - lib/src/embedded_sass.*.dart - name: Deploy run: dart run grinder pkg-github-release pkg-github-linux-ia32 pkg-github-linux-x64 env: {GH_BEARER_TOKEN: "${{ github.token }}"} @@ -243,9 +229,10 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/download-artifact@v3 - with: - name: embedded-protocol + - uses: bufbuild/buf-setup-action@v1.13.1 + with: {github_token: "${{ github.token }}"} + - run: dart pub get + - run: dart pub grinder protobuf - uses: docker/setup-qemu-action@v2 - name: Deploy run: | @@ -278,14 +265,14 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/download-artifact@v3 - with: - name: embedded-protocol + - uses: bufbuild/buf-setup-action@v1.13.1 + with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 # Workaround for dart-lang/setup-dart#59 with: architecture: ${{ matrix.architecture }} - run: dart pub get + - run: dart pub run grinder protobuf - name: Deploy run: dart run grinder pkg-github-${{ matrix.platform }} env: {GH_BEARER_TOKEN: "${{ github.token }}"} diff --git a/README.md b/README.md index 9fe89f7b0..71cd05edf 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,22 @@ and importers. - `dart-sass-embedded` starts the compiler and listens on stdin. - `dart-sass-embedded --version` prints `versionResponse` with `id = 0` in JSON and exits. +### Development + +To run the embedded compiler from source: + +* Run `dart pub get`. + +* [Install `buf`]. + +* Run `dart run grinder protobuf`. + +From there, you can either run `dart bin/dart_sass_embedded.dart` directly or +`dart run grinder pkg-standalone-dev` to build a compiled development +executable. + +[Install `buf`]: https://docs.buf.build/installation + ### Releases Binary releases are available from the [GitHub release page]. We recommend that diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 000000000..9b078c8b5 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,4 @@ +version: v1 +plugins: +- plugin: dart + out: lib/src diff --git a/buf.work.yaml b/buf.work.yaml new file mode 100644 index 000000000..0cc295bc9 --- /dev/null +++ b/buf.work.yaml @@ -0,0 +1,2 @@ +version: v1 +directories: [build/embedded-protocol] diff --git a/tool/grind.dart b/tool/grind.dart index 91477a98d..4a10c7199 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -51,11 +51,13 @@ Future protobuf() async { if (Platform.isWindows) { File('build/protoc-gen-dart.bat').writeAsStringSync(''' @echo off -dart pub run protoc_plugin %* +dart run protoc_plugin %* '''); } else { - File('build/protoc-gen-dart') - .writeAsStringSync('dart pub run protoc_plugin "\$@"'); + File('build/protoc-gen-dart').writeAsStringSync(''' +#!/bin/sh +dart run protoc_plugin "\$@" +'''); run('chmod', arguments: ['a+x', 'build/protoc-gen-dart']); } @@ -63,12 +65,8 @@ dart pub run protoc_plugin %* await cloneOrPull("https://github.com/sass/embedded-protocol.git"); } - await runAsync("protoc", - arguments: [ - "-Ibuild/embedded-protocol", - "embedded_sass.proto", - "--dart_out=lib/src/" - ], + await runAsync("buf", + arguments: ["generate"], runOptions: RunOptions(environment: { "PATH": 'build' + (Platform.isWindows ? ";" : ":") + From b4d390f096d98cca434578d8fa6a3620461b321b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 9 Feb 2023 17:56:24 -0800 Subject: [PATCH 144/162] Add missing setup-dart step in qemu release (#147) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2bc8f29b..2d926439b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,6 +231,7 @@ jobs: - uses: actions/checkout@v3 - uses: bufbuild/buf-setup-action@v1.13.1 with: {github_token: "${{ github.token }}"} + - uses: dart-lang/setup-dart@v1 - run: dart pub get - run: dart pub grinder protobuf - uses: docker/setup-qemu-action@v2 From 9d2abbc498e8f30510bce5ba4fa5ed569da57582 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 00:47:15 +0000 Subject: [PATCH 145/162] Bump grinder from 0.9.2 to 0.9.3 (#145) Bumps [grinder](https://github.com/google/grinder.dart) from 0.9.2 to 0.9.3. - [Release notes](https://github.com/google/grinder.dart/releases) - [Changelog](https://github.com/google/grinder.dart/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/grinder.dart/compare/0.9.2...v0.9.3) --- updated-dependencies: - dependency-name: grinder 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> --- pubspec.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 75081d6fd..1b92fdd9c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -147,7 +147,7 @@ packages: name: grinder url: "https://pub.dartlang.org" source: hosted - version: "0.9.2" + version: "0.9.3" http: dependency: transitive description: @@ -315,7 +315,7 @@ packages: name: sass url: "https://pub.dartlang.org" source: hosted - version: "1.57.1" + version: "1.58.0" sass_analysis: dependency: "direct dev" description: @@ -331,7 +331,7 @@ packages: name: sass_api url: "https://pub.dartlang.org" source: hosted - version: "4.2.1" + version: "5.0.0" shelf: dependency: transitive description: From e468cf012264957b81b07e695ceff9d21d0d467c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 00:47:31 +0000 Subject: [PATCH 146/162] Bump meta from 1.8.0 to 1.9.0 (#144) Bumps [meta](https://github.com/dart-lang/sdk/tree/main/pkg) from 1.8.0 to 1.9.0. - [Release notes](https://github.com/dart-lang/sdk/releases) - [Changelog](https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/sdk/commits/1.9.0/pkg) --- updated-dependencies: - dependency-name: meta 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> --- pubspec.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index 1b92fdd9c..713517b6b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -217,7 +217,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.9.0" mime: dependency: transitive description: From f966cbcb516e9c1af1bccc84762835dec77fef71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 00:47:58 +0000 Subject: [PATCH 147/162] Bump sass_api from 4.2.1 to 5.0.0 (#143) Bumps [sass_api](https://github.com/sass/dart-sass) from 4.2.1 to 5.0.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/sass_api/4.2.1...sass_api/5.0.0) --- updated-dependencies: - dependency-name: sass_api dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 2c8bf35adf91694a62cccf8460bb99a25cb3a136 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 14 Feb 2023 00:57:06 +0000 Subject: [PATCH 148/162] Update Dart Sass version and release --- CHANGELOG.md | 6 ++ pubspec.lock | 255 ++++++++++++++++++++++++++++++++------------------- pubspec.yaml | 6 +- 3 files changed, 172 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b64a1a8de..3d6fa2cb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.58.1 + +* Emit a unitless hue when serializing `hsl()` colors. The `deg` unit is + incompatible with IE, and while that officially falls outside our + compatibility policy, it's better to lean towards greater compatibility. + ## 1.58.0 * Remove sourcemap comments from Sass sources. The generated sourcemap comment diff --git a/pubspec.lock b/pubspec.lock index 713517b6b..9ffa9c82d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,323 +5,368 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201" + url: "https://pub.dev" source: hosted - version: "51.0.0" + version: "52.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4 + url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.4.0" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + url: "https://pub.dev" source: hosted - version: "3.3.5" + version: "3.3.6" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" async: dependency: "direct main" description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted version: "2.1.1" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" cli_pkg: dependency: "direct dev" description: name: cli_pkg - url: "https://pub.dartlang.org" + sha256: "977b0a29d838a0b18630f9c3ee83a8276a061c1715ef0b1040d4a63005c85431" + url: "https://pub.dev" source: hosted version: "2.2.0" cli_repl: dependency: transitive description: name: cli_repl - url: "https://pub.dartlang.org" + sha256: a2ee06d98f211cb960c777519cb3d14e882acd90fe5e078668e3ab4baab0ddd4 + url: "https://pub.dev" source: hosted version: "0.2.3" cli_util: dependency: transitive description: name: cli_util - url: "https://pub.dartlang.org" + sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + url: "https://pub.dev" source: hosted version: "0.3.5" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted version: "3.1.1" coverage: dependency: transitive description: name: coverage - url: "https://pub.dartlang.org" + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" source: hosted - version: "1.6.1" + version: "1.6.3" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + url: "https://pub.dev" source: hosted version: "2.2.4" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" source: hosted version: "3.2.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" source: hosted version: "2.1.1" grinder: dependency: "direct dev" description: name: grinder - url: "https://pub.dartlang.org" + sha256: "1dabcd70f0d3975f9143d0cebf48a09cf56d4f5e0922f1d1931781e1047c8d00" + url: "https://pub.dev" source: hosted version: "0.9.3" http: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.0" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 + url: "https://pub.dev" source: hosted version: "0.12.14" meta: dependency: "direct main" description: name: meta - url: "https://pub.dartlang.org" + sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b" + url: "https://pub.dev" source: hosted version: "1.9.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" node_interop: dependency: transitive description: name: node_interop - url: "https://pub.dartlang.org" + sha256: "3af2420c728173806f4378cf89c53ba9f27f7f67792b898561bff9d390deb98e" + url: "https://pub.dev" source: hosted version: "2.1.0" node_preamble: dependency: transitive description: name: node_preamble - url: "https://pub.dartlang.org" + sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + url: "https://pub.dev" source: hosted version: "2.0.1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: "direct main" description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted version: "1.8.3" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" source: hosted version: "5.1.0" pointycastle: dependency: transitive description: name: pointycastle - url: "https://pub.dartlang.org" + sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + url: "https://pub.dev" source: hosted version: "3.6.2" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" protobuf: dependency: "direct main" description: name: protobuf - url: "https://pub.dartlang.org" + sha256: "01dd9bd0fa02548bf2ceee13545d4a0ec6046459d847b6b061d8a27237108a08" + url: "https://pub.dev" source: hosted version: "2.1.0" protoc_plugin: dependency: "direct dev" description: name: protoc_plugin - url: "https://pub.dartlang.org" + sha256: e2be5014ba145dc0f8de20ac425afa2a513aff64fe350d338e481d40de0573df + url: "https://pub.dev" source: hosted version: "20.0.1" pub_semver: dependency: "direct dev" description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" source: hosted version: "2.1.3" pubspec_parse: dependency: "direct dev" description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + url: "https://pub.dev" source: hosted version: "1.2.1" retry: dependency: transitive description: name: retry - url: "https://pub.dartlang.org" + sha256: "45dfeebaf095b606fdb9dbfb4c114cc204449bc274783b452658365e03afdbab" + url: "https://pub.dev" source: hosted version: "3.1.0" sass: dependency: "direct main" description: name: sass - url: "https://pub.dartlang.org" + sha256: "8606f1a8d79c635463d453687f40e75d23c5d005a7ca01c9ce4661212d386e61" + url: "https://pub.dev" source: hosted - version: "1.58.0" + version: "1.58.1" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "5522c17a7bf88f07ddef02ae97caf15c779196de" + resolved-ref: c8b4cd09ebddba5620a1f3831b5656953c2170b1 url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -329,183 +374,209 @@ packages: dependency: "direct main" description: name: sass_api - url: "https://pub.dartlang.org" + sha256: b0d934d8316a59bfb237b85ffbc9989f81632fff1d36a08e3f215507eddb40c5 + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.0.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + url: "https://pub.dev" source: hosted version: "1.4.0" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - url: "https://pub.dartlang.org" + sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 + url: "https://pub.dev" source: hosted version: "3.0.1" shelf_static: dependency: transitive description: name: shelf_static - url: "https://pub.dartlang.org" + sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c + url: "https://pub.dev" source: hosted version: "1.1.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + url: "https://pub.dev" source: hosted version: "1.0.3" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace - url: "https://pub.dartlang.org" + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" source: hosted version: "2.1.1" source_maps: dependency: "direct dev" description: name: source_maps - url: "https://pub.dartlang.org" + sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + url: "https://pub.dev" source: hosted version: "0.10.11" source_span: dependency: "direct main" description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted version: "1.9.1" stack_trace: dependency: "direct main" description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted version: "1.11.0" stream_channel: dependency: "direct main" description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted version: "1.2.0" term_glyph: dependency: "direct main" description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test: dependency: "direct dev" description: name: test - url: "https://pub.dartlang.org" + sha256: "5301f54eb6fe945daa99bc8df6ece3f88b5ceaa6f996f250efdaaf63e22886be" + url: "https://pub.dev" source: hosted - version: "1.22.2" + version: "1.23.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d" + url: "https://pub.dev" source: hosted version: "0.4.18" test_core: dependency: transitive description: name: test_core - url: "https://pub.dartlang.org" + sha256: d2e9240594b409565524802b84b7b39341da36dd6fd8e1660b53ad928ec3e9af + url: "https://pub.dev" source: hosted - version: "0.4.22" + version: "0.4.24" test_descriptor: dependency: "direct dev" description: name: test_descriptor - url: "https://pub.dartlang.org" + sha256: abe245e8b0d61245684127fe32343542c25dc2a1ce8f405531637241d98d07e4 + url: "https://pub.dev" source: hosted version: "2.0.1" test_process: dependency: transitive description: name: test_process - url: "https://pub.dartlang.org" + sha256: b0e6702f58272d459d5b80b88696483f86eac230dab05ecf73d0662e305d005e + url: "https://pub.dev" source: hosted version: "2.0.3" tuple: dependency: transitive description: name: tuple - url: "https://pub.dartlang.org" + sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + url: "https://pub.dev" source: hosted version: "2.0.1" typed_data: dependency: "direct main" description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: a4040e9852e56bf8a3c5a2e08a56f6facd76e75500cf2a922ce5d52394c4998a + url: "https://pub.dev" source: hosted - version: "9.4.0" + version: "11.0.1" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" source: hosted version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol - url: "https://pub.dartlang.org" + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" source: hosted version: "1.2.0" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: "80d494c09849dc3f899d227a78c30c5b949b985ededf884cb3f3bcd39f4b447a" + url: "https://pub.dev" source: hosted version: "5.4.1" yaml: dependency: "direct dev" description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=2.19.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8840976d3..34f50d6d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.58.0 +version: 1.58.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.58.0 - sass_api: ^5.0.0 + sass: 1.58.1 + sass_api: ^5.0.1 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 13a18cde0c6a8cd7b6b491f3485568ded3f3a8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Tue, 14 Feb 2023 14:06:40 -0800 Subject: [PATCH 149/162] Fix qemu releases (#149) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d926439b..71f1f3bda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,7 +233,7 @@ jobs: with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 - run: dart pub get - - run: dart pub grinder protobuf + - run: dart run grinder protobuf - uses: docker/setup-qemu-action@v2 - name: Deploy run: | @@ -273,7 +273,7 @@ jobs: with: architecture: ${{ matrix.architecture }} - run: dart pub get - - run: dart pub run grinder protobuf + - run: dart run grinder protobuf - name: Deploy run: dart run grinder pkg-github-${{ matrix.platform }} env: {GH_BEARER_TOKEN: "${{ github.token }}"} @@ -289,7 +289,7 @@ jobs: - uses: dart-lang/setup-dart@v1 - run: dart pub get - name: Deploy - run: dart pub run grinder pkg-homebrew-update + run: dart run grinder pkg-homebrew-update env: GH_TOKEN: "${{ secrets.GH_TOKEN }}" GH_USER: sassbot From c23d5d98f38d8db03db31d03d2d72a37a3092b9f Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 17 Feb 2023 01:39:22 +0000 Subject: [PATCH 150/162] Update Dart Sass version and release --- CHANGELOG.md | 9 +++++++++ pubspec.lock | 22 +++++++++++----------- pubspec.yaml | 6 +++--- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d6fa2cb6..f1b152031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.58.2 + +### Command Line Interface + +* Add a timestamp to messages printed in `--watch` mode. + +* Print better `calc()`-based suggestions for `/`-as-division expression that + contain calculation-incompatible constructs like unary minus. + ## 1.58.1 * Emit a unitless hue when serializing `hsl()` colors. The `deg` unit is diff --git a/pubspec.lock b/pubspec.lock index 9ffa9c82d..f6348c8cf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201" + sha256: "569ddca58d535e601dd1584afa117710abc999d036c0cd2c51777fb257df78e8" url: "https://pub.dev" source: hosted - version: "52.0.0" + version: "53.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4 + sha256: "10927c4b7c7c88b1adbca278c3d5531db92e2f4b4abf04e2919a800af965f3f5" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.5.0" archive: dependency: transitive description: @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: "8606f1a8d79c635463d453687f40e75d23c5d005a7ca01c9ce4661212d386e61" + sha256: f08ef7beae55ca2d07fabb4e0733dd20bc08186e7a714eac953725c9971b49b7 url: "https://pub.dev" source: hosted - version: "1.58.1" + version: "1.58.2" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: c8b4cd09ebddba5620a1f3831b5656953c2170b1 + resolved-ref: c4523884bf9fba3a312bae2af559049cd374d42e url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: b0d934d8316a59bfb237b85ffbc9989f81632fff1d36a08e3f215507eddb40c5 + sha256: "4b35efdef6bf4282648498e1556d518c15d0fcc480eccd3dfb30b3b0d82dc36a" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.1.0" shelf: dependency: transitive description: @@ -422,10 +422,10 @@ packages: dependency: "direct dev" description: name: source_maps - sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" url: "https://pub.dev" source: hosted - version: "0.10.11" + version: "0.10.12" source_span: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 34f50d6d5..897c56fd0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.58.1 +version: 1.58.2 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.58.1 - sass_api: ^5.0.1 + sass: 1.58.2 + sass_api: ^5.1.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 909441934ae22e9d69de079b1bfb2391946ed5bf Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Sat, 18 Feb 2023 00:40:20 +0000 Subject: [PATCH 151/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 10 +++++----- pubspec.yaml | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b152031..9cae5bed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.58.3 + +* No user-visible changes. + ## 1.58.2 ### Command Line Interface diff --git a/pubspec.lock b/pubspec.lock index f6348c8cf..05c8e9ed1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: f08ef7beae55ca2d07fabb4e0733dd20bc08186e7a714eac953725c9971b49b7 + sha256: c3e37d50a372cee0fd4058b12f0167da8307c602ff8e357ebf587142b753b41a url: "https://pub.dev" source: hosted - version: "1.58.2" + version: "1.58.3" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: c4523884bf9fba3a312bae2af559049cd374d42e + resolved-ref: "620d8d355e8396afe107b3e167b11524d757f3ca" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: "4b35efdef6bf4282648498e1556d518c15d0fcc480eccd3dfb30b3b0d82dc36a" + sha256: d4f402a63d06745c83415e5850022b2e2741b896b9fd6a50714bce509dc81c36 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.1.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 897c56fd0..7157bf0b3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.58.2 +version: 1.58.3 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.58.2 - sass_api: ^5.1.0 + sass: 1.58.3 + sass_api: ^5.1.1 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 7d38d428172d7384fa88cf01df048c45756ee9ae Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 6 Mar 2023 13:18:28 -0800 Subject: [PATCH 152/162] Remove workaround for dart-lang/setup-dart#59 (#151) --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71f1f3bda..c27091bc0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -256,22 +256,16 @@ jobs: include: - runner: macos-latest platform: macos-x64 - architecture: x64 - runner: self-hosted platform: macos-arm64 - architecture: arm64 - runner: windows-latest platform: windows - architecture: x64 steps: - uses: actions/checkout@v3 - uses: bufbuild/buf-setup-action@v1.13.1 with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 - # Workaround for dart-lang/setup-dart#59 - with: - architecture: ${{ matrix.architecture }} - run: dart pub get - run: dart run grinder protobuf - name: Deploy From ffc70679d35c70a9969580c6846d65a8db67deca Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 10 Mar 2023 22:36:41 +0000 Subject: [PATCH 153/162] Update Dart Sass version and release --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ pubspec.lock | 46 +++++++++++++++++++++++----------------------- pubspec.yaml | 6 +++--- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cae5bed9..9bb9bca8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,38 @@ +## 1.59.0 + +### Command Line Interface + +* Added a new `--fatal-deprecation` flag that lets you treat a deprecation + warning as an error. You can pass an individual deprecation ID + (e.g. `slash-div`) or you can pass a Dart Sass version to treat all + deprecations initially emitted in that version or earlier as errors. + +* New `--future-deprecation` flag that lets you opt into warning for use of + certain features that will be deprecated in the future. At the moment, the + only option is `--future-deprecation=import`, which will emit warnings for + Sass `@import` rules, which are not yet deprecated, but will be in the future. + +### Dart API + +* New `Deprecation` enum, which contains the different current and future + deprecations used by the new CLI flags. + +* The `compile` methods now take in `fatalDeprecations` and `futureDeprecations` + parameters, which work similarly to the CLI flags. + +## 1.58.4 + +* Pull `@font-face` to the root rather than bubbling the style rule selector + inwards. + +* Improve error messages for invalid CSS values passed to plain CSS functions. + +* Improve error messages involving selectors. + +### Embedded Sass + +* Improve the performance of starting up a compilation. + ## 1.58.3 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index 05c8e9ed1..691bf5372 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "569ddca58d535e601dd1584afa117710abc999d036c0cd2c51777fb257df78e8" + sha256: "98d1d33ed129b372846e862de23a0fc365745f4d7b5e786ce667fcbbb7ac5c07" url: "https://pub.dev" source: hosted - version: "53.0.0" + version: "55.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "10927c4b7c7c88b1adbca278c3d5531db92e2f4b4abf04e2919a800af965f3f5" + sha256: "881348aed9b0b425882c97732629a6a31093c8ff20fc4b3b03fb9d3d50a3a126" url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.7.1" archive: dependency: transitive description: @@ -37,10 +37,10 @@ packages: dependency: "direct main" description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: "direct dev" description: name: cli_pkg - sha256: "977b0a29d838a0b18630f9c3ee83a8276a061c1715ef0b1040d4a63005c85431" + sha256: "2f5bdb861f152ec1c2251e51371600b69dce552ef2e8cf610bd0637be794b59b" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.0" cli_repl: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + sha256: "5be16bf1707658e4c03078d4a9b90208ded217fb02c163e207d334082412f2fb" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.5" file: dependency: transitive description: @@ -269,10 +269,10 @@ packages: dependency: transitive description: name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" package_config: dependency: transitive description: @@ -293,10 +293,10 @@ packages: dependency: transitive description: name: petitparser - sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + sha256: a9346a3fbba7546a28374bdbcd7f54ea48bb47772bf3a7ab4bfaadc40bc8b8c6 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.3.0" pointycastle: dependency: transitive description: @@ -341,10 +341,10 @@ packages: dependency: "direct dev" description: name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + sha256: ec85d7d55339d85f44ec2b682a82fea340071e8978257e5a43e69f79e98ef50c url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" retry: dependency: transitive description: @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: c3e37d50a372cee0fd4058b12f0167da8307c602ff8e357ebf587142b753b41a + sha256: cc169a52f627c41bf50b38c9977f3cc8bf10838a665c08648a3ae6f4281371e7 url: "https://pub.dev" source: hosted - version: "1.58.3" + version: "1.59.0" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "620d8d355e8396afe107b3e167b11524d757f3ca" + resolved-ref: "8f8138dfabbf48437d736b9bba7f481fac71ed3c" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: d4f402a63d06745c83415e5850022b2e2741b896b9fd6a50714bce509dc81c36 + sha256: f2f29f60971c215dceecd1ae05da39b3f2b6a77403e0cb02a2624c38bd592a38 url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "6.0.0" shelf: dependency: transitive description: @@ -534,10 +534,10 @@ packages: dependency: transitive description: name: vm_service - sha256: a4040e9852e56bf8a3c5a2e08a56f6facd76e75500cf2a922ce5d52394c4998a + sha256: eb3cf3f45fc1500ae30481ac9ab788302fa5e8edc3f3eaddf183945ee93a8bf3 url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "11.2.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7157bf0b3..68dd45ed1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.58.3 +version: 1.59.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.58.3 - sass_api: ^5.1.1 + sass: 1.59.0 + sass_api: ^6.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 9893512d4aa0aac50be2d771c4d1b052c3006d03 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Fri, 10 Mar 2023 23:48:10 +0000 Subject: [PATCH 154/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 10 +++++----- pubspec.yaml | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bb9bca8f..1ae8d52ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.59.1 + +* No user-visible changes. + ## 1.59.0 ### Command Line Interface diff --git a/pubspec.lock b/pubspec.lock index 691bf5372..8902736b6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: cc169a52f627c41bf50b38c9977f3cc8bf10838a665c08648a3ae6f4281371e7 + sha256: "8c6bc35c8cd8263dd3dddfb8b7e318645ad293f9c054f92b1c13e7d000b4b14f" url: "https://pub.dev" source: hosted - version: "1.59.0" + version: "1.59.1" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "8f8138dfabbf48437d736b9bba7f481fac71ed3c" + resolved-ref: d0ca8e0bc9f790a2b411728a07f9ec44b168c10e url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: f2f29f60971c215dceecd1ae05da39b3f2b6a77403e0cb02a2624c38bd592a38 + sha256: "7cbd35eb48ba8c9ebd6e0b4eedc6a239bb41057a92c243328b7a141d9c07a3bf" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.0.1" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 68dd45ed1..e58b9899e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.59.0 +version: 1.59.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.59.0 - sass_api: ^6.0.0 + sass: 1.59.1 + sass_api: ^6.0.1 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From c6752b5a3f8033e51ea5d13148e10963aaf1b274 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Fri, 10 Mar 2023 16:58:04 -0800 Subject: [PATCH 155/162] Revert "Remove workaround for dart-lang/setup-dart#59 (#151)" (#153) This reverts commit 7d38d428172d7384fa88cf01df048c45756ee9ae. --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c27091bc0..71f1f3bda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -256,16 +256,22 @@ jobs: include: - runner: macos-latest platform: macos-x64 + architecture: x64 - runner: self-hosted platform: macos-arm64 + architecture: arm64 - runner: windows-latest platform: windows + architecture: x64 steps: - uses: actions/checkout@v3 - uses: bufbuild/buf-setup-action@v1.13.1 with: {github_token: "${{ github.token }}"} - uses: dart-lang/setup-dart@v1 + # Workaround for dart-lang/setup-dart#59 + with: + architecture: ${{ matrix.architecture }} - run: dart pub get - run: dart run grinder protobuf - name: Deploy From a3e3d9b6d093c14503765db24a5216c27b9f0584 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Sat, 11 Mar 2023 01:20:46 +0000 Subject: [PATCH 156/162] Update Dart Sass version and release --- CHANGELOG.md | 4 ++++ pubspec.lock | 10 +++++----- pubspec.yaml | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae8d52ef..ebc7ec3f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.59.2 + +* No user-visible changes. + ## 1.59.1 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index 8902736b6..3aee81e2d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: "8c6bc35c8cd8263dd3dddfb8b7e318645ad293f9c054f92b1c13e7d000b4b14f" + sha256: "84c0634b18cd739abf799400ea9cfb26a74482a958b35f42a6bf0223dd121bea" url: "https://pub.dev" source: hosted - version: "1.59.1" + version: "1.59.2" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: d0ca8e0bc9f790a2b411728a07f9ec44b168c10e + resolved-ref: b540d5914e4d6f0d8942c5af6310cf89691eb7ce url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: "7cbd35eb48ba8c9ebd6e0b4eedc6a239bb41057a92c243328b7a141d9c07a3bf" + sha256: cd0d9bdf773627ba70a34a021feccbb8cf930f1316bff58a0f6e7d2e06c28c22 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.0.2" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e58b9899e..bd8e296f9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.59.1 +version: 1.59.2 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.59.1 - sass_api: ^6.0.1 + sass: 1.59.2 + sass_api: ^6.0.2 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 2d210a4d24496b4540c463c56521580d33d9ea3c Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 14 Mar 2023 21:21:23 +0000 Subject: [PATCH 157/162] Update Dart Sass version and release --- CHANGELOG.md | 10 ++++++++++ pubspec.lock | 18 +++++++++--------- pubspec.yaml | 6 +++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebc7ec3f8..4618111fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 1.59.3 + +* Fix a performance regression introduced in 1.59.0. + +* The NPM release of 1.59.0 dropped support for Node 12 without actually + indicating so in its pubspec. This release temporarily adds back support so + that the latest Sass version that declares it supports Node 12 actually does + so. However, Node 12 is now end-of-life, so we will drop support for it + properly in an upcoming release. + ## 1.59.2 * No user-visible changes. diff --git a/pubspec.lock b/pubspec.lock index 3aee81e2d..b491ec75b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: "direct dev" description: name: cli_pkg - sha256: "2f5bdb861f152ec1c2251e51371600b69dce552ef2e8cf610bd0637be794b59b" + sha256: "7ae1c54d9c2cefded0ff35838176c5160c31b7a20039f20c745e69ffadca3efd" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.2" cli_repl: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "5be16bf1707658e4c03078d4a9b90208ded217fb02c163e207d334082412f2fb" + sha256: "6d691edde054969f0e0f26abb1b30834b5138b963793e56f69d3a9a4435e6352" url: "https://pub.dev" source: hosted - version: "2.2.5" + version: "2.3.0" file: dependency: transitive description: @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: "84c0634b18cd739abf799400ea9cfb26a74482a958b35f42a6bf0223dd121bea" + sha256: "151282d9fe37369766f32f05332f74b98e4029f31032eae139e7d4b07b4a90ce" url: "https://pub.dev" source: hosted - version: "1.59.2" + version: "1.59.3" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: b540d5914e4d6f0d8942c5af6310cf89691eb7ce + resolved-ref: "09a5f09638b3d7a57f55907abcab624f98629d81" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: cd0d9bdf773627ba70a34a021feccbb8cf930f1316bff58a0f6e7d2e06c28c22 + sha256: d6aeef2a45783a35c011d9f1684d199d1dcd4ca9e39b9be73985d867b470b430 url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.0.3" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bd8e296f9..20b26126c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.59.2 +version: 1.59.3 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.59.2 - sass_api: ^6.0.2 + sass: 1.59.3 + sass_api: ^6.0.3 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 96a5ffe252f76f9e922c5a8daf5ce069373bc2bd Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 23 Mar 2023 23:13:50 +0000 Subject: [PATCH 158/162] Update Dart Sass version and release --- CHANGELOG.md | 12 ++++++++++++ pubspec.lock | 50 +++++++++++++++++++++++++------------------------- pubspec.yaml | 6 +++--- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4618111fe..2075cc82c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## 1.60.0 + +* Add support for the `pi`, `e`, `infinity`, `-infinity`, and `NaN` constants in + calculations. These will be interpreted as the corresponding numbers. + +* Add support for unknown constants in calculations. These will be interpreted + as unquoted strings. + +* Serialize numbers with value `infinity`, `-infinity`, and `NaN` to `calc()` + expressions rather than CSS-invalid identifiers. Numbers with complex units + still can't be serialized. + ## 1.59.3 * Fix a performance regression introduced in 1.59.0. diff --git a/pubspec.lock b/pubspec.lock index b491ec75b..c0a0d68ee 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "98d1d33ed129b372846e862de23a0fc365745f4d7b5e786ce667fcbbb7ac5c07" + sha256: d74f051467a841ce893a50ebeb420b7a5695f985d2781e22b3927fbc849aea45 url: "https://pub.dev" source: hosted - version: "55.0.0" + version: "57.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "881348aed9b0b425882c97732629a6a31093c8ff20fc4b3b03fb9d3d50a3a126" + sha256: b665679cdccab0c754e65021f01087c6fab07a0b13659dd58827f765739b40f8 url: "https://pub.dev" source: hosted - version: "5.7.1" + version: "5.9.0" archive: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: "direct dev" description: name: cli_pkg - sha256: "7ae1c54d9c2cefded0ff35838176c5160c31b7a20039f20c745e69ffadca3efd" + sha256: c5bae978235d16395df3c9bbc94c476bcfb90324795693f2f6a6e2e9aaac35e6 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" cli_repl: dependency: transitive description: @@ -237,18 +237,18 @@ packages: dependency: transitive description: name: matcher - sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.14" + version: "0.12.15" meta: dependency: "direct main" description: name: meta - sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" mime: dependency: transitive description: @@ -301,10 +301,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: c3120a968135aead39699267f4c74bc9a08e4e909e86bc1b0af5bfd78691123c url: "https://pub.dev" source: hosted - version: "3.6.2" + version: "3.7.2" pool: dependency: transitive description: @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: "151282d9fe37369766f32f05332f74b98e4029f31032eae139e7d4b07b4a90ce" + sha256: "050de6ed666d3f06a45da2c51eab5764c690766ee96b47b94944e582c93315b7" url: "https://pub.dev" source: hosted - version: "1.59.3" + version: "1.60.0" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "09a5f09638b3d7a57f55907abcab624f98629d81" + resolved-ref: c6e7dbc0cd75f9d50f4091f7a53f9f9e3c6cc2de url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: d6aeef2a45783a35c011d9f1684d199d1dcd4ca9e39b9be73985d867b470b430 + sha256: e79ebf557e5599f9f57850ce7b6af8af605e7487d4bfa396f0ba057661f2e2a1 url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.1.0" shelf: dependency: transitive description: @@ -478,26 +478,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "5301f54eb6fe945daa99bc8df6ece3f88b5ceaa6f996f250efdaaf63e22886be" + sha256: ce63f9d79c7b5ae87b8756b92deb0b78bdfb3a6421226b7cd03bf9e414d560ed url: "https://pub.dev" source: hosted - version: "1.23.1" + version: "1.24.0" test_api: dependency: transitive description: name: test_api - sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d" + sha256: "6b12a91cd2febdb6f7e7d92c00d1d0c01d88bffc7fe36b1ed236f0cc37cb5ca4" url: "https://pub.dev" source: hosted - version: "0.4.18" + version: "0.5.0" test_core: dependency: transitive description: name: test_core - sha256: d2e9240594b409565524802b84b7b39341da36dd6fd8e1660b53ad928ec3e9af + sha256: "4f44e9d888186f91f93ca581d6962424e796b9317acc3a1a997ab86753bf4717" url: "https://pub.dev" source: hosted - version: "0.4.24" + version: "0.5.0" test_descriptor: dependency: "direct dev" description: @@ -534,10 +534,10 @@ packages: dependency: transitive description: name: vm_service - sha256: eb3cf3f45fc1500ae30481ac9ab788302fa5e8edc3f3eaddf183945ee93a8bf3 + sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe url: "https://pub.dev" source: hosted - version: "11.2.0" + version: "11.3.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 20b26126c..d01b41cc7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.59.3 +version: 1.60.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.59.3 - sass_api: ^6.0.3 + sass: 1.60.0 + sass_api: ^6.1.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 0c76246e353d6f07527ca162e02dbe83c1692ba1 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Thu, 6 Apr 2023 21:55:44 +0000 Subject: [PATCH 159/162] Update Dart Sass version and release --- CHANGELOG.md | 11 +++++++++++ pubspec.lock | 42 +++++++++++++++++++++--------------------- pubspec.yaml | 6 +++--- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2075cc82c..446755ebb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## 1.61.0 + +* **Potentially breaking change:** Drop support for End-of-Life Node.js 12. + +* Fix remaining cases for the performance regression introduced in 1.59.0. + +### Embedded Sass + +* The JS embedded host now loads files from the working directory when using the + legacy API. + ## 1.60.0 * Add support for the `pi`, `e`, `infinity`, `-infinity`, and `NaN` constants in diff --git a/pubspec.lock b/pubspec.lock index c0a0d68ee..a2facf110 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: d74f051467a841ce893a50ebeb420b7a5695f985d2781e22b3927fbc849aea45 + sha256: a36ec4843dc30ea6bf652bf25e3448db6c5e8bcf4aa55f063a5d1dad216d8214 url: "https://pub.dev" source: hosted - version: "57.0.0" + version: "58.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: b665679cdccab0c754e65021f01087c6fab07a0b13659dd58827f765739b40f8 + sha256: cc4242565347e98424ce9945c819c192ec0838cb9d1f6aa4a97cc96becbc5b27 url: "https://pub.dev" source: hosted - version: "5.9.0" + version: "5.10.0" archive: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: "direct dev" description: name: cli_pkg - sha256: c5bae978235d16395df3c9bbc94c476bcfb90324795693f2f6a6e2e9aaac35e6 + sha256: "0f76b0ea3f158e9c68e3ae132e90435cfd094c507ae6aaeccb05bbc2ef758517" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.4" cli_repl: dependency: transitive description: @@ -349,24 +349,24 @@ packages: dependency: transitive description: name: retry - sha256: "45dfeebaf095b606fdb9dbfb4c114cc204449bc274783b452658365e03afdbab" + sha256: a8a1e475a100a0bdc73f529ca8ea1e9c9c76bec8ad86a1f47780139a34ce7aea url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" sass: dependency: "direct main" description: name: sass - sha256: "050de6ed666d3f06a45da2c51eab5764c690766ee96b47b94944e582c93315b7" + sha256: "3174cb19e5d655e57f814176b82510ea1ff964f0df6a6dec839f1912e250d36e" url: "https://pub.dev" source: hosted - version: "1.60.0" + version: "1.61.0" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: c6e7dbc0cd75f9d50f4091f7a53f9f9e3c6cc2de + resolved-ref: "702a7ee7a18c0265f8f90ff1155268e477dd77cf" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: e79ebf557e5599f9f57850ce7b6af8af605e7487d4bfa396f0ba057661f2e2a1 + sha256: "19a3bc0c3ad28d362c4d207557d06cd6aed89a94cf5d89681fa3b625f0904a27" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.0" shelf: dependency: transitive description: @@ -430,10 +430,10 @@ packages: dependency: "direct main" description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: "direct main" description: @@ -478,26 +478,26 @@ packages: dependency: "direct dev" description: name: test - sha256: ce63f9d79c7b5ae87b8756b92deb0b78bdfb3a6421226b7cd03bf9e414d560ed + sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" url: "https://pub.dev" source: hosted - version: "1.24.0" + version: "1.24.1" test_api: dependency: transitive description: name: test_api - sha256: "6b12a91cd2febdb6f7e7d92c00d1d0c01d88bffc7fe36b1ed236f0cc37cb5ca4" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.5.1" test_core: dependency: transitive description: name: test_core - sha256: "4f44e9d888186f91f93ca581d6962424e796b9317acc3a1a997ab86753bf4717" + sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.5.1" test_descriptor: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index d01b41cc7..053306c98 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.60.0 +version: 1.61.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.60.0 - sass_api: ^6.1.0 + sass: 1.61.0 + sass_api: ^6.2.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 6f1305cf659398b0d350340b805b05d66c2d7bd5 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 11 Apr 2023 22:56:34 +0000 Subject: [PATCH 160/162] Update Dart Sass version and release --- CHANGELOG.md | 13 +++++++++++++ pubspec.lock | 18 +++++++++--------- pubspec.yaml | 6 +++--- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 446755ebb..e7ab81f9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## 1.62.0 + +* Deprecate the use of multiple `!global` or `!default` flags on the same + variable. This deprecation is named `duplicate-var-flags`. + +* Allow special numbers like `var()` or `calc()` in the global functions: + `grayscale()`, `invert()`, `saturate()`, and `opacity()`. These are also + native CSS `filter` functions. This is in addition to number values which were + already allowed. + +* Fix a cosmetic bug where an outer rule could be duplicated after nesting was + resolved, instead of re-using a shared rule. + ## 1.61.0 * **Potentially breaking change:** Drop support for End-of-Life Node.js 12. diff --git a/pubspec.lock b/pubspec.lock index a2facf110..e240ff226 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.3.7" args: dependency: transitive description: @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: "3174cb19e5d655e57f814176b82510ea1ff964f0df6a6dec839f1912e250d36e" + sha256: "2ed4971a0b2acf0f5927e45988abe910cbebb467ba396503976d3556ee5af730" url: "https://pub.dev" source: hosted - version: "1.61.0" + version: "1.62.0" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: "702a7ee7a18c0265f8f90ff1155268e477dd77cf" + resolved-ref: c55235d166591e86ed342a1b5937b3d600e4d4de url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: "19a3bc0c3ad28d362c4d207557d06cd6aed89a94cf5d89681fa3b625f0904a27" + sha256: "712eeb6707214c9712eb5032a7e23c496f080a965c54e9e2b2efa885296fd3cb" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.3.0" shelf: dependency: transitive description: @@ -550,10 +550,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 053306c98..961e790a6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.61.0 +version: 1.62.0 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.61.0 - sass_api: ^6.2.0 + sass: 1.62.0 + sass_api: ^6.3.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 152754e291608d1846ad514599aec729a09490b4 Mon Sep 17 00:00:00 2001 From: Sass Bot Date: Tue, 25 Apr 2023 23:32:15 +0000 Subject: [PATCH 161/162] Update Dart Sass version and release --- CHANGELOG.md | 5 +++++ pubspec.lock | 42 +++++++++++++++++++++--------------------- pubspec.yaml | 6 +++--- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7ab81f9c..74dd0ba27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.62.1 + +* Fix a bug where `:has(+ &)` and related constructs would drop the leading + combinator. + ## 1.62.0 * Deprecate the use of multiple `!global` or `!default` flags on the same diff --git a/pubspec.lock b/pubspec.lock index e240ff226..9bafcb537 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: a36ec4843dc30ea6bf652bf25e3448db6c5e8bcf4aa55f063a5d1dad216d8214 + sha256: "8880b4cfe7b5b17d57c052a5a3a8cc1d4f546261c7cc8fbd717bd53f48db0568" url: "https://pub.dev" source: hosted - version: "58.0.0" + version: "59.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: cc4242565347e98424ce9945c819c192ec0838cb9d1f6aa4a97cc96becbc5b27 + sha256: a89627f49b0e70e068130a36571409726b04dab12da7e5625941d2c8ec278b96 url: "https://pub.dev" source: hosted - version: "5.10.0" + version: "5.11.1" archive: dependency: transitive description: @@ -293,18 +293,18 @@ packages: dependency: transitive description: name: petitparser - sha256: a9346a3fbba7546a28374bdbcd7f54ea48bb47772bf3a7ab4bfaadc40bc8b8c6 + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.4.0" pointycastle: dependency: transitive description: name: pointycastle - sha256: c3120a968135aead39699267f4c74bc9a08e4e909e86bc1b0af5bfd78691123c + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.7.2" + version: "3.7.3" pool: dependency: transitive description: @@ -357,16 +357,16 @@ packages: dependency: "direct main" description: name: sass - sha256: "2ed4971a0b2acf0f5927e45988abe910cbebb467ba396503976d3556ee5af730" + sha256: cb18c7093e4e6ebabba6efbcbb9926238ca9932e3bf6c553dc811a89e1524b28 url: "https://pub.dev" source: hosted - version: "1.62.0" + version: "1.62.1" sass_analysis: dependency: "direct dev" description: path: analysis ref: HEAD - resolved-ref: c55235d166591e86ed342a1b5937b3d600e4d4de + resolved-ref: "8dddcb7b7db13984fea69fa85438acf30b56b4bb" url: "https://github.com/sass/dart-sass.git" source: git version: "0.0.0" @@ -374,10 +374,10 @@ packages: dependency: "direct main" description: name: sass_api - sha256: "712eeb6707214c9712eb5032a7e23c496f080a965c54e9e2b2efa885296fd3cb" + sha256: "6901d0dd784a981946f7eb2cfc6cf2c3e24662230048375d28f4859797907052" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "7.0.0" shelf: dependency: transitive description: @@ -478,26 +478,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" + sha256: "4f92f103ef63b1bbac6f4bd1930624fca81b2574464482512c4f0896319be575" url: "https://pub.dev" source: hosted - version: "1.24.1" + version: "1.24.2" test_api: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: daadc9baabec998b062c9091525aa95786508b1c48e9c30f1f891b8bf6ff2e64 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.5.2" test_core: dependency: transitive description: name: test_core - sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" + sha256: "3642b184882f79e76ca57a9230fb971e494c3c1fd09c21ae3083ce891bcc0aa1" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.5.2" test_descriptor: dependency: "direct dev" description: @@ -534,10 +534,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe + sha256: "518254c0d3ee20667a1feef39eefe037df87439851e4b3cb277e5b3f37afa2f0" url: "https://pub.dev" source: hosted - version: "11.3.0" + version: "11.4.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 961e790a6..1cfd1d98e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass_embedded -version: 1.62.0 +version: 1.62.1 description: An implementation of the Sass embedded protocol using Dart Sass. homepage: https://github.com/sass/dart-sass-embedded environment: @@ -11,8 +11,8 @@ dependencies: meta: ^1.1.0 path: ^1.6.0 protobuf: ^2.0.0 - sass: 1.62.0 - sass_api: ^6.3.0 + sass: 1.62.1 + sass_api: ^7.0.0 source_span: ^1.1.0 stack_trace: ^1.6.0 stream_channel: ">=1.6.0 <3.0.0" From 3fc6a42e8fb684e4c226f653aaa126c3240641b7 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 8 May 2023 17:34:32 -0700 Subject: [PATCH 162/162] Move source and test files to namespaced subdirectories --- lib/src/{ => embedded}/dispatcher.dart | 0 lib/src/{ => embedded}/function_registry.dart | 0 lib/src/{ => embedded}/host_callable.dart | 0 lib/src/{ => embedded}/importer/base.dart | 0 lib/src/{ => embedded}/importer/file.dart | 0 lib/src/{ => embedded}/importer/host.dart | 0 lib/src/{ => embedded}/logger.dart | 0 lib/src/{ => embedded}/protofier.dart | 0 lib/src/{ => embedded}/util/length_delimited_transformer.dart | 0 lib/src/{ => embedded}/utils.dart | 0 lib/src/{ => embedded}/value.dart | 0 test/{ => embedded}/dependencies_test.dart | 0 test/{ => embedded}/embedded_process.dart | 0 test/{ => embedded}/file_importer_test.dart | 0 test/{ => embedded}/function_test.dart | 0 test/{ => embedded}/importer_test.dart | 0 test/{ => embedded}/length_delimited_test.dart | 0 test/{ => embedded}/protocol_test.dart | 0 test/{ => embedded}/utils.dart | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename lib/src/{ => embedded}/dispatcher.dart (100%) rename lib/src/{ => embedded}/function_registry.dart (100%) rename lib/src/{ => embedded}/host_callable.dart (100%) rename lib/src/{ => embedded}/importer/base.dart (100%) rename lib/src/{ => embedded}/importer/file.dart (100%) rename lib/src/{ => embedded}/importer/host.dart (100%) rename lib/src/{ => embedded}/logger.dart (100%) rename lib/src/{ => embedded}/protofier.dart (100%) rename lib/src/{ => embedded}/util/length_delimited_transformer.dart (100%) rename lib/src/{ => embedded}/utils.dart (100%) rename lib/src/{ => embedded}/value.dart (100%) rename test/{ => embedded}/dependencies_test.dart (100%) rename test/{ => embedded}/embedded_process.dart (100%) rename test/{ => embedded}/file_importer_test.dart (100%) rename test/{ => embedded}/function_test.dart (100%) rename test/{ => embedded}/importer_test.dart (100%) rename test/{ => embedded}/length_delimited_test.dart (100%) rename test/{ => embedded}/protocol_test.dart (100%) rename test/{ => embedded}/utils.dart (100%) diff --git a/lib/src/dispatcher.dart b/lib/src/embedded/dispatcher.dart similarity index 100% rename from lib/src/dispatcher.dart rename to lib/src/embedded/dispatcher.dart diff --git a/lib/src/function_registry.dart b/lib/src/embedded/function_registry.dart similarity index 100% rename from lib/src/function_registry.dart rename to lib/src/embedded/function_registry.dart diff --git a/lib/src/host_callable.dart b/lib/src/embedded/host_callable.dart similarity index 100% rename from lib/src/host_callable.dart rename to lib/src/embedded/host_callable.dart diff --git a/lib/src/importer/base.dart b/lib/src/embedded/importer/base.dart similarity index 100% rename from lib/src/importer/base.dart rename to lib/src/embedded/importer/base.dart diff --git a/lib/src/importer/file.dart b/lib/src/embedded/importer/file.dart similarity index 100% rename from lib/src/importer/file.dart rename to lib/src/embedded/importer/file.dart diff --git a/lib/src/importer/host.dart b/lib/src/embedded/importer/host.dart similarity index 100% rename from lib/src/importer/host.dart rename to lib/src/embedded/importer/host.dart diff --git a/lib/src/logger.dart b/lib/src/embedded/logger.dart similarity index 100% rename from lib/src/logger.dart rename to lib/src/embedded/logger.dart diff --git a/lib/src/protofier.dart b/lib/src/embedded/protofier.dart similarity index 100% rename from lib/src/protofier.dart rename to lib/src/embedded/protofier.dart diff --git a/lib/src/util/length_delimited_transformer.dart b/lib/src/embedded/util/length_delimited_transformer.dart similarity index 100% rename from lib/src/util/length_delimited_transformer.dart rename to lib/src/embedded/util/length_delimited_transformer.dart diff --git a/lib/src/utils.dart b/lib/src/embedded/utils.dart similarity index 100% rename from lib/src/utils.dart rename to lib/src/embedded/utils.dart diff --git a/lib/src/value.dart b/lib/src/embedded/value.dart similarity index 100% rename from lib/src/value.dart rename to lib/src/embedded/value.dart diff --git a/test/dependencies_test.dart b/test/embedded/dependencies_test.dart similarity index 100% rename from test/dependencies_test.dart rename to test/embedded/dependencies_test.dart diff --git a/test/embedded_process.dart b/test/embedded/embedded_process.dart similarity index 100% rename from test/embedded_process.dart rename to test/embedded/embedded_process.dart diff --git a/test/file_importer_test.dart b/test/embedded/file_importer_test.dart similarity index 100% rename from test/file_importer_test.dart rename to test/embedded/file_importer_test.dart diff --git a/test/function_test.dart b/test/embedded/function_test.dart similarity index 100% rename from test/function_test.dart rename to test/embedded/function_test.dart diff --git a/test/importer_test.dart b/test/embedded/importer_test.dart similarity index 100% rename from test/importer_test.dart rename to test/embedded/importer_test.dart diff --git a/test/length_delimited_test.dart b/test/embedded/length_delimited_test.dart similarity index 100% rename from test/length_delimited_test.dart rename to test/embedded/length_delimited_test.dart diff --git a/test/protocol_test.dart b/test/embedded/protocol_test.dart similarity index 100% rename from test/protocol_test.dart rename to test/embedded/protocol_test.dart diff --git a/test/utils.dart b/test/embedded/utils.dart similarity index 100% rename from test/utils.dart rename to test/embedded/utils.dart