Skip to content

Commit e87176a

Browse files
ntkmenex3
andauthored
Add a factory method for creating host callable (#1829)
Co-authored-by: Natalie Weizenbaum <[email protected]>
1 parent 790eb8a commit e87176a

File tree

9 files changed

+83
-49
lines changed

9 files changed

+83
-49
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.56.2
2+
3+
### Embedded Sass
4+
5+
* The embedded compiler now supports version 1.2.0 of [the embedded
6+
protocol](https://github.com/sass/embedded-protocol).
7+
18
## 1.56.1
29

310
### Embedded Sass

lib/src/callable.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
// https://opensource.org/licenses/MIT.
44

55
import 'package:meta/meta.dart';
6+
import 'package:tuple/tuple.dart';
67

8+
import 'ast/sass.dart';
79
import 'callable/async.dart';
810
import 'callable/built_in.dart';
911
import 'exception.dart';
12+
import 'utils.dart';
1013
import 'value.dart';
1114

1215
export 'callable/async.dart';
@@ -117,4 +120,15 @@ abstract class Callable extends AsyncCallable {
117120
factory Callable.function(String name, String arguments,
118121
Value callback(List<Value> arguments)) =>
119122
BuiltInCallable.function(name, arguments, callback);
123+
124+
/// Creates a callable with a single [signature] and a single [callback].
125+
///
126+
/// Throws a [SassFormatException] if parsing fails.
127+
factory Callable.fromSignature(
128+
String signature, Value callback(List<Value> arguments),
129+
{bool requireParens = true}) {
130+
Tuple2<String, ArgumentDeclaration> tuple =
131+
parseSignature(signature, requireParens: requireParens);
132+
return BuiltInCallable.parsed(tuple.item1, tuple.item2, callback);
133+
}
120134
}

lib/src/callable/async.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
import 'dart:async';
66

77
import 'package:meta/meta.dart';
8+
import 'package:tuple/tuple.dart';
89

10+
import '../ast/sass.dart';
911
import '../exception.dart';
12+
import '../utils.dart';
1013
import '../value.dart';
1114
import 'async_built_in.dart';
1215

@@ -40,4 +43,15 @@ abstract class AsyncCallable {
4043
factory AsyncCallable.function(String name, String arguments,
4144
FutureOr<Value> callback(List<Value> arguments)) =>
4245
AsyncBuiltInCallable.function(name, arguments, callback);
46+
47+
/// Creates a callable with a single [signature] and a single [callback].
48+
///
49+
/// Throws a [SassFormatException] if parsing fails.
50+
factory AsyncCallable.fromSignature(
51+
String signature, FutureOr<Value> callback(List<Value> arguments),
52+
{bool requireParens = true}) {
53+
Tuple2<String, ArgumentDeclaration> tuple =
54+
parseSignature(signature, requireParens: requireParens);
55+
return AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2, callback);
56+
}
4357
}

lib/src/node/compile.dart

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,16 @@ import 'package:js/js.dart';
66
import 'package:node_interop/js.dart';
77
import 'package:node_interop/util.dart' hide futureToPromise;
88
import 'package:term_glyph/term_glyph.dart' as glyph;
9-
import 'package:tuple/tuple.dart';
109

1110
import '../../sass.dart';
12-
import '../ast/sass.dart';
13-
import '../callable.dart';
14-
import '../exception.dart';
1511
import '../importer/no_op.dart';
1612
import '../importer/node_to_dart/async.dart';
1713
import '../importer/node_to_dart/async_file.dart';
1814
import '../importer/node_to_dart/file.dart';
1915
import '../importer/node_to_dart/sync.dart';
2016
import '../io.dart';
2117
import '../logger/node_to_dart.dart';
22-
import '../parse/scss.dart';
2318
import '../util/nullable.dart';
24-
import '../utils.dart';
2519
import 'compile_options.dart';
2620
import 'compile_result.dart';
2721
import 'exception.dart';
@@ -236,42 +230,35 @@ List<AsyncCallable> _parseFunctions(Object? functions, {bool asynch = false}) {
236230

237231
var result = <AsyncCallable>[];
238232
jsForEach(functions, (signature, callback) {
239-
Tuple2<String, ArgumentDeclaration> tuple;
240-
try {
241-
tuple = ScssParser(signature).parseSignature();
242-
} on SassFormatException catch (error, stackTrace) {
243-
throwWithTrace(
244-
SassFormatException(
245-
'Invalid signature "$signature": ${error.message}', error.span),
246-
stackTrace);
247-
}
248-
249233
if (!asynch) {
250-
result.add(BuiltInCallable.parsed(tuple.item1, tuple.item2, (arguments) {
234+
late Callable callable;
235+
callable = Callable.fromSignature(signature, (arguments) {
251236
var result = (callback as Function)(toJSArray(arguments));
252237
if (result is Value) return result;
253238
if (isPromise(result)) {
254239
throw 'Invalid return value for custom function '
255-
'"${tuple.item1}":\n'
240+
'"${callable.name}":\n'
256241
'Promises may only be returned for sass.compileAsync() and '
257242
'sass.compileStringAsync().';
258243
} else {
259244
throw 'Invalid return value for custom function '
260-
'"${tuple.item1}": $result is not a sass.Value.';
245+
'"${callable.name}": $result is not a sass.Value.';
261246
}
262-
}));
247+
});
248+
result.add(callable);
263249
} else {
264-
result.add(AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2,
265-
(arguments) async {
250+
late AsyncCallable callable;
251+
callable = AsyncCallable.fromSignature(signature, (arguments) async {
266252
var result = (callback as Function)(toJSArray(arguments));
267253
if (isPromise(result)) {
268254
result = await promiseToFuture<Object>(result as Promise);
269255
}
270256

271257
if (result is Value) return result;
272258
throw 'Invalid return value for custom function '
273-
'"${tuple.item1}": $result is not a sass.Value.';
274-
}));
259+
'"${callable.name}": $result is not a sass.Value.';
260+
});
261+
result.add(callable);
275262
}
276263
});
277264
return result;

lib/src/node/legacy.dart

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import 'dart:typed_data';
1010
import 'package:js/js.dart';
1111
import 'package:node_interop/js.dart';
1212
import 'package:path/path.dart' as p;
13-
import 'package:tuple/tuple.dart';
1413

15-
import '../ast/sass.dart';
1614
import '../callable.dart';
1715
import '../compile.dart';
1816
import '../compile_result.dart';
@@ -21,7 +19,6 @@ import '../importer/legacy_node.dart';
2119
import '../io.dart';
2220
import '../logger.dart';
2321
import '../logger/node_to_dart.dart';
24-
import '../parse/scss.dart';
2522
import '../syntax.dart';
2623
import '../util/nullable.dart';
2724
import '../utils.dart';
@@ -208,22 +205,12 @@ List<AsyncCallable> _parseFunctions(RenderOptions options, DateTime start,
208205

209206
var result = <AsyncCallable>[];
210207
jsForEach(functions, (signature, callback) {
211-
Tuple2<String, ArgumentDeclaration> tuple;
212-
try {
213-
tuple = ScssParser(signature).parseSignature(requireParens: false);
214-
} on SassFormatException catch (error, stackTrace) {
215-
throwWithTrace(
216-
SassFormatException(
217-
'Invalid signature "$signature": ${error.message}', error.span),
218-
stackTrace);
219-
}
220-
221208
var context = RenderContext(options: _contextOptions(options, start));
222209
context.options.context = context;
223210

224211
var fiber = options.fiber;
225212
if (fiber != null) {
226-
result.add(BuiltInCallable.parsed(tuple.item1, tuple.item2, (arguments) {
213+
result.add(Callable.fromSignature(signature, (arguments) {
227214
var currentFiber = fiber.current;
228215
var jsArguments = [
229216
...arguments.map(wrapValue),
@@ -240,16 +227,15 @@ List<AsyncCallable> _parseFunctions(RenderOptions options, DateTime start,
240227
// `Zone.current` in an inconsistent state.
241228
? runZoned(() => fiber.yield())
242229
: result);
243-
}));
230+
}, requireParens: false));
244231
} else if (!asynch) {
245-
result.add(BuiltInCallable.parsed(
246-
tuple.item1,
247-
tuple.item2,
232+
result.add(Callable.fromSignature(
233+
signature,
248234
(arguments) => unwrapValue((callback as JSFunction)
249-
.apply(context, arguments.map(wrapValue).toList()))));
235+
.apply(context, arguments.map(wrapValue).toList())),
236+
requireParens: false));
250237
} else {
251-
result.add(AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2,
252-
(arguments) async {
238+
result.add(AsyncCallable.fromSignature(signature, (arguments) async {
253239
var completer = Completer<Object?>();
254240
var jsArguments = [
255241
...arguments.map(wrapValue),
@@ -258,7 +244,7 @@ List<AsyncCallable> _parseFunctions(RenderOptions options, DateTime start,
258244
var result = (callback as JSFunction).apply(context, jsArguments);
259245
return unwrapValue(
260246
isUndefined(result) ? await completer.future : result);
261-
}));
247+
}, requireParens: false));
262248
}
263249
});
264250
return result;

lib/src/utils.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import 'package:source_span/source_span.dart';
1010
import 'package:stack_trace/stack_trace.dart';
1111
import 'package:string_scanner/string_scanner.dart';
1212
import 'package:term_glyph/term_glyph.dart' as glyph;
13+
import 'package:tuple/tuple.dart';
1314

15+
import 'ast/sass.dart';
16+
import 'exception.dart';
17+
import 'parse/scss.dart';
1418
import 'util/character.dart';
1519

1620
/// The URL used in stack traces when no source URL is available.
@@ -469,3 +473,21 @@ extension IterableExtension<E> on Iterable<E> {
469473
return take(size);
470474
}
471475
}
476+
477+
/// Parses a function signature of the format allowed by Node Sass's functions
478+
/// option and returns its name and declaration.
479+
///
480+
/// If [requireParens] is `false`, this allows parentheses to be omitted.
481+
///
482+
/// Throws a [SassFormatException] if parsing fails.
483+
Tuple2<String, ArgumentDeclaration> parseSignature(String signature,
484+
{bool requireParens = true}) {
485+
try {
486+
return ScssParser(signature).parseSignature(requireParens: requireParens);
487+
} on SassFormatException catch (error, stackTrace) {
488+
throwWithTrace(
489+
SassFormatException(
490+
'Invalid signature "$signature": ${error.message}', error.span),
491+
stackTrace);
492+
}
493+
}

pkg/sass_api/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.1.2
2+
3+
* No user-visible changes.
4+
15
## 4.1.1
26

37
* No user-visible changes.

pkg/sass_api/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ name: sass_api
22
# Note: Every time we add a new Sass AST node, we need to bump the *major*
33
# version because it's a breaking change for anyone who's implementing the
44
# visitor interface(s).
5-
version: 4.1.1
5+
version: 4.1.2
66
description: Additional APIs for Dart Sass.
77
homepage: https://github.com/sass/dart-sass
88

99
environment:
1010
sdk: ">=2.17.0 <3.0.0"
1111

1212
dependencies:
13-
sass: 1.56.1
13+
sass: 1.56.2
1414

1515
dev_dependencies:
1616
dartdoc: ^5.0.0

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: sass
2-
version: 1.56.1
2+
version: 1.56.2
33
description: A Sass implementation in Dart.
44
homepage: https://github.com/sass/dart-sass
55

0 commit comments

Comments
 (0)