From f1d4dba23589e011eb86ad492afcfee668b263f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Wed, 16 Nov 2022 21:16:51 -0800 Subject: [PATCH 1/6] Add a factory method for creating host callable --- lib/src/callable.dart | 13 +++++++++++ lib/src/callable/async.dart | 14 +++++++++++ lib/src/node/compile.dart | 35 +++++++++------------------- lib/src/node/legacy.dart | 30 +++++++----------------- lib/src/util/function_signature.dart | 28 ++++++++++++++++++++++ 5 files changed, 74 insertions(+), 46 deletions(-) create mode 100644 lib/src/util/function_signature.dart diff --git a/lib/src/callable.dart b/lib/src/callable.dart index 7f8b0c383..3125f70ca 100644 --- a/lib/src/callable.dart +++ b/lib/src/callable.dart @@ -3,10 +3,13 @@ // https://opensource.org/licenses/MIT. import 'package:meta/meta.dart'; +import 'package:tuple/tuple.dart'; +import 'ast/sass.dart'; import 'callable/async.dart'; import 'callable/built_in.dart'; import 'exception.dart'; +import 'util/function_signature.dart'; import 'value.dart'; export 'callable/async.dart'; @@ -117,4 +120,14 @@ abstract class Callable extends AsyncCallable { factory Callable.function(String name, String arguments, Value callback(List arguments)) => BuiltInCallable.function(name, arguments, callback); + + /// Creates a host callable with a single [signature] and a single [callback]. + /// + /// Throws a [SassFormatException] if parsing fails. + factory Callable.host(String signature, Value callback(List arguments), + {bool requireParens = true}) { + Tuple2 tuple = + parseSignature(signature, requireParens: requireParens); + return BuiltInCallable.parsed(tuple.item1, tuple.item2, callback); + } } diff --git a/lib/src/callable/async.dart b/lib/src/callable/async.dart index 28965bc80..f382d5039 100644 --- a/lib/src/callable/async.dart +++ b/lib/src/callable/async.dart @@ -5,8 +5,11 @@ import 'dart:async'; import 'package:meta/meta.dart'; +import 'package:tuple/tuple.dart'; +import '../ast/sass.dart'; import '../exception.dart'; +import '../util/function_signature.dart'; import '../value.dart'; import 'async_built_in.dart'; @@ -40,4 +43,15 @@ abstract class AsyncCallable { factory AsyncCallable.function(String name, String arguments, FutureOr callback(List arguments)) => AsyncBuiltInCallable.function(name, arguments, callback); + + /// Creates a host callable with a single [signature] and a single [callback]. + /// + /// Throws a [SassFormatException] if parsing fails. + factory AsyncCallable.host( + String signature, FutureOr callback(List arguments), + {bool requireParens = true}) { + Tuple2 tuple = + parseSignature(signature, requireParens: requireParens); + return AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2, callback); + } } diff --git a/lib/src/node/compile.dart b/lib/src/node/compile.dart index ebbd55add..78ba0ddb6 100644 --- a/lib/src/node/compile.dart +++ b/lib/src/node/compile.dart @@ -6,12 +6,8 @@ import 'package:js/js.dart'; import 'package:node_interop/js.dart'; import 'package:node_interop/util.dart' hide futureToPromise; import 'package:term_glyph/term_glyph.dart' as glyph; -import 'package:tuple/tuple.dart'; import '../../sass.dart'; -import '../ast/sass.dart'; -import '../callable.dart'; -import '../exception.dart'; import '../importer/no_op.dart'; import '../importer/node_to_dart/async.dart'; import '../importer/node_to_dart/async_file.dart'; @@ -19,9 +15,7 @@ import '../importer/node_to_dart/file.dart'; import '../importer/node_to_dart/sync.dart'; import '../io.dart'; import '../logger/node_to_dart.dart'; -import '../parse/scss.dart'; import '../util/nullable.dart'; -import '../utils.dart'; import 'compile_options.dart'; import 'compile_result.dart'; import 'exception.dart'; @@ -236,33 +230,25 @@ List _parseFunctions(Object? functions, {bool asynch = false}) { var result = []; jsForEach(functions, (signature, callback) { - Tuple2 tuple; - try { - tuple = ScssParser(signature).parseSignature(); - } on SassFormatException catch (error, stackTrace) { - throwWithTrace( - SassFormatException( - 'Invalid signature "$signature": ${error.message}', error.span), - stackTrace); - } - if (!asynch) { - result.add(BuiltInCallable.parsed(tuple.item1, tuple.item2, (arguments) { + Callable? callable; + callable = Callable.host(signature, (arguments) { var result = (callback as Function)(toJSArray(arguments)); if (result is Value) return result; if (isPromise(result)) { throw 'Invalid return value for custom function ' - '"${tuple.item1}":\n' + '"${callable!.name}":\n' 'Promises may only be returned for sass.compileAsync() and ' 'sass.compileStringAsync().'; } else { throw 'Invalid return value for custom function ' - '"${tuple.item1}": $result is not a sass.Value.'; + '"${callable!.name}": $result is not a sass.Value.'; } - })); + }); + result.add(callable); } else { - result.add(AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2, - (arguments) async { + AsyncCallable? callable; + callable = AsyncCallable.host(signature, (arguments) async { var result = (callback as Function)(toJSArray(arguments)); if (isPromise(result)) { result = await promiseToFuture(result as Promise); @@ -270,8 +256,9 @@ List _parseFunctions(Object? functions, {bool asynch = false}) { if (result is Value) return result; throw 'Invalid return value for custom function ' - '"${tuple.item1}": $result is not a sass.Value.'; - })); + '"${callable!.name}": $result is not a sass.Value.'; + }); + result.add(callable); } }); return result; diff --git a/lib/src/node/legacy.dart b/lib/src/node/legacy.dart index e310a8de5..d39204c26 100644 --- a/lib/src/node/legacy.dart +++ b/lib/src/node/legacy.dart @@ -10,9 +10,7 @@ import 'dart:typed_data'; import 'package:js/js.dart'; import 'package:node_interop/js.dart'; import 'package:path/path.dart' as p; -import 'package:tuple/tuple.dart'; -import '../ast/sass.dart'; import '../callable.dart'; import '../compile.dart'; import '../compile_result.dart'; @@ -21,7 +19,6 @@ import '../importer/legacy_node.dart'; import '../io.dart'; import '../logger.dart'; import '../logger/node_to_dart.dart'; -import '../parse/scss.dart'; import '../syntax.dart'; import '../util/nullable.dart'; import '../utils.dart'; @@ -208,22 +205,12 @@ List _parseFunctions(RenderOptions options, DateTime start, var result = []; jsForEach(functions, (signature, callback) { - Tuple2 tuple; - try { - tuple = ScssParser(signature).parseSignature(requireParens: false); - } on SassFormatException catch (error, stackTrace) { - throwWithTrace( - SassFormatException( - 'Invalid signature "$signature": ${error.message}', error.span), - stackTrace); - } - var context = RenderContext(options: _contextOptions(options, start)); context.options.context = context; var fiber = options.fiber; if (fiber != null) { - result.add(BuiltInCallable.parsed(tuple.item1, tuple.item2, (arguments) { + result.add(Callable.host(signature, (arguments) { var currentFiber = fiber.current; var jsArguments = [ ...arguments.map(wrapValue), @@ -240,16 +227,15 @@ List _parseFunctions(RenderOptions options, DateTime start, // `Zone.current` in an inconsistent state. ? runZoned(() => fiber.yield()) : result); - })); + }, requireParens: false)); } else if (!asynch) { - result.add(BuiltInCallable.parsed( - tuple.item1, - tuple.item2, + result.add(Callable.host( + signature, (arguments) => unwrapValue((callback as JSFunction) - .apply(context, arguments.map(wrapValue).toList())))); + .apply(context, arguments.map(wrapValue).toList())), + requireParens: false)); } else { - result.add(AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2, - (arguments) async { + result.add(AsyncCallable.host(signature, (arguments) async { var completer = Completer(); var jsArguments = [ ...arguments.map(wrapValue), @@ -258,7 +244,7 @@ List _parseFunctions(RenderOptions options, DateTime start, var result = (callback as JSFunction).apply(context, jsArguments); return unwrapValue( isUndefined(result) ? await completer.future : result); - })); + }, requireParens: false)); } }); return result; diff --git a/lib/src/util/function_signature.dart b/lib/src/util/function_signature.dart new file mode 100644 index 000000000..f1983ac93 --- /dev/null +++ b/lib/src/util/function_signature.dart @@ -0,0 +1,28 @@ +// Copyright 2022 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:tuple/tuple.dart'; + +import '../ast/sass.dart'; +import '../exception.dart'; +import '../parse/scss.dart'; +import '../utils.dart'; + +/// Parses a function signature of the format allowed by Node Sass's functions +/// option and returns its name and declaration. +/// +/// If [requireParens] is `false`, this allows parentheses to be omitted. +/// +/// Throws a [SassFormatException] if parsing fails. +Tuple2 parseSignature(String signature, + {bool requireParens = true}) { + try { + return ScssParser(signature).parseSignature(requireParens: requireParens); + } on SassFormatException catch (error, stackTrace) { + throwWithTrace( + SassFormatException( + 'Invalid signature "$signature": ${error.message}', error.span), + stackTrace); + } +} From 6c2f02435ebbc29f20a9e532e48d1708944ecfa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AA=E3=81=A4=E3=81=8D?= Date: Thu, 1 Dec 2022 03:26:07 +0000 Subject: [PATCH 2/6] Address review feedbacks --- lib/src/callable.dart | 5 +++-- lib/src/callable/async.dart | 4 ++-- lib/src/node/compile.dart | 14 +++++++------- lib/src/node/legacy.dart | 6 +++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/src/callable.dart b/lib/src/callable.dart index 3125f70ca..9f4a0bea2 100644 --- a/lib/src/callable.dart +++ b/lib/src/callable.dart @@ -121,10 +121,11 @@ abstract class Callable extends AsyncCallable { Value callback(List arguments)) => BuiltInCallable.function(name, arguments, callback); - /// Creates a host callable with a single [signature] and a single [callback]. + /// Creates a callable with a single [signature] and a single [callback]. /// /// Throws a [SassFormatException] if parsing fails. - factory Callable.host(String signature, Value callback(List arguments), + factory Callable.fromSignature( + String signature, Value callback(List arguments), {bool requireParens = true}) { Tuple2 tuple = parseSignature(signature, requireParens: requireParens); diff --git a/lib/src/callable/async.dart b/lib/src/callable/async.dart index f382d5039..543c39bbc 100644 --- a/lib/src/callable/async.dart +++ b/lib/src/callable/async.dart @@ -44,10 +44,10 @@ abstract class AsyncCallable { FutureOr callback(List arguments)) => AsyncBuiltInCallable.function(name, arguments, callback); - /// Creates a host callable with a single [signature] and a single [callback]. + /// Creates a callable with a single [signature] and a single [callback]. /// /// Throws a [SassFormatException] if parsing fails. - factory AsyncCallable.host( + factory AsyncCallable.fromSignature( String signature, FutureOr callback(List arguments), {bool requireParens = true}) { Tuple2 tuple = diff --git a/lib/src/node/compile.dart b/lib/src/node/compile.dart index 78ba0ddb6..a5a5e50f2 100644 --- a/lib/src/node/compile.dart +++ b/lib/src/node/compile.dart @@ -231,24 +231,24 @@ List _parseFunctions(Object? functions, {bool asynch = false}) { var result = []; jsForEach(functions, (signature, callback) { if (!asynch) { - Callable? callable; - callable = Callable.host(signature, (arguments) { + late Callable callable; + callable = Callable.fromSignature(signature, (arguments) { var result = (callback as Function)(toJSArray(arguments)); if (result is Value) return result; if (isPromise(result)) { throw 'Invalid return value for custom function ' - '"${callable!.name}":\n' + '"${callable.name}":\n' 'Promises may only be returned for sass.compileAsync() and ' 'sass.compileStringAsync().'; } else { throw 'Invalid return value for custom function ' - '"${callable!.name}": $result is not a sass.Value.'; + '"${callable.name}": $result is not a sass.Value.'; } }); result.add(callable); } else { - AsyncCallable? callable; - callable = AsyncCallable.host(signature, (arguments) async { + late AsyncCallable callable; + callable = AsyncCallable.fromSignature(signature, (arguments) async { var result = (callback as Function)(toJSArray(arguments)); if (isPromise(result)) { result = await promiseToFuture(result as Promise); @@ -256,7 +256,7 @@ List _parseFunctions(Object? functions, {bool asynch = false}) { if (result is Value) return result; throw 'Invalid return value for custom function ' - '"${callable!.name}": $result is not a sass.Value.'; + '"${callable.name}": $result is not a sass.Value.'; }); result.add(callable); } diff --git a/lib/src/node/legacy.dart b/lib/src/node/legacy.dart index d39204c26..1fe86d11f 100644 --- a/lib/src/node/legacy.dart +++ b/lib/src/node/legacy.dart @@ -210,7 +210,7 @@ List _parseFunctions(RenderOptions options, DateTime start, var fiber = options.fiber; if (fiber != null) { - result.add(Callable.host(signature, (arguments) { + result.add(Callable.fromSignature(signature, (arguments) { var currentFiber = fiber.current; var jsArguments = [ ...arguments.map(wrapValue), @@ -229,13 +229,13 @@ List _parseFunctions(RenderOptions options, DateTime start, : result); }, requireParens: false)); } else if (!asynch) { - result.add(Callable.host( + result.add(Callable.fromSignature( signature, (arguments) => unwrapValue((callback as JSFunction) .apply(context, arguments.map(wrapValue).toList())), requireParens: false)); } else { - result.add(AsyncCallable.host(signature, (arguments) async { + result.add(AsyncCallable.fromSignature(signature, (arguments) async { var completer = Completer(); var jsArguments = [ ...arguments.map(wrapValue), From cccb4d4e875a551e4207a322fb9822052a37768c 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 04:30:34 +0000 Subject: [PATCH 3/6] Address review feedbacks --- lib/src/callable.dart | 2 +- lib/src/callable/async.dart | 2 +- lib/src/util/function_signature.dart | 28 ---------------------------- lib/src/utils.dart | 22 ++++++++++++++++++++++ 4 files changed, 24 insertions(+), 30 deletions(-) delete mode 100644 lib/src/util/function_signature.dart diff --git a/lib/src/callable.dart b/lib/src/callable.dart index 9f4a0bea2..28f65c2b1 100644 --- a/lib/src/callable.dart +++ b/lib/src/callable.dart @@ -9,7 +9,7 @@ import 'ast/sass.dart'; import 'callable/async.dart'; import 'callable/built_in.dart'; import 'exception.dart'; -import 'util/function_signature.dart'; +import 'utils.dart'; import 'value.dart'; export 'callable/async.dart'; diff --git a/lib/src/callable/async.dart b/lib/src/callable/async.dart index 543c39bbc..7a77d243a 100644 --- a/lib/src/callable/async.dart +++ b/lib/src/callable/async.dart @@ -9,7 +9,7 @@ import 'package:tuple/tuple.dart'; import '../ast/sass.dart'; import '../exception.dart'; -import '../util/function_signature.dart'; +import '../utils.dart'; import '../value.dart'; import 'async_built_in.dart'; diff --git a/lib/src/util/function_signature.dart b/lib/src/util/function_signature.dart deleted file mode 100644 index f1983ac93..000000000 --- a/lib/src/util/function_signature.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 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:tuple/tuple.dart'; - -import '../ast/sass.dart'; -import '../exception.dart'; -import '../parse/scss.dart'; -import '../utils.dart'; - -/// Parses a function signature of the format allowed by Node Sass's functions -/// option and returns its name and declaration. -/// -/// If [requireParens] is `false`, this allows parentheses to be omitted. -/// -/// Throws a [SassFormatException] if parsing fails. -Tuple2 parseSignature(String signature, - {bool requireParens = true}) { - try { - return ScssParser(signature).parseSignature(requireParens: requireParens); - } on SassFormatException catch (error, stackTrace) { - throwWithTrace( - SassFormatException( - 'Invalid signature "$signature": ${error.message}', error.span), - stackTrace); - } -} diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 20f12fcc6..295f753db 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -10,7 +10,11 @@ import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:string_scanner/string_scanner.dart'; import 'package:term_glyph/term_glyph.dart' as glyph; +import 'package:tuple/tuple.dart'; +import 'ast/sass.dart'; +import 'exception.dart'; +import 'parse/scss.dart'; import 'util/character.dart'; /// The URL used in stack traces when no source URL is available. @@ -469,3 +473,21 @@ extension IterableExtension on Iterable { return take(size); } } + +/// Parses a function signature of the format allowed by Node Sass's functions +/// option and returns its name and declaration. +/// +/// If [requireParens] is `false`, this allows parentheses to be omitted. +/// +/// Throws a [SassFormatException] if parsing fails. +Tuple2 parseSignature(String signature, + {bool requireParens = true}) { + try { + return ScssParser(signature).parseSignature(requireParens: requireParens); + } on SassFormatException catch (error, stackTrace) { + throwWithTrace( + SassFormatException( + 'Invalid signature "$signature": ${error.message}', error.span), + stackTrace); + } +} From 800274bc6bb31aca889e299782210810bf42881a 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 10:41:52 -0800 Subject: [PATCH 4/6] Trigger CI From af0ee0f0a36e4bde3adb4d0be81e9c02ecf8a6b7 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 8 Dec 2022 11:50:40 -0800 Subject: [PATCH 5/6] Update the pubspec and changelog --- CHANGELOG.md | 7 +++++++ pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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.yaml b/pubspec.yaml index b20562378..36f86e43f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.56.1 +version: 1.56.2 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass From eddddfe42dfb16d233c6a59d340e010c286acf9d Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 8 Dec 2022 11:59:05 -0800 Subject: [PATCH 6/6] Update sass_api --- pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 1155f85eb..8e8476613 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.1.2 + +* No user-visible changes. + ## 4.1.1 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 8a3e401ed..e4a69ccaa 100644 --- a/pkg/sass_api/pubspec.yaml +++ b/pkg/sass_api/pubspec.yaml @@ -2,7 +2,7 @@ name: sass_api # Note: Every time we add a new Sass AST node, we need to bump the *major* # version because it's a breaking change for anyone who's implementing the # visitor interface(s). -version: 4.1.1 +version: 4.1.2 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=2.17.0 <3.0.0" dependencies: - sass: 1.56.1 + sass: 1.56.2 dev_dependencies: dartdoc: ^5.0.0