Make errors subtypes of Error

This commit is contained in:
Natalie Weizenbaum 2018-03-23 14:58:57 -07:00
parent 0e5a707ab4
commit 6608a46d1e
6 changed files with 76 additions and 71 deletions

View File

@ -6,6 +6,8 @@
### Node API
* Errors are now subtypes of the `Error` type.
* Allow both the `data` and `file` options to be passed to `render()` and
`renderSync()` at once. The `data` option will be used as the contents of the
stylesheet, and the `file` option will be used as the path for error reporting

View File

@ -3,6 +3,7 @@
// https://opensource.org/licenses/MIT.
import 'dart:async';
import 'dart:js_util';
import 'package:collection/collection.dart';
import 'package:js/js.dart';
@ -14,10 +15,10 @@ import 'compile.dart';
import 'exception.dart';
import 'executable.dart' as executable;
import 'importer/node.dart';
import 'node/error.dart';
import 'node/exports.dart';
import 'node/render_context.dart';
import 'node/render_context_options.dart';
import 'node/render_error.dart';
import 'node/render_options.dart';
import 'node/render_result.dart';
import 'node/types.dart';
@ -61,14 +62,14 @@ void main() {
/// possible.
///
/// [render]: https://github.com/sass/node-sass#options
void _render(RenderOptions options,
void callback(RenderError error, RenderResult result)) {
void _render(
RenderOptions options, void callback(JSError error, RenderResult result)) {
if (options.fiber != null) {
options.fiber.call(allowInterop(() {
try {
callback(null, _renderSync(options));
} catch (error) {
callback(error as RenderError, null);
callback(error as JSError, null);
}
})).run();
} else {
@ -78,7 +79,7 @@ void _render(RenderOptions options,
if (error is SassException) {
callback(_wrapException(error), null);
} else {
callback(newRenderError(error.toString(), status: 3), null);
callback(_newRenderError(error.toString(), status: 3), null);
}
});
}
@ -166,33 +167,37 @@ RenderResult _renderSync(RenderOptions options) {
} on SassException catch (error) {
jsThrow(_wrapException(error));
} catch (error) {
jsThrow(newRenderError(error.toString(), status: 3));
jsThrow(_newRenderError(error.toString(), status: 3));
}
throw "unreachable";
}
/// Converts a [SassException] to a [RenderError].
RenderError _wrapException(SassException exception) {
var trace = exception is SassRuntimeException
? "\n" +
exception.trace
.toString()
.trimRight()
.split("\n")
.map((frame) => " $frame")
.join("\n")
: "\n ${p.prettyUri(exception.span.sourceUrl ?? '-')} "
"${exception.span.start.line + 1}:${exception.span.start.column + 1} "
"root stylesheet";
/// Converts an exception to a [JSError].
JSError _wrapException(exception) {
if (exception is SassException) {
var trace = exception is SassRuntimeException
? "\n" +
exception.trace
.toString()
.trimRight()
.split("\n")
.map((frame) => " $frame")
.join("\n")
: "\n ${p.prettyUri(exception.span.sourceUrl ?? '-')} "
"${exception.span.start.line + 1}:${exception.span.start.column + 1} "
"root stylesheet";
return newRenderError(exception.message + trace,
formatted: exception.toString(),
line: exception.span.start.line + 1,
column: exception.span.start.column + 1,
file: exception.span.sourceUrl == null
? 'stdin'
: p.fromUri(exception.span.sourceUrl),
status: 1);
return _newRenderError(exception.message + trace,
formatted: exception.toString(),
line: exception.span.start.line + 1,
column: exception.span.start.column + 1,
file: exception.span.sourceUrl == null
? 'stdin'
: p.fromUri(exception.span.sourceUrl),
status: 1);
} else {
return new JSError(exception.toString());
}
}
/// Parses `functions` from [RenderOptions] into a list of [Callable]s or
@ -327,3 +332,16 @@ LineFeed _parseLineFeed(String str) {
return LineFeed.lf;
}
}
/// Creates a [JSError] with the given fields added to it so it acts like a Node
/// Sass error.
JSError _newRenderError(String message,
{String formatted, int line, int column, String file, int status}) {
var error = new JSError(message);
if (formatted != null) setProperty(error, 'formatted', formatted);
if (line != null) setProperty(error, 'line', line);
if (column != null) setProperty(error, 'column', column);
if (file != null) setProperty(error, 'file', file);
if (status != null) setProperty(error, 'status', status);
return error;
}

11
lib/src/node/error.dart Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2016 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("Error")
class JSError {
external String get message;
external JSError(String message);
}

View File

@ -1,39 +0,0 @@
// Copyright 2016 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 'utils.dart';
@JS()
@anonymous
class RenderError {
external String get message;
external String get formatted;
external int get line;
external int get column;
external String get file;
external int get status;
external factory RenderError._(
{String message,
String formatted,
int line,
int column,
String file,
int status});
}
RenderError newRenderError(String message,
{String formatted, int line, int column, String file, int status}) {
var error = new RenderError._(
message: message,
formatted: formatted,
line: line,
column: column,
file: file,
status: status);
setToString(error, () => "Error: $message");
return error;
}

View File

@ -7,16 +7,15 @@
/// will be used in the real world without having to manually write any JS.
import 'package:sass/src/node/fiber.dart';
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:sass/src/util/path.dart';
import 'package:js/js.dart';
export 'package:sass/src/node/error.dart';
export 'package:sass/src/node/importer_result.dart';
export 'package:sass/src/node/render_context.dart';
export 'package:sass/src/node/render_error.dart';
export 'package:sass/src/node/render_options.dart';
export 'package:sass/src/node/render_result.dart';
@ -58,9 +57,14 @@ class Sass {
external SassTypes get types;
}
@JS("Error")
class JSError {
external JSError(String message);
@JS()
class RenderError {
external String get message;
external String get formatted;
external int get line;
external int get column;
external String get file;
external int get status;
}
@JS()

View File

@ -10,6 +10,7 @@ import 'package:path/path.dart' as unsafePath;
import 'package:test/test.dart';
import 'package:sass/src/util/path.dart';
import 'package:sass/src/node/utils.dart';
import 'ensure_npm_package.dart';
import 'hybrid.dart';
@ -269,6 +270,10 @@ a {
error = renderSyncError(new RenderOptions(file: sassPath));
});
test("is a JS Error", () async {
expect(isJSError(error), isTrue);
});
test("has a useful toString() and message", () async {
expect(
error,
@ -297,6 +302,10 @@ a {
error = renderSyncError(new RenderOptions(data: "a {b: }"));
});
test("is a JS Error", () async {
expect(isJSError(error), isTrue);
});
test("has a useful toString() and message", () {
expect(
error,