mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-21 21:31:11 +01:00
parent
2dd7601ba6
commit
6ed530c895
@ -6,10 +6,11 @@ import 'package:js/js.dart';
|
|||||||
|
|
||||||
import 'exception.dart';
|
import 'exception.dart';
|
||||||
import 'executable.dart' as executable;
|
import 'executable.dart' as executable;
|
||||||
import 'node/error.dart';
|
|
||||||
import 'node/exports.dart';
|
import 'node/exports.dart';
|
||||||
import 'node/options.dart';
|
import 'node/render_error.dart';
|
||||||
import 'node/result.dart';
|
import 'node/render_options.dart';
|
||||||
|
import 'node/render_result.dart';
|
||||||
|
import 'node/utils.dart';
|
||||||
import 'render.dart';
|
import 'render.dart';
|
||||||
import 'visitor/serialize.dart';
|
import 'visitor/serialize.dart';
|
||||||
|
|
||||||
@ -35,22 +36,17 @@ void main() {
|
|||||||
/// possible.
|
/// possible.
|
||||||
///
|
///
|
||||||
/// [render]: https://github.com/sass/node-sass#options
|
/// [render]: https://github.com/sass/node-sass#options
|
||||||
void _render(
|
void _render(RenderOptions options,
|
||||||
NodeOptions options, void callback(NodeError error, NodeResult result)) {
|
void callback(RenderError error, RenderResult result)) {
|
||||||
try {
|
try {
|
||||||
var indentWidthValue = options.indentWidth;
|
var result = newRenderResult(render(options.file,
|
||||||
var indentWidth = indentWidthValue is int
|
useSpaces: options.indentType != 'tab',
|
||||||
? indentWidthValue
|
indentWidth: _parseIndentWidth(options.indentWidth),
|
||||||
: int.parse(indentWidthValue.toString());
|
lineFeed: _parseLineFeed(options.linefeed)));
|
||||||
var lineFeed = _parseLineFeed(options.linefeed);
|
|
||||||
var result = newNodeResult(render(options.file,
|
|
||||||
useSpaces: options.indentType == 'space',
|
|
||||||
indentWidth: indentWidth,
|
|
||||||
lineFeed: lineFeed));
|
|
||||||
callback(null, result);
|
callback(null, result);
|
||||||
} on SassException catch (error) {
|
} on SassException catch (error) {
|
||||||
// TODO: populate the error more thoroughly if possible.
|
// TODO: populate the error more thoroughly if possible.
|
||||||
callback(new NodeError(message: error.message), null);
|
callback(newRenderError(message: error.message), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,23 +56,25 @@ void _render(
|
|||||||
/// as possible.
|
/// as possible.
|
||||||
///
|
///
|
||||||
/// [render]: https://github.com/sass/node-sass#options
|
/// [render]: https://github.com/sass/node-sass#options
|
||||||
NodeResult _renderSync(NodeOptions options) {
|
RenderResult _renderSync(RenderOptions options) {
|
||||||
try {
|
try {
|
||||||
var indentWidthValue = options.indentWidth;
|
return newRenderResult(render(options.file,
|
||||||
var indentWidth = indentWidthValue is int
|
useSpaces: options.indentType != 'tab',
|
||||||
? indentWidthValue
|
indentWidth: _parseIndentWidth(options.indentWidth),
|
||||||
: int.parse(indentWidthValue.toString());
|
lineFeed: _parseLineFeed(options.linefeed)));
|
||||||
var lineFeed = _parseLineFeed(options.linefeed);
|
|
||||||
return newNodeResult(render(options.file,
|
|
||||||
useSpaces: options.indentType == 'space',
|
|
||||||
indentWidth: indentWidth,
|
|
||||||
lineFeed: lineFeed));
|
|
||||||
} on SassException catch (error) {
|
} on SassException catch (error) {
|
||||||
// TODO: populate the error more thoroughly if possible.
|
// TODO: populate the error more thoroughly if possible.
|
||||||
throw new NodeError(message: error.message);
|
jsThrow(newRenderError(message: error.message));
|
||||||
|
throw "unreachable";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses the indentation width into an [int].
|
||||||
|
int _parseIndentWidth(width) {
|
||||||
|
if (width == null) return null;
|
||||||
|
return width is int ? width : int.parse(width.toString());
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses the name of a line feed type into a [LineFeed].
|
/// Parses the name of a line feed type into a [LineFeed].
|
||||||
LineFeed _parseLineFeed(String str) {
|
LineFeed _parseLineFeed(String str) {
|
||||||
switch (str) {
|
switch (str) {
|
||||||
|
13
lib/src/node/function.dart
Normal file
13
lib/src/node/function.dart
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2017 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:js/js.dart';
|
||||||
|
|
||||||
|
@JS("Function")
|
||||||
|
class JSFunction {
|
||||||
|
@JS("Function")
|
||||||
|
external JSFunction(String arg1, [String arg2, String arg3]);
|
||||||
|
|
||||||
|
external call(thisArg, [arg1, arg2]);
|
||||||
|
}
|
@ -4,15 +4,25 @@
|
|||||||
|
|
||||||
import 'package:js/js.dart';
|
import 'package:js/js.dart';
|
||||||
|
|
||||||
|
import 'utils.dart';
|
||||||
|
|
||||||
@JS()
|
@JS()
|
||||||
@anonymous
|
@anonymous
|
||||||
class NodeError {
|
class RenderError {
|
||||||
external String get message;
|
external String get message;
|
||||||
external int get line;
|
external int get line;
|
||||||
external int get column;
|
external int get column;
|
||||||
external int get status;
|
external int get status;
|
||||||
external String get file;
|
external String get file;
|
||||||
|
|
||||||
external factory NodeError(
|
external factory RenderError._(
|
||||||
{String message, int line, int column, int status, String file});
|
{String message, int line, int column, int status, String file});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenderError newRenderError(
|
||||||
|
{String message, int line, int column, int status, String file}) {
|
||||||
|
var error = new RenderError._(
|
||||||
|
message: message, line: line, column: column, status: status, file: file);
|
||||||
|
setToString(error, () => "Error: $message");
|
||||||
|
return error;
|
||||||
|
}
|
@ -5,9 +5,13 @@
|
|||||||
import 'package:js/js.dart';
|
import 'package:js/js.dart';
|
||||||
|
|
||||||
@JS()
|
@JS()
|
||||||
class NodeOptions {
|
@anonymous
|
||||||
|
class RenderOptions {
|
||||||
external String get file;
|
external String get file;
|
||||||
external String get indentType;
|
external String get indentType;
|
||||||
external dynamic get indentWidth;
|
external dynamic get indentWidth;
|
||||||
external String get linefeed;
|
external String get linefeed;
|
||||||
|
|
||||||
|
external factory RenderOptions(
|
||||||
|
{String file, String indentType, indentWidth, String linefeed});
|
||||||
}
|
}
|
@ -2,6 +2,8 @@
|
|||||||
// MIT-style license that can be found in the LICENSE file or at
|
// MIT-style license that can be found in the LICENSE file or at
|
||||||
// https://opensource.org/licenses/MIT.
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:js/js.dart';
|
import 'package:js/js.dart';
|
||||||
|
|
||||||
@JS('Buffer.from')
|
@JS('Buffer.from')
|
||||||
@ -9,11 +11,11 @@ external _buffer(String source, String encoding);
|
|||||||
|
|
||||||
@JS()
|
@JS()
|
||||||
@anonymous
|
@anonymous
|
||||||
class NodeResult {
|
class RenderResult {
|
||||||
external get buffer;
|
external Uint8List get css;
|
||||||
|
|
||||||
external factory NodeResult._({buffer});
|
external factory RenderResult._({css});
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeResult newNodeResult(String css) =>
|
RenderResult newRenderResult(String css) =>
|
||||||
new NodeResult._(buffer: _buffer(css, 'utf8'));
|
new RenderResult._(css: _buffer(css, 'utf8'));
|
23
lib/src/node/utils.dart
Normal file
23
lib/src/node/utils.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 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:js/js.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
import 'function.dart';
|
||||||
|
|
||||||
|
/// Sets the `toString()` function for [object] to [body].
|
||||||
|
///
|
||||||
|
/// Dart's JS interop doesn't currently let us set toString() for custom
|
||||||
|
/// classes, so we use this as a workaround.
|
||||||
|
void setToString(object, String body()) =>
|
||||||
|
_setToString.call(object, allowInterop(body));
|
||||||
|
|
||||||
|
final _setToString =
|
||||||
|
new JSFunction("object", "body", "object.toString = body;");
|
||||||
|
|
||||||
|
/// Throws [error] like JS would, without any Dart wrappers.
|
||||||
|
void jsThrow(error) => _jsThrow.call(error);
|
||||||
|
|
||||||
|
final _jsThrow = new JSFunction("error", "throw error;");
|
@ -28,8 +28,15 @@ dev_dependencies:
|
|||||||
http: "^0.11.0"
|
http: "^0.11.0"
|
||||||
js: "^0.6.0"
|
js: "^0.6.0"
|
||||||
node_preamble: "^1.1.0"
|
node_preamble: "^1.1.0"
|
||||||
|
stream_channel: "^1.0.0"
|
||||||
test_descriptor: "^1.0.0"
|
test_descriptor: "^1.0.0"
|
||||||
test_process: "^1.0.0-rc.1"
|
test_process: "^1.0.0-rc.1"
|
||||||
test: "^0.12.5"
|
test: "^0.12.24"
|
||||||
xml: "^2.4.0"
|
xml: "^2.4.0"
|
||||||
yaml: "^2.0.0"
|
yaml: "^2.0.0"
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
test:
|
||||||
|
git:
|
||||||
|
url: git://github.com/dart-lang/test.git
|
||||||
|
ref: node
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// MIT-style license that can be found in the LICENSE file or at
|
// MIT-style license that can be found in the LICENSE file or at
|
||||||
// https://opensource.org/licenses/MIT.
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
@TestOn('vm')
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// MIT-style license that can be found in the LICENSE file or at
|
// MIT-style license that can be found in the LICENSE file or at
|
||||||
// https://opensource.org/licenses/MIT.
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
@TestOn('vm')
|
||||||
|
|
||||||
import 'package:package_resolver/package_resolver.dart';
|
import 'package:package_resolver/package_resolver.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
@ -6,22 +6,25 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:stream_channel/stream_channel.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:yaml/yaml.dart';
|
import 'package:yaml/yaml.dart';
|
||||||
|
|
||||||
void hybridMain(StreamChannel channel) async {
|
hybridMain(StreamChannel channel) async {
|
||||||
if (!new Directory("build/npm").existsSync()) {
|
if (!new Directory("build/npm").existsSync()) {
|
||||||
throw "NPM package is not build. Run pub run grinder npm_package.";
|
throw "NPM package is not build. Run pub run grinder npm_package.";
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastModified = new DateTime(0);
|
var lastModified = new DateTime(0);
|
||||||
var entriesToCheck = new Directory("lib").listSync(recursive: true).toList()
|
var entriesToCheck = new Directory("lib").listSync(recursive: true).toList()
|
||||||
..add("pubspec.lock");
|
..add(new File("pubspec.lock"));
|
||||||
for (var entry in entriesToCheck) {
|
for (var entry in entriesToCheck) {
|
||||||
if (entry is! File) continue;
|
if (entry is File) {
|
||||||
var entryLastModified = entry.lastModifiedSync();
|
var entryLastModified = entry.lastModifiedSync();
|
||||||
if (lastModified.isBefore(entryLastModified))
|
if (lastModified.isBefore(entryLastModified)) {
|
||||||
lastModified = entryLastModified;
|
lastModified = entryLastModified;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastModified
|
if (lastModified
|
||||||
|
56
test/hybrid.dart
Normal file
56
test/hybrid.dart
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2017 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 'package:test/test.dart';
|
||||||
|
|
||||||
|
/// Creates a directory in the system temp directory and returns its path.
|
||||||
|
Future<String> createTempDir() async => (await runHybridExpression(
|
||||||
|
'(await Directory.systemTemp.createTemp("dart_sass_")).path')) as String;
|
||||||
|
|
||||||
|
/// Writes [text] to [path].
|
||||||
|
Future writeTextFile(String path, String text) => runHybridExpression(
|
||||||
|
'new File(message[0]).writeAsString(message[1])', [path, text]);
|
||||||
|
|
||||||
|
/// Recursively deletes the directoy at [path].
|
||||||
|
Future deleteDirectory(String path) =>
|
||||||
|
runHybridExpression('new Directory(message).delete(recursive: true)', path);
|
||||||
|
|
||||||
|
/// Runs [expression], which may be asynchronous, in a hybrid isolate.
|
||||||
|
///
|
||||||
|
/// Returns the result of [expression] if it's JSON-serializable.
|
||||||
|
Future runHybridExpression(String expression, [message]) async {
|
||||||
|
var channel = spawnHybridCode(
|
||||||
|
'''
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:stream_channel/stream_channel.dart';
|
||||||
|
|
||||||
|
hybridMain(StreamChannel channel, message) async {
|
||||||
|
var result = await ${expression};
|
||||||
|
channel.sink.add(_isJsonSafe(result) ? JSON.encode(result) : 'null');
|
||||||
|
channel.sink.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isJsonSafe(object) {
|
||||||
|
if (object == null) return true;
|
||||||
|
if (object is String) return true;
|
||||||
|
if (object is num) return true;
|
||||||
|
if (object is bool) return true;
|
||||||
|
if (object is List) return object.every(_isJsonSafe);
|
||||||
|
if (object is Map) {
|
||||||
|
return object.keys.every(_isJsonSafe) &&
|
||||||
|
object.values.every(_isJsonSafe);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
''',
|
||||||
|
message: message);
|
||||||
|
|
||||||
|
return JSON.decode((await channel.stream.first) as String);
|
||||||
|
}
|
33
test/node_api.dart
Normal file
33
test/node_api.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
/// This library exposes Dart Sass's Node.js API, imported as JavaScript, back
|
||||||
|
/// to Dart. This is kind of convoluted, but it allows us to test the API as it
|
||||||
|
/// will be used in the real world without having to manually write any JS.
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:sass/src/node/render_error.dart';
|
||||||
|
import 'package:sass/src/node/render_options.dart';
|
||||||
|
import 'package:sass/src/node/render_result.dart';
|
||||||
|
|
||||||
|
import 'package:js/js.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
|
export 'package:sass/src/node/render_error.dart';
|
||||||
|
export 'package:sass/src/node/render_options.dart';
|
||||||
|
export 'package:sass/src/node/render_result.dart';
|
||||||
|
|
||||||
|
/// The Sass module.
|
||||||
|
final sass = _require(p.absolute("build/npm/sass.dart"));
|
||||||
|
|
||||||
|
@JS("require")
|
||||||
|
external Sass _require(String path);
|
||||||
|
|
||||||
|
@JS()
|
||||||
|
class Sass {
|
||||||
|
external RenderResult renderSync(RenderOptions args);
|
||||||
|
external void render(RenderOptions args,
|
||||||
|
void callback(RenderError error, RenderResult result));
|
||||||
|
}
|
166
test/node_api_test.dart
Normal file
166
test/node_api_test.dart
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
// Copyright 2017 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(const ['node'])
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:js/js.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'ensure_npm_package.dart';
|
||||||
|
import 'hybrid.dart';
|
||||||
|
import 'node_api.dart';
|
||||||
|
|
||||||
|
String sandbox;
|
||||||
|
String sassPath;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
setUpAll(ensureNpmPackage);
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
sandbox = await createTempDir();
|
||||||
|
sassPath = p.join(sandbox, 'test.scss');
|
||||||
|
await writeTextFile(sassPath, 'a {b: c}');
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() async {
|
||||||
|
if (sandbox != null) await deleteDirectory(sandbox);
|
||||||
|
});
|
||||||
|
|
||||||
|
group("renderSync()", () {
|
||||||
|
test("renders a file", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath)), equals('''
|
||||||
|
a {
|
||||||
|
b: c;
|
||||||
|
}'''));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("allows tab indentation", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, indentType: 'tab')),
|
||||||
|
equals('''
|
||||||
|
a {
|
||||||
|
\t\tb: c;
|
||||||
|
}'''));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("allows unknown indentation names", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, indentType: 'asdf')),
|
||||||
|
equals('''
|
||||||
|
a {
|
||||||
|
b: c;
|
||||||
|
}'''));
|
||||||
|
});
|
||||||
|
|
||||||
|
group("linefeed allows", () {
|
||||||
|
test("cr", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, linefeed: 'cr')),
|
||||||
|
equals('a {\r b: c;\r}'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("crlf", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, linefeed: 'crlf')),
|
||||||
|
equals('a {\r\n b: c;\r\n}'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("lfcr", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, linefeed: 'lfcr')),
|
||||||
|
equals('a {\n\r b: c;\n\r}'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("unknown names", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, linefeed: 'asdf')),
|
||||||
|
equals('a {\n b: c;\n}'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("indentWidth allows", () {
|
||||||
|
test("a number", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, indentWidth: 10)),
|
||||||
|
equals('''
|
||||||
|
a {
|
||||||
|
b: c;
|
||||||
|
}'''));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a string", () {
|
||||||
|
expect(_renderSync(new RenderOptions(file: sassPath, indentWidth: '1')),
|
||||||
|
equals('''
|
||||||
|
a {
|
||||||
|
b: c;
|
||||||
|
}'''));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("throws an error that", () {
|
||||||
|
setUp(() => writeTextFile(sassPath, 'a {b: }'));
|
||||||
|
|
||||||
|
test("has a useful toString", () {
|
||||||
|
var error = _renderSyncError(new RenderOptions(file: sassPath));
|
||||||
|
expect(error.toString(), equals("Error: Expected expression."));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("has a useful message", () {
|
||||||
|
var error = _renderSyncError(new RenderOptions(file: sassPath));
|
||||||
|
expect(error.message, equals("Expected expression."));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("render()", () {
|
||||||
|
test("renders a file", () async {
|
||||||
|
expect(await _render(new RenderOptions(file: sassPath)), equals('''
|
||||||
|
a {
|
||||||
|
b: c;
|
||||||
|
}'''));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("throws an error that has a useful toString", () async {
|
||||||
|
await writeTextFile(sassPath, 'a {b: }');
|
||||||
|
|
||||||
|
var error = await _renderError(new RenderOptions(file: sassPath));
|
||||||
|
expect(error.toString(), equals("Error: Expected expression."));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the result of rendering via [options] as a string.
|
||||||
|
Future<String> _render(RenderOptions options) {
|
||||||
|
var completer = new Completer<String>();
|
||||||
|
sass.render(options, allowInterop((error, result) {
|
||||||
|
expect(error, isNull);
|
||||||
|
completer.complete(UTF8.decode(result.css));
|
||||||
|
}));
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asserts that rendering via [options] produces an error, and returns that
|
||||||
|
/// error.
|
||||||
|
Future<RenderError> _renderError(RenderOptions options) {
|
||||||
|
var completer = new Completer<RenderError>();
|
||||||
|
sass.render(options, allowInterop((error, result) {
|
||||||
|
expect(result, isNull);
|
||||||
|
completer.complete(error as RenderError);
|
||||||
|
}));
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the result of rendering via [options] as a string.
|
||||||
|
String _renderSync(RenderOptions options) =>
|
||||||
|
UTF8.decode(sass.renderSync(options).css);
|
||||||
|
|
||||||
|
/// Asserts that rendering via [options] produces an error, and returns that
|
||||||
|
/// error.
|
||||||
|
RenderError _renderSyncError(RenderOptions options) {
|
||||||
|
try {
|
||||||
|
sass.renderSync(options);
|
||||||
|
} catch (error) {
|
||||||
|
return error as RenderError;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Expected renderSync() to throw an error.";
|
||||||
|
}
|
@ -2,7 +2,9 @@
|
|||||||
// MIT-style license that can be found in the LICENSE file or at
|
// MIT-style license that can be found in the LICENSE file or at
|
||||||
// https://opensource.org/licenses/MIT.
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
|
@TestOn('vm')
|
||||||
@Tags(const ['node'])
|
@Tags(const ['node'])
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user