mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
Add a factory method for creating host callable (#1829)
Co-authored-by: Natalie Weizenbaum <nweiz@google.com>
This commit is contained in:
parent
790eb8a933
commit
e87176a52a
@ -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
|
||||
|
@ -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 'utils.dart';
|
||||
import 'value.dart';
|
||||
|
||||
export 'callable/async.dart';
|
||||
@ -117,4 +120,15 @@ abstract class Callable extends AsyncCallable {
|
||||
factory Callable.function(String name, String arguments,
|
||||
Value callback(List<Value> arguments)) =>
|
||||
BuiltInCallable.function(name, arguments, callback);
|
||||
|
||||
/// Creates a callable with a single [signature] and a single [callback].
|
||||
///
|
||||
/// Throws a [SassFormatException] if parsing fails.
|
||||
factory Callable.fromSignature(
|
||||
String signature, Value callback(List<Value> arguments),
|
||||
{bool requireParens = true}) {
|
||||
Tuple2<String, ArgumentDeclaration> tuple =
|
||||
parseSignature(signature, requireParens: requireParens);
|
||||
return BuiltInCallable.parsed(tuple.item1, tuple.item2, callback);
|
||||
}
|
||||
}
|
||||
|
@ -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 '../utils.dart';
|
||||
import '../value.dart';
|
||||
import 'async_built_in.dart';
|
||||
|
||||
@ -40,4 +43,15 @@ abstract class AsyncCallable {
|
||||
factory AsyncCallable.function(String name, String arguments,
|
||||
FutureOr<Value> callback(List<Value> arguments)) =>
|
||||
AsyncBuiltInCallable.function(name, arguments, callback);
|
||||
|
||||
/// Creates a callable with a single [signature] and a single [callback].
|
||||
///
|
||||
/// Throws a [SassFormatException] if parsing fails.
|
||||
factory AsyncCallable.fromSignature(
|
||||
String signature, FutureOr<Value> callback(List<Value> arguments),
|
||||
{bool requireParens = true}) {
|
||||
Tuple2<String, ArgumentDeclaration> tuple =
|
||||
parseSignature(signature, requireParens: requireParens);
|
||||
return AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2, callback);
|
||||
}
|
||||
}
|
||||
|
@ -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<AsyncCallable> _parseFunctions(Object? functions, {bool asynch = false}) {
|
||||
|
||||
var result = <AsyncCallable>[];
|
||||
jsForEach(functions, (signature, callback) {
|
||||
Tuple2<String, ArgumentDeclaration> 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) {
|
||||
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 '
|
||||
'"${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 {
|
||||
late AsyncCallable callable;
|
||||
callable = AsyncCallable.fromSignature(signature, (arguments) async {
|
||||
var result = (callback as Function)(toJSArray(arguments));
|
||||
if (isPromise(result)) {
|
||||
result = await promiseToFuture<Object>(result as Promise);
|
||||
@ -270,8 +256,9 @@ List<AsyncCallable> _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;
|
||||
|
@ -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<AsyncCallable> _parseFunctions(RenderOptions options, DateTime start,
|
||||
|
||||
var result = <AsyncCallable>[];
|
||||
jsForEach(functions, (signature, callback) {
|
||||
Tuple2<String, ArgumentDeclaration> 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.fromSignature(signature, (arguments) {
|
||||
var currentFiber = fiber.current;
|
||||
var jsArguments = [
|
||||
...arguments.map(wrapValue),
|
||||
@ -240,16 +227,15 @@ List<AsyncCallable> _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.fromSignature(
|
||||
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.fromSignature(signature, (arguments) async {
|
||||
var completer = Completer<Object?>();
|
||||
var jsArguments = [
|
||||
...arguments.map(wrapValue),
|
||||
@ -258,7 +244,7 @@ List<AsyncCallable> _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;
|
||||
|
@ -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<E> on Iterable<E> {
|
||||
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<String, ArgumentDeclaration> 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);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
## 4.1.2
|
||||
|
||||
* No user-visible changes.
|
||||
|
||||
## 4.1.1
|
||||
|
||||
* No user-visible changes.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user