From 7699029dbd87bb600626b8335d1dcffb7f2734ac Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 15 Jan 2020 12:04:26 +0100 Subject: [PATCH] NodeJS `run_` API method should return native JavaScript `Promise` Currently the `run_` method, exposed through the `dart.sass.js` file, returns a `Future`. The `Future` object is not accessible due to the Dart compilation process and `Future` not being a thing in the JavaScript/NodeJS platform. In order to provide a better interface to the Sass API for JavaScript/NodeJS consumers, a native `Promise` is now returned. Fixes https://github.com/bazelbuild/rules_sass/issues/96. --- lib/src/node.dart | 6 ++++-- lib/src/node/promise.dart | 19 +++++++++++++++++ test/node_api/api.dart | 2 ++ test/node_api/exports_test.dart | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 lib/src/node/promise.dart create mode 100644 test/node_api/exports_test.dart diff --git a/lib/src/node.dart b/lib/src/node.dart index 4399c23fe..811a2c010 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:js'; import 'dart:js_util'; import 'dart:typed_data'; @@ -21,6 +22,7 @@ import 'importer/node.dart'; import 'node/error.dart'; import 'node/exports.dart'; import 'node/function.dart'; +import 'node/promise.dart'; import 'node/render_context.dart'; import 'node/render_context_options.dart'; import 'node/render_options.dart'; @@ -39,8 +41,8 @@ import 'visitor/serialize.dart'; /// export that runs the normal `main()`, which is called from `package/sass.js` /// to run the executable when installed from npm. void main() { - exports.run_ = allowInterop( - (Object args) => executable.main(List.from(args as List))); + exports.run_ = allowInterop((Object args) => + futureToPromise(executable.main(List.from(args as List)))); exports.render = allowInterop(_render); exports.renderSync = allowInterop(_renderSync); exports.info = diff --git a/lib/src/node/promise.dart b/lib/src/node/promise.dart new file mode 100644 index 000000000..79c621e57 --- /dev/null +++ b/lib/src/node/promise.dart @@ -0,0 +1,19 @@ +// 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:js'; + +import 'package:js/js.dart'; + +/// Describes the native JavaScript `Promise` global. +@JS() +class Promise { + external Promise(void executor(void resolve(T result), Function reject)); +} + +/// Converts a Future to a JavaScript Promise. +Promise futureToPromise(Future future) { + return Promise(allowInterop((resolve, reject) => + future.then(resolve, onError: reject))); +} diff --git a/test/node_api/api.dart b/test/node_api/api.dart index 1ca9fa27a..7e1264a4a 100644 --- a/test/node_api/api.dart +++ b/test/node_api/api.dart @@ -15,6 +15,7 @@ export 'package:sass/src/node/render_context.dart'; export 'package:sass/src/node/render_options.dart'; export 'package:sass/src/node/render_result.dart'; import 'package:sass/src/node/fiber.dart'; +import 'package:sass/src/node/promise.dart'; import 'package:sass/src/node/render_options.dart'; import 'package:sass/src/node/render_result.dart'; @@ -50,6 +51,7 @@ external FiberClass _requireFiber(String path); @JS() class Sass { + external Promise run_(Object args); external RenderResult renderSync(RenderOptions args); external void render(RenderOptions args, void callback(RenderError error, RenderResult result)); diff --git a/test/node_api/exports_test.dart b/test/node_api/exports_test.dart new file mode 100644 index 000000000..664afa2af --- /dev/null +++ b/test/node_api/exports_test.dart @@ -0,0 +1,37 @@ +// Copyright 2018 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. + +@TestOn('node') +@Tags(['node']) + +import 'package:js/js.dart'; +import 'package:js/js_util.dart'; +import 'package:sass/src/node/promise.dart'; +import 'package:test/test.dart'; + +import '../ensure_npm_package.dart'; +import 'api.dart'; +import 'utils.dart'; + +/// Describes a JavaScript object. +/// +/// Object's always have a `constructor` property in JavaScript. +@JS() +class ObjectWithConstructor { + Object constructor; +} + +void main() { + setUpAll(ensureNpmPackage); + useSandbox(); + + group('run_ method', () { + test('returns a JavaScript native Promise', () async { + var result = sass.run_([]) as ObjectWithConstructor; + expect(result, isA>()); + expect(result.constructor.toString(), contains('[native code]')); + await promiseToFuture(result); + }); + }); +}