mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
Combine CLI Errors (#2487)
This commit is contained in:
parent
43f48386d7
commit
425df50484
35 changed files with 1305 additions and 759 deletions
|
@ -79,14 +79,6 @@ pub fn red(s: String) -> impl fmt::Display {
|
|||
style.paint(s)
|
||||
}
|
||||
|
||||
pub fn grey(s: String) -> impl fmt::Display {
|
||||
let mut style = Style::new();
|
||||
if use_color() {
|
||||
style = style.fg(Fixed(8));
|
||||
}
|
||||
style.paint(s)
|
||||
}
|
||||
|
||||
pub fn bold(s: String) -> impl fmt::Display {
|
||||
let mut style = Style::new();
|
||||
if use_color() {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::deno_error::err_check;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::diagnostics::Diagnostic;
|
||||
use crate::msg;
|
||||
use crate::resources;
|
||||
|
@ -6,7 +8,6 @@ use crate::startup_data;
|
|||
use crate::state::*;
|
||||
use crate::tokio_util;
|
||||
use crate::worker::Worker;
|
||||
use deno::js_check;
|
||||
use deno::Buf;
|
||||
use futures::Future;
|
||||
use futures::Stream;
|
||||
|
@ -92,7 +93,7 @@ pub fn bundle_async(
|
|||
state: ThreadSafeState,
|
||||
module_name: String,
|
||||
out_file: String,
|
||||
) -> impl Future<Item = (), Error = Diagnostic> {
|
||||
) -> impl Future<Item = (), Error = DenoError> {
|
||||
debug!(
|
||||
"Invoking the compiler to bundle. module_name: {}",
|
||||
module_name
|
||||
|
@ -112,9 +113,9 @@ pub fn bundle_async(
|
|||
// as was done previously.
|
||||
state.clone(),
|
||||
);
|
||||
js_check(worker.execute("denoMain()"));
|
||||
js_check(worker.execute("workerMain()"));
|
||||
js_check(worker.execute("compilerMain()"));
|
||||
err_check(worker.execute("denoMain()"));
|
||||
err_check(worker.execute("workerMain()"));
|
||||
err_check(worker.execute("compilerMain()"));
|
||||
|
||||
let resource = worker.state.resource.clone();
|
||||
let compiler_rid = resource.rid;
|
||||
|
@ -140,7 +141,7 @@ pub fn bundle_async(
|
|||
let json_str = std::str::from_utf8(&msg).unwrap();
|
||||
debug!("Message: {}", json_str);
|
||||
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
|
||||
return Err(diagnostics);
|
||||
return Err(DenoError::from(diagnostics));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +153,7 @@ pub fn bundle_async(
|
|||
pub fn compile_async(
|
||||
state: ThreadSafeState,
|
||||
module_meta_data: &ModuleMetaData,
|
||||
) -> impl Future<Item = ModuleMetaData, Error = Diagnostic> {
|
||||
) -> impl Future<Item = ModuleMetaData, Error = DenoError> {
|
||||
let module_name = module_meta_data.module_name.clone();
|
||||
|
||||
debug!(
|
||||
|
@ -174,9 +175,9 @@ pub fn compile_async(
|
|||
// as was done previously.
|
||||
state.clone(),
|
||||
);
|
||||
js_check(worker.execute("denoMain()"));
|
||||
js_check(worker.execute("workerMain()"));
|
||||
js_check(worker.execute("compilerMain()"));
|
||||
err_check(worker.execute("denoMain()"));
|
||||
err_check(worker.execute("workerMain()"));
|
||||
err_check(worker.execute("compilerMain()"));
|
||||
|
||||
let compiling_job = state.progress.add(format!("Compiling {}", module_name));
|
||||
|
||||
|
@ -205,7 +206,7 @@ pub fn compile_async(
|
|||
let json_str = std::str::from_utf8(&msg).unwrap();
|
||||
debug!("Message: {}", json_str);
|
||||
if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) {
|
||||
return Err(diagnostics);
|
||||
return Err(DenoError::from(diagnostics));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +236,7 @@ pub fn compile_async(
|
|||
pub fn compile_sync(
|
||||
state: ThreadSafeState,
|
||||
module_meta_data: &ModuleMetaData,
|
||||
) -> Result<ModuleMetaData, Diagnostic> {
|
||||
) -> Result<ModuleMetaData, DenoError> {
|
||||
tokio_util::block_on(compile_async(state, module_meta_data))
|
||||
}
|
||||
|
||||
|
@ -306,6 +307,6 @@ mod tests {
|
|||
]);
|
||||
let out =
|
||||
bundle_async(state, module_name, String::from("$deno$/bundle.js"));
|
||||
assert_eq!(tokio_util::block_on(out), Ok(()));
|
||||
assert!(tokio_util::block_on(out).is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::compiler::ModuleMetaData;
|
||||
use crate::errors;
|
||||
use crate::errors::DenoError;
|
||||
use crate::errors::DenoResult;
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::deno_error;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::deno_error::DenoResult;
|
||||
use crate::deno_error::ErrorKind;
|
||||
use crate::fs as deno_fs;
|
||||
use crate::http_util;
|
||||
use crate::js_errors::SourceMapGetter;
|
||||
use crate::msg;
|
||||
use crate::progress::Progress;
|
||||
use crate::source_maps::SourceMapGetter;
|
||||
use crate::tokio_util;
|
||||
use crate::version;
|
||||
use dirs;
|
||||
|
@ -152,7 +152,7 @@ impl DenoDir {
|
|||
referrer: &str,
|
||||
use_cache: bool,
|
||||
no_fetch: bool,
|
||||
) -> impl Future<Item = ModuleMetaData, Error = errors::DenoError> {
|
||||
) -> impl Future<Item = ModuleMetaData, Error = deno_error::DenoError> {
|
||||
debug!(
|
||||
"fetch_module_meta_data. specifier {} referrer {}",
|
||||
specifier, referrer
|
||||
|
@ -187,7 +187,7 @@ impl DenoDir {
|
|||
Err(err) => {
|
||||
if err.kind() == ErrorKind::NotFound {
|
||||
// For NotFound, change the message to something better.
|
||||
return Err(errors::new(
|
||||
return Err(deno_error::new(
|
||||
ErrorKind::NotFound,
|
||||
format!(
|
||||
"Cannot resolve module \"{}\" from \"{}\"",
|
||||
|
@ -255,7 +255,7 @@ impl DenoDir {
|
|||
referrer: &str,
|
||||
use_cache: bool,
|
||||
no_fetch: bool,
|
||||
) -> Result<ModuleMetaData, errors::DenoError> {
|
||||
) -> Result<ModuleMetaData, deno_error::DenoError> {
|
||||
tokio_util::block_on(
|
||||
self
|
||||
.fetch_module_meta_data_async(specifier, referrer, use_cache, no_fetch),
|
||||
|
@ -349,6 +349,20 @@ impl SourceMapGetter for DenoDir {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_source_line(&self, script_name: &str, line: usize) -> Option<String> {
|
||||
match self.fetch_module_meta_data(script_name, ".", true, true) {
|
||||
Ok(out) => match str::from_utf8(&out.source_code) {
|
||||
Ok(v) => {
|
||||
let lines: Vec<&str> = v.lines().collect();
|
||||
assert!(lines.len() > line);
|
||||
Some(lines[line].to_string())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This fetches source code, locally or remotely.
|
||||
|
|
538
cli/deno_error.rs
Normal file
538
cli/deno_error.rs
Normal file
|
@ -0,0 +1,538 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::diagnostics;
|
||||
use crate::fmt_errors::JSErrorColor;
|
||||
use crate::import_map;
|
||||
pub use crate::msg::ErrorKind;
|
||||
use crate::resolve_addr::ResolveAddrError;
|
||||
use crate::source_maps::apply_source_map;
|
||||
use crate::source_maps::SourceMapGetter;
|
||||
use deno::JSError;
|
||||
use hyper;
|
||||
#[cfg(unix)]
|
||||
use nix::{errno::Errno, Error as UnixError};
|
||||
use std;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::str;
|
||||
use url;
|
||||
|
||||
pub type DenoResult<T> = std::result::Result<T, DenoError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DenoError {
|
||||
repr: Repr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Repr {
|
||||
Simple(ErrorKind, String),
|
||||
IoErr(io::Error),
|
||||
UrlErr(url::ParseError),
|
||||
HyperErr(hyper::Error),
|
||||
ImportMapErr(import_map::ImportMapError),
|
||||
Diagnostic(diagnostics::Diagnostic),
|
||||
JSError(JSError),
|
||||
}
|
||||
|
||||
/// Create a new simple DenoError.
|
||||
pub fn new(kind: ErrorKind, msg: String) -> DenoError {
|
||||
DenoError {
|
||||
repr: Repr::Simple(kind, msg),
|
||||
}
|
||||
}
|
||||
|
||||
impl DenoError {
|
||||
pub fn kind(&self) -> ErrorKind {
|
||||
match self.repr {
|
||||
Repr::Simple(kind, ref _msg) => kind,
|
||||
// Repr::Simple(kind) => kind,
|
||||
Repr::IoErr(ref err) => {
|
||||
use std::io::ErrorKind::*;
|
||||
match err.kind() {
|
||||
NotFound => ErrorKind::NotFound,
|
||||
PermissionDenied => ErrorKind::PermissionDenied,
|
||||
ConnectionRefused => ErrorKind::ConnectionRefused,
|
||||
ConnectionReset => ErrorKind::ConnectionReset,
|
||||
ConnectionAborted => ErrorKind::ConnectionAborted,
|
||||
NotConnected => ErrorKind::NotConnected,
|
||||
AddrInUse => ErrorKind::AddrInUse,
|
||||
AddrNotAvailable => ErrorKind::AddrNotAvailable,
|
||||
BrokenPipe => ErrorKind::BrokenPipe,
|
||||
AlreadyExists => ErrorKind::AlreadyExists,
|
||||
WouldBlock => ErrorKind::WouldBlock,
|
||||
InvalidInput => ErrorKind::InvalidInput,
|
||||
InvalidData => ErrorKind::InvalidData,
|
||||
TimedOut => ErrorKind::TimedOut,
|
||||
Interrupted => ErrorKind::Interrupted,
|
||||
WriteZero => ErrorKind::WriteZero,
|
||||
Other => ErrorKind::Other,
|
||||
UnexpectedEof => ErrorKind::UnexpectedEof,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Repr::UrlErr(ref err) => {
|
||||
use url::ParseError::*;
|
||||
match err {
|
||||
EmptyHost => ErrorKind::EmptyHost,
|
||||
IdnaError => ErrorKind::IdnaError,
|
||||
InvalidPort => ErrorKind::InvalidPort,
|
||||
InvalidIpv4Address => ErrorKind::InvalidIpv4Address,
|
||||
InvalidIpv6Address => ErrorKind::InvalidIpv6Address,
|
||||
InvalidDomainCharacter => ErrorKind::InvalidDomainCharacter,
|
||||
RelativeUrlWithoutBase => ErrorKind::RelativeUrlWithoutBase,
|
||||
RelativeUrlWithCannotBeABaseBase => {
|
||||
ErrorKind::RelativeUrlWithCannotBeABaseBase
|
||||
}
|
||||
SetHostOnCannotBeABaseUrl => ErrorKind::SetHostOnCannotBeABaseUrl,
|
||||
Overflow => ErrorKind::Overflow,
|
||||
}
|
||||
}
|
||||
Repr::HyperErr(ref err) => {
|
||||
// For some reason hyper::errors::Kind is private.
|
||||
if err.is_parse() {
|
||||
ErrorKind::HttpParse
|
||||
} else if err.is_user() {
|
||||
ErrorKind::HttpUser
|
||||
} else if err.is_canceled() {
|
||||
ErrorKind::HttpCanceled
|
||||
} else if err.is_closed() {
|
||||
ErrorKind::HttpClosed
|
||||
} else {
|
||||
ErrorKind::HttpOther
|
||||
}
|
||||
}
|
||||
Repr::ImportMapErr(ref _err) => ErrorKind::ImportMapError,
|
||||
Repr::Diagnostic(ref _err) => ErrorKind::Diagnostic,
|
||||
Repr::JSError(ref _err) => ErrorKind::JSError,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_source_map<G: SourceMapGetter>(self, getter: &G) -> Self {
|
||||
if let Repr::JSError(js_error) = self.repr {
|
||||
return DenoError {
|
||||
repr: Repr::JSError(apply_source_map(&js_error, getter)),
|
||||
};
|
||||
} else {
|
||||
panic!("attempt to apply source map an unremappable error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DenoError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.repr {
|
||||
Repr::Simple(_kind, ref err_str) => f.pad(err_str),
|
||||
Repr::IoErr(ref err) => err.fmt(f),
|
||||
Repr::UrlErr(ref err) => err.fmt(f),
|
||||
Repr::HyperErr(ref err) => err.fmt(f),
|
||||
Repr::ImportMapErr(ref err) => f.pad(&err.msg),
|
||||
Repr::Diagnostic(ref err) => err.fmt(f),
|
||||
Repr::JSError(ref err) => JSErrorColor(err).fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DenoError {
|
||||
fn description(&self) -> &str {
|
||||
match self.repr {
|
||||
Repr::Simple(_kind, ref msg) => msg.as_str(),
|
||||
Repr::IoErr(ref err) => err.description(),
|
||||
Repr::UrlErr(ref err) => err.description(),
|
||||
Repr::HyperErr(ref err) => err.description(),
|
||||
Repr::ImportMapErr(ref err) => &err.msg,
|
||||
Repr::Diagnostic(ref err) => &err.items[0].message,
|
||||
Repr::JSError(ref err) => &err.description(),
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||
match self.repr {
|
||||
Repr::Simple(_kind, ref _msg) => None,
|
||||
Repr::IoErr(ref err) => Some(err),
|
||||
Repr::UrlErr(ref err) => Some(err),
|
||||
Repr::HyperErr(ref err) => Some(err),
|
||||
Repr::ImportMapErr(ref _err) => None,
|
||||
Repr::Diagnostic(ref _err) => None,
|
||||
Repr::JSError(ref err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for DenoError {
|
||||
#[inline]
|
||||
fn from(err: io::Error) -> Self {
|
||||
Self {
|
||||
repr: Repr::IoErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<url::ParseError> for DenoError {
|
||||
#[inline]
|
||||
fn from(err: url::ParseError) -> Self {
|
||||
Self {
|
||||
repr: Repr::UrlErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<hyper::Error> for DenoError {
|
||||
#[inline]
|
||||
fn from(err: hyper::Error) -> Self {
|
||||
Self {
|
||||
repr: Repr::HyperErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResolveAddrError> for DenoError {
|
||||
fn from(e: ResolveAddrError) -> Self {
|
||||
match e {
|
||||
ResolveAddrError::Syntax => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::InvalidInput,
|
||||
"invalid address syntax".to_string(),
|
||||
),
|
||||
},
|
||||
ResolveAddrError::Resolution(io_err) => Self {
|
||||
repr: Repr::IoErr(io_err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<UnixError> for DenoError {
|
||||
fn from(e: UnixError) -> Self {
|
||||
match e {
|
||||
UnixError::Sys(Errno::EPERM) => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::PermissionDenied,
|
||||
Errno::EPERM.desc().to_owned(),
|
||||
),
|
||||
},
|
||||
UnixError::Sys(Errno::EINVAL) => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::InvalidInput,
|
||||
Errno::EINVAL.desc().to_owned(),
|
||||
),
|
||||
},
|
||||
UnixError::Sys(Errno::ENOENT) => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::NotFound,
|
||||
Errno::ENOENT.desc().to_owned(),
|
||||
),
|
||||
},
|
||||
UnixError::Sys(err) => Self {
|
||||
repr: Repr::Simple(ErrorKind::UnixError, err.desc().to_owned()),
|
||||
},
|
||||
_ => Self {
|
||||
repr: Repr::Simple(ErrorKind::Other, format!("{}", e)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<import_map::ImportMapError> for DenoError {
|
||||
fn from(err: import_map::ImportMapError) -> Self {
|
||||
Self {
|
||||
repr: Repr::ImportMapErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diagnostics::Diagnostic> for DenoError {
|
||||
fn from(diagnostic: diagnostics::Diagnostic) -> Self {
|
||||
Self {
|
||||
repr: Repr::Diagnostic(diagnostic),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JSError> for DenoError {
|
||||
fn from(err: JSError) -> Self {
|
||||
Self {
|
||||
repr: Repr::JSError(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bad_resource() -> DenoError {
|
||||
new(ErrorKind::BadResource, String::from("bad resource id"))
|
||||
}
|
||||
|
||||
pub fn permission_denied() -> DenoError {
|
||||
new(
|
||||
ErrorKind::PermissionDenied,
|
||||
String::from("permission denied"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn op_not_implemented() -> DenoError {
|
||||
new(
|
||||
ErrorKind::OpNotAvailable,
|
||||
String::from("op not implemented"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn worker_init_failed() -> DenoError {
|
||||
// TODO(afinch7) pass worker error data through here
|
||||
new(
|
||||
ErrorKind::WorkerInitFailed,
|
||||
String::from("worker init failed"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn no_buffer_specified() -> DenoError {
|
||||
new(ErrorKind::InvalidInput, String::from("no buffer specified"))
|
||||
}
|
||||
|
||||
pub fn no_async_support() -> DenoError {
|
||||
new(
|
||||
ErrorKind::NoAsyncSupport,
|
||||
String::from("op doesn't support async calls"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn no_sync_support() -> DenoError {
|
||||
new(
|
||||
ErrorKind::NoSyncSupport,
|
||||
String::from("op doesn't support sync calls"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn err_check<R>(r: Result<R, DenoError>) {
|
||||
if let Err(e) = r {
|
||||
panic!(e.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ansi::strip_ansi_codes;
|
||||
use crate::diagnostics::Diagnostic;
|
||||
use crate::diagnostics::DiagnosticCategory;
|
||||
use crate::diagnostics::DiagnosticItem;
|
||||
use crate::import_map::ImportMapError;
|
||||
use deno::StackFrame;
|
||||
|
||||
fn js_error() -> JSError {
|
||||
JSError {
|
||||
message: "Error: foo bar".to_string(),
|
||||
source_line: None,
|
||||
script_resource_name: None,
|
||||
line_number: None,
|
||||
start_position: None,
|
||||
end_position: None,
|
||||
error_level: None,
|
||||
start_column: None,
|
||||
end_column: None,
|
||||
frames: vec![
|
||||
StackFrame {
|
||||
line: 4,
|
||||
column: 16,
|
||||
script_name: "foo_bar.ts".to_string(),
|
||||
function_name: "foo".to_string(),
|
||||
is_eval: false,
|
||||
is_constructor: false,
|
||||
is_wasm: false,
|
||||
},
|
||||
StackFrame {
|
||||
line: 5,
|
||||
column: 20,
|
||||
script_name: "bar_baz.ts".to_string(),
|
||||
function_name: "qat".to_string(),
|
||||
is_eval: false,
|
||||
is_constructor: false,
|
||||
is_wasm: false,
|
||||
},
|
||||
StackFrame {
|
||||
line: 1,
|
||||
column: 1,
|
||||
script_name: "deno_main.js".to_string(),
|
||||
function_name: "".to_string(),
|
||||
is_eval: false,
|
||||
is_constructor: false,
|
||||
is_wasm: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn diagnostic() -> Diagnostic {
|
||||
Diagnostic {
|
||||
items: vec![
|
||||
DiagnosticItem {
|
||||
message: "Example 1".to_string(),
|
||||
message_chain: None,
|
||||
code: 2322,
|
||||
category: DiagnosticCategory::Error,
|
||||
start_position: Some(267),
|
||||
end_position: Some(273),
|
||||
source_line: Some(" values: o => [".to_string()),
|
||||
line_number: Some(18),
|
||||
script_resource_name: Some(
|
||||
"deno/tests/complex_diagnostics.ts".to_string(),
|
||||
),
|
||||
start_column: Some(2),
|
||||
end_column: Some(8),
|
||||
related_information: None,
|
||||
},
|
||||
DiagnosticItem {
|
||||
message: "Example 2".to_string(),
|
||||
message_chain: None,
|
||||
code: 2000,
|
||||
category: DiagnosticCategory::Error,
|
||||
start_position: Some(2),
|
||||
end_position: Some(2),
|
||||
source_line: Some(" values: undefined,".to_string()),
|
||||
line_number: Some(128),
|
||||
script_resource_name: Some("/foo/bar.ts".to_string()),
|
||||
start_column: Some(2),
|
||||
end_column: Some(8),
|
||||
related_information: None,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
struct MockSourceMapGetter {}
|
||||
|
||||
impl SourceMapGetter for MockSourceMapGetter {
|
||||
fn get_source_map(&self, _script_name: &str) -> Option<Vec<u8>> {
|
||||
Some(vec![])
|
||||
}
|
||||
|
||||
fn get_source_line(
|
||||
&self,
|
||||
_script_name: &str,
|
||||
_line: usize,
|
||||
) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn io_error() -> io::Error {
|
||||
io::Error::from(io::ErrorKind::NotFound)
|
||||
}
|
||||
|
||||
fn url_error() -> url::ParseError {
|
||||
url::ParseError::EmptyHost
|
||||
}
|
||||
|
||||
fn import_map_error() -> ImportMapError {
|
||||
ImportMapError {
|
||||
msg: "an import map error".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_error() {
|
||||
let err = new(ErrorKind::NoError, "foo".to_string());
|
||||
assert_eq!(err.kind(), ErrorKind::NoError);
|
||||
assert_eq!(err.to_string(), "foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_io_error() {
|
||||
let err = DenoError::from(io_error());
|
||||
assert_eq!(err.kind(), ErrorKind::NotFound);
|
||||
assert_eq!(err.to_string(), "entity not found");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_url_error() {
|
||||
let err = DenoError::from(url_error());
|
||||
assert_eq!(err.kind(), ErrorKind::EmptyHost);
|
||||
assert_eq!(err.to_string(), "empty host");
|
||||
}
|
||||
|
||||
// TODO find a way to easily test tokio errors and unix errors
|
||||
|
||||
#[test]
|
||||
fn test_diagnostic() {
|
||||
let err = DenoError::from(diagnostic());
|
||||
assert_eq!(err.kind(), ErrorKind::Diagnostic);
|
||||
assert_eq!(strip_ansi_codes(&err.to_string()), "error TS2322: Example 1\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\nerror TS2000: Example 2\n\n► /foo/bar.ts:129:3\n\n129 values: undefined,\n ~~~~~~\n\n\nFound 2 errors.\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_js_error() {
|
||||
let err = DenoError::from(js_error());
|
||||
assert_eq!(err.kind(), ErrorKind::JSError);
|
||||
assert_eq!(strip_ansi_codes(&err.to_string()), "error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_import_map_error() {
|
||||
let err = DenoError::from(import_map_error());
|
||||
assert_eq!(err.kind(), ErrorKind::ImportMapError);
|
||||
assert_eq!(err.to_string(), "an import map error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_resource() {
|
||||
let err = bad_resource();
|
||||
assert_eq!(err.kind(), ErrorKind::BadResource);
|
||||
assert_eq!(err.to_string(), "bad resource id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_permission_denied() {
|
||||
let err = permission_denied();
|
||||
assert_eq!(err.kind(), ErrorKind::PermissionDenied);
|
||||
assert_eq!(err.to_string(), "permission denied");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_not_implemented() {
|
||||
let err = op_not_implemented();
|
||||
assert_eq!(err.kind(), ErrorKind::OpNotAvailable);
|
||||
assert_eq!(err.to_string(), "op not implemented");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worker_init_failed() {
|
||||
let err = worker_init_failed();
|
||||
assert_eq!(err.kind(), ErrorKind::WorkerInitFailed);
|
||||
assert_eq!(err.to_string(), "worker init failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_buffer_specified() {
|
||||
let err = no_buffer_specified();
|
||||
assert_eq!(err.kind(), ErrorKind::InvalidInput);
|
||||
assert_eq!(err.to_string(), "no buffer specified");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_async_support() {
|
||||
let err = no_async_support();
|
||||
assert_eq!(err.kind(), ErrorKind::NoAsyncSupport);
|
||||
assert_eq!(err.to_string(), "op doesn't support async calls");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_sync_support() {
|
||||
let err = no_sync_support();
|
||||
assert_eq!(err.kind(), ErrorKind::NoSyncSupport);
|
||||
assert_eq!(err.to_string(), "op doesn't support sync calls");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_apply_source_map_invalid() {
|
||||
let getter = MockSourceMapGetter {};
|
||||
let err = new(ErrorKind::NotFound, "not found".to_string());
|
||||
err.apply_source_map(&getter);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_err_check() {
|
||||
err_check(
|
||||
Err(new(ErrorKind::NotFound, "foo".to_string())) as Result<(), DenoError>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,20 +2,13 @@
|
|||
//! This module encodes TypeScript errors (diagnostics) into Rust structs and
|
||||
//! contains code for printing them to the console.
|
||||
use crate::ansi;
|
||||
use crate::fmt_errors::format_maybe_source_line;
|
||||
use crate::fmt_errors::format_maybe_source_name;
|
||||
use crate::fmt_errors::DisplayFormatter;
|
||||
use serde_json;
|
||||
use serde_json::value::Value;
|
||||
use std::fmt;
|
||||
|
||||
// A trait which specifies parts of a diagnostic like item needs to be able to
|
||||
// generate to conform its display to other diagnostic like items
|
||||
pub trait DisplayFormatter {
|
||||
fn format_category_and_code(&self) -> String;
|
||||
fn format_message(&self, level: usize) -> String;
|
||||
fn format_related_info(&self) -> String;
|
||||
fn format_source_line(&self, level: usize) -> String;
|
||||
fn format_source_name(&self, level: usize) -> String;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Diagnostic {
|
||||
pub items: Vec<DiagnosticItem>,
|
||||
|
@ -179,23 +172,21 @@ impl DiagnosticItem {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO should chare logic with cli/js_errors, possibly with JSError
|
||||
// implementing the `DisplayFormatter` trait.
|
||||
impl DisplayFormatter for DiagnosticItem {
|
||||
fn format_category_and_code(&self) -> String {
|
||||
let category = match self.category {
|
||||
DiagnosticCategory::Error => {
|
||||
format!("- {}", ansi::red("error".to_string()))
|
||||
format!("{}", ansi::red_bold("error".to_string()))
|
||||
}
|
||||
DiagnosticCategory::Warning => "- warn".to_string(),
|
||||
DiagnosticCategory::Debug => "- debug".to_string(),
|
||||
DiagnosticCategory::Info => "- info".to_string(),
|
||||
DiagnosticCategory::Warning => "warn".to_string(),
|
||||
DiagnosticCategory::Debug => "debug".to_string(),
|
||||
DiagnosticCategory::Info => "info".to_string(),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
|
||||
let code = ansi::grey(format!(" TS{}:", self.code.to_string())).to_string();
|
||||
let code = ansi::bold(format!(" TS{}", self.code.to_string())).to_string();
|
||||
|
||||
format!("{}{} ", category, code)
|
||||
format!("{}{}: ", category, code)
|
||||
}
|
||||
|
||||
fn format_message(&self, level: usize) -> String {
|
||||
|
@ -229,10 +220,10 @@ impl DisplayFormatter for DiagnosticItem {
|
|||
for related_diagnostic in related_information {
|
||||
let rd = &related_diagnostic;
|
||||
s.push_str(&format!(
|
||||
"\n{}{}{}\n",
|
||||
rd.format_source_name(2),
|
||||
"\n{}\n\n ► {}{}\n",
|
||||
rd.format_message(2),
|
||||
rd.format_source_name(),
|
||||
rd.format_source_line(4),
|
||||
rd.format_message(4),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -240,74 +231,24 @@ impl DisplayFormatter for DiagnosticItem {
|
|||
}
|
||||
|
||||
fn format_source_line(&self, level: usize) -> String {
|
||||
if self.source_line.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let source_line = self.source_line.as_ref().unwrap();
|
||||
// sometimes source_line gets set with an empty string, which then outputs
|
||||
// an empty source line when displayed, so need just short circuit here
|
||||
if source_line.is_empty() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
assert!(self.line_number.is_some());
|
||||
assert!(self.start_column.is_some());
|
||||
assert!(self.end_column.is_some());
|
||||
let line = (1 + self.line_number.unwrap()).to_string();
|
||||
let line_color = ansi::black_on_white(line.to_string());
|
||||
let line_len = line.clone().len();
|
||||
let line_padding =
|
||||
ansi::black_on_white(format!("{:indent$}", "", indent = line_len))
|
||||
.to_string();
|
||||
let mut s = String::new();
|
||||
let start_column = self.start_column.unwrap();
|
||||
let end_column = self.end_column.unwrap();
|
||||
// TypeScript uses `~` always, but V8 would utilise `^` always, even when
|
||||
// doing ranges, so here, if we only have one marker (very common with V8
|
||||
// errors) we will use `^` instead.
|
||||
let underline_char = if (end_column - start_column) <= 1 {
|
||||
'^'
|
||||
} else {
|
||||
'~'
|
||||
};
|
||||
for i in 0..end_column {
|
||||
if i >= start_column {
|
||||
s.push(underline_char);
|
||||
} else {
|
||||
s.push(' ');
|
||||
}
|
||||
}
|
||||
let color_underline = match self.category {
|
||||
DiagnosticCategory::Error => ansi::red(s).to_string(),
|
||||
_ => ansi::cyan(s).to_string(),
|
||||
};
|
||||
|
||||
let indent = format!("{:indent$}", "", indent = level);
|
||||
|
||||
format!(
|
||||
"\n\n{}{} {}\n{}{} {}\n",
|
||||
indent, line_color, source_line, indent, line_padding, color_underline
|
||||
format_maybe_source_line(
|
||||
self.source_line.clone(),
|
||||
self.line_number,
|
||||
self.start_column,
|
||||
self.end_column,
|
||||
match self.category {
|
||||
DiagnosticCategory::Error => true,
|
||||
_ => false,
|
||||
},
|
||||
level,
|
||||
)
|
||||
}
|
||||
|
||||
fn format_source_name(&self, level: usize) -> String {
|
||||
if self.script_resource_name.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let script_name = ansi::cyan(self.script_resource_name.clone().unwrap());
|
||||
assert!(self.line_number.is_some());
|
||||
assert!(self.start_column.is_some());
|
||||
let line = ansi::yellow((1 + self.line_number.unwrap()).to_string());
|
||||
let column = ansi::yellow((1 + self.start_column.unwrap()).to_string());
|
||||
format!(
|
||||
"{:indent$}{}:{}:{} ",
|
||||
"",
|
||||
script_name,
|
||||
line,
|
||||
column,
|
||||
indent = level
|
||||
fn format_source_name(&self) -> String {
|
||||
format_maybe_source_name(
|
||||
self.script_resource_name.clone(),
|
||||
self.line_number,
|
||||
self.start_column,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -316,15 +257,13 @@ impl fmt::Display for DiagnosticItem {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}{}{}",
|
||||
self.format_source_name(0),
|
||||
"{}{}\n\n► {}{}{}",
|
||||
self.format_category_and_code(),
|
||||
self.format_message(0),
|
||||
self.format_source_name(),
|
||||
self.format_source_line(0),
|
||||
self.format_related_info(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,14 +594,14 @@ mod tests {
|
|||
#[test]
|
||||
fn diagnostic_to_string1() {
|
||||
let d = diagnostic1();
|
||||
let expected = "deno/tests/complex_diagnostics.ts:19:3 - error TS2322: Type \'(o: T) => { v: any; f: (x: B) => string; }[]\' is not assignable to type \'(r: B) => Value<B>[]\'.\n Types of parameters \'o\' and \'r\' are incompatible.\n Type \'B\' is not assignable to type \'T\'.\n\n19 values: o => [\n ~~~~~~\n\n deno/tests/complex_diagnostics.ts:7:3 \n\n 7 values?: (r: T) => Array<Value<T>>;\n ~~~~~~\n The expected type comes from property \'values\' which is declared here on type \'SettingsInterface<B>\'\n";
|
||||
let expected = "error TS2322: Type \'(o: T) => { v: any; f: (x: B) => string; }[]\' is not assignable to type \'(r: B) => Value<B>[]\'.\n Types of parameters \'o\' and \'r\' are incompatible.\n Type \'B\' is not assignable to type \'T\'.\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\n The expected type comes from property \'values\' which is declared here on type \'SettingsInterface<B>\'\n\n ► deno/tests/complex_diagnostics.ts:7:3\n\n 7 values?: (r: T) => Array<Value<T>>;\n ~~~~~~\n\n";
|
||||
assert_eq!(expected, strip_ansi_codes(&d.to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostic_to_string2() {
|
||||
let d = diagnostic2();
|
||||
let expected = "deno/tests/complex_diagnostics.ts:19:3 - error TS2322: Example 1\n\n19 values: o => [\n ~~~~~~\n\n/foo/bar.ts:129:3 - error TS2000: Example 2\n\n129 values: undefined,\n ~~~~~~\n\n\nFound 2 errors.\n";
|
||||
let expected = "error TS2322: Example 1\n\n► deno/tests/complex_diagnostics.ts:19:3\n\n19 values: o => [\n ~~~~~~\n\nerror TS2000: Example 2\n\n► /foo/bar.ts:129:3\n\n129 values: undefined,\n ~~~~~~\n\n\nFound 2 errors.\n";
|
||||
assert_eq!(expected, strip_ansi_codes(&d.to_string()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,27 +124,27 @@ pub fn dispatch_minimal(
|
|||
}
|
||||
|
||||
mod ops {
|
||||
use crate::errors;
|
||||
use crate::deno_error;
|
||||
use crate::resources;
|
||||
use crate::tokio_write;
|
||||
use deno::PinnedBuf;
|
||||
use futures::Future;
|
||||
|
||||
type MinimalOp = dyn Future<Item = i32, Error = errors::DenoError> + Send;
|
||||
type MinimalOp = dyn Future<Item = i32, Error = deno_error::DenoError> + Send;
|
||||
|
||||
pub fn read(rid: i32, zero_copy: Option<PinnedBuf>) -> Box<MinimalOp> {
|
||||
debug!("read rid={}", rid);
|
||||
let zero_copy = match zero_copy {
|
||||
None => {
|
||||
return Box::new(futures::future::err(errors::no_buffer_specified()))
|
||||
return Box::new(futures::future::err(deno_error::no_buffer_specified()))
|
||||
}
|
||||
Some(buf) => buf,
|
||||
};
|
||||
match resources::lookup(rid as u32) {
|
||||
None => Box::new(futures::future::err(errors::bad_resource())),
|
||||
None => Box::new(futures::future::err(deno_error::bad_resource())),
|
||||
Some(resource) => Box::new(
|
||||
tokio::io::read(resource, zero_copy)
|
||||
.map_err(errors::DenoError::from)
|
||||
.map_err(deno_error::DenoError::from)
|
||||
.and_then(move |(_resource, _buf, nread)| Ok(nread as i32)),
|
||||
),
|
||||
}
|
||||
|
@ -154,15 +154,15 @@ mod ops {
|
|||
debug!("write rid={}", rid);
|
||||
let zero_copy = match zero_copy {
|
||||
None => {
|
||||
return Box::new(futures::future::err(errors::no_buffer_specified()))
|
||||
return Box::new(futures::future::err(deno_error::no_buffer_specified()))
|
||||
}
|
||||
Some(buf) => buf,
|
||||
};
|
||||
match resources::lookup(rid as u32) {
|
||||
None => Box::new(futures::future::err(errors::bad_resource())),
|
||||
None => Box::new(futures::future::err(deno_error::bad_resource())),
|
||||
Some(resource) => Box::new(
|
||||
tokio_write::write(resource, zero_copy)
|
||||
.map_err(errors::DenoError::from)
|
||||
.map_err(deno_error::DenoError::from)
|
||||
.and_then(move |(_resource, _buf, nwritten)| Ok(nwritten as i32)),
|
||||
),
|
||||
}
|
||||
|
|
295
cli/errors.rs
295
cli/errors.rs
|
@ -1,295 +0,0 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::import_map::ImportMapError;
|
||||
use crate::js_errors::JSErrorColor;
|
||||
pub use crate::msg::ErrorKind;
|
||||
use crate::resolve_addr::ResolveAddrError;
|
||||
use deno::JSError;
|
||||
use hyper;
|
||||
#[cfg(unix)]
|
||||
use nix::{errno::Errno, Error as UnixError};
|
||||
use std;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use url;
|
||||
|
||||
pub type DenoResult<T> = std::result::Result<T, DenoError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DenoError {
|
||||
repr: Repr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Repr {
|
||||
Simple(ErrorKind, String),
|
||||
IoErr(io::Error),
|
||||
UrlErr(url::ParseError),
|
||||
HyperErr(hyper::Error),
|
||||
ImportMapErr(ImportMapError),
|
||||
}
|
||||
|
||||
pub fn new(kind: ErrorKind, msg: String) -> DenoError {
|
||||
DenoError {
|
||||
repr: Repr::Simple(kind, msg),
|
||||
}
|
||||
}
|
||||
|
||||
impl DenoError {
|
||||
pub fn kind(&self) -> ErrorKind {
|
||||
match self.repr {
|
||||
Repr::Simple(kind, ref _msg) => kind,
|
||||
// Repr::Simple(kind) => kind,
|
||||
Repr::IoErr(ref err) => {
|
||||
use std::io::ErrorKind::*;
|
||||
match err.kind() {
|
||||
NotFound => ErrorKind::NotFound,
|
||||
PermissionDenied => ErrorKind::PermissionDenied,
|
||||
ConnectionRefused => ErrorKind::ConnectionRefused,
|
||||
ConnectionReset => ErrorKind::ConnectionReset,
|
||||
ConnectionAborted => ErrorKind::ConnectionAborted,
|
||||
NotConnected => ErrorKind::NotConnected,
|
||||
AddrInUse => ErrorKind::AddrInUse,
|
||||
AddrNotAvailable => ErrorKind::AddrNotAvailable,
|
||||
BrokenPipe => ErrorKind::BrokenPipe,
|
||||
AlreadyExists => ErrorKind::AlreadyExists,
|
||||
WouldBlock => ErrorKind::WouldBlock,
|
||||
InvalidInput => ErrorKind::InvalidInput,
|
||||
InvalidData => ErrorKind::InvalidData,
|
||||
TimedOut => ErrorKind::TimedOut,
|
||||
Interrupted => ErrorKind::Interrupted,
|
||||
WriteZero => ErrorKind::WriteZero,
|
||||
Other => ErrorKind::Other,
|
||||
UnexpectedEof => ErrorKind::UnexpectedEof,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Repr::UrlErr(ref err) => {
|
||||
use url::ParseError::*;
|
||||
match err {
|
||||
EmptyHost => ErrorKind::EmptyHost,
|
||||
IdnaError => ErrorKind::IdnaError,
|
||||
InvalidPort => ErrorKind::InvalidPort,
|
||||
InvalidIpv4Address => ErrorKind::InvalidIpv4Address,
|
||||
InvalidIpv6Address => ErrorKind::InvalidIpv6Address,
|
||||
InvalidDomainCharacter => ErrorKind::InvalidDomainCharacter,
|
||||
RelativeUrlWithoutBase => ErrorKind::RelativeUrlWithoutBase,
|
||||
RelativeUrlWithCannotBeABaseBase => {
|
||||
ErrorKind::RelativeUrlWithCannotBeABaseBase
|
||||
}
|
||||
SetHostOnCannotBeABaseUrl => ErrorKind::SetHostOnCannotBeABaseUrl,
|
||||
Overflow => ErrorKind::Overflow,
|
||||
}
|
||||
}
|
||||
Repr::HyperErr(ref err) => {
|
||||
// For some reason hyper::errors::Kind is private.
|
||||
if err.is_parse() {
|
||||
ErrorKind::HttpParse
|
||||
} else if err.is_user() {
|
||||
ErrorKind::HttpUser
|
||||
} else if err.is_canceled() {
|
||||
ErrorKind::HttpCanceled
|
||||
} else if err.is_closed() {
|
||||
ErrorKind::HttpClosed
|
||||
} else {
|
||||
ErrorKind::HttpOther
|
||||
}
|
||||
}
|
||||
Repr::ImportMapErr(ref _err) => ErrorKind::ImportMapError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DenoError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.repr {
|
||||
Repr::Simple(_kind, ref err_str) => f.pad(err_str),
|
||||
Repr::IoErr(ref err) => err.fmt(f),
|
||||
Repr::UrlErr(ref err) => err.fmt(f),
|
||||
Repr::HyperErr(ref err) => err.fmt(f),
|
||||
Repr::ImportMapErr(ref err) => f.pad(&err.msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DenoError {
|
||||
fn description(&self) -> &str {
|
||||
match self.repr {
|
||||
Repr::Simple(_kind, ref msg) => msg.as_str(),
|
||||
Repr::IoErr(ref err) => err.description(),
|
||||
Repr::UrlErr(ref err) => err.description(),
|
||||
Repr::HyperErr(ref err) => err.description(),
|
||||
Repr::ImportMapErr(ref err) => &err.msg,
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||
match self.repr {
|
||||
Repr::Simple(_kind, ref _msg) => None,
|
||||
Repr::IoErr(ref err) => Some(err),
|
||||
Repr::UrlErr(ref err) => Some(err),
|
||||
Repr::HyperErr(ref err) => Some(err),
|
||||
Repr::ImportMapErr(ref _err) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for DenoError {
|
||||
#[inline]
|
||||
fn from(err: io::Error) -> Self {
|
||||
Self {
|
||||
repr: Repr::IoErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<url::ParseError> for DenoError {
|
||||
#[inline]
|
||||
fn from(err: url::ParseError) -> Self {
|
||||
Self {
|
||||
repr: Repr::UrlErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<hyper::Error> for DenoError {
|
||||
#[inline]
|
||||
fn from(err: hyper::Error) -> Self {
|
||||
Self {
|
||||
repr: Repr::HyperErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResolveAddrError> for DenoError {
|
||||
fn from(e: ResolveAddrError) -> Self {
|
||||
match e {
|
||||
ResolveAddrError::Syntax => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::InvalidInput,
|
||||
"invalid address syntax".to_string(),
|
||||
),
|
||||
},
|
||||
ResolveAddrError::Resolution(io_err) => Self {
|
||||
repr: Repr::IoErr(io_err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<UnixError> for DenoError {
|
||||
fn from(e: UnixError) -> Self {
|
||||
match e {
|
||||
UnixError::Sys(Errno::EPERM) => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::PermissionDenied,
|
||||
Errno::EPERM.desc().to_owned(),
|
||||
),
|
||||
},
|
||||
UnixError::Sys(Errno::EINVAL) => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::InvalidInput,
|
||||
Errno::EINVAL.desc().to_owned(),
|
||||
),
|
||||
},
|
||||
UnixError::Sys(Errno::ENOENT) => Self {
|
||||
repr: Repr::Simple(
|
||||
ErrorKind::NotFound,
|
||||
Errno::ENOENT.desc().to_owned(),
|
||||
),
|
||||
},
|
||||
UnixError::Sys(err) => Self {
|
||||
repr: Repr::Simple(ErrorKind::UnixError, err.desc().to_owned()),
|
||||
},
|
||||
_ => Self {
|
||||
repr: Repr::Simple(ErrorKind::Other, format!("{}", e)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImportMapError> for DenoError {
|
||||
fn from(err: ImportMapError) -> Self {
|
||||
Self {
|
||||
repr: Repr::ImportMapErr(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bad_resource() -> DenoError {
|
||||
new(ErrorKind::BadResource, String::from("bad resource id"))
|
||||
}
|
||||
|
||||
pub fn permission_denied() -> DenoError {
|
||||
new(
|
||||
ErrorKind::PermissionDenied,
|
||||
String::from("permission denied"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn op_not_implemented() -> DenoError {
|
||||
new(ErrorKind::OpNotAvaiable, String::from("op not implemented"))
|
||||
}
|
||||
|
||||
pub fn worker_init_failed() -> DenoError {
|
||||
// TODO(afinch7) pass worker error data through here
|
||||
new(
|
||||
ErrorKind::WorkerInitFailed,
|
||||
String::from("worker init failed"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn no_buffer_specified() -> DenoError {
|
||||
new(ErrorKind::InvalidInput, String::from("no buffer specified"))
|
||||
}
|
||||
|
||||
pub fn no_async_support() -> DenoError {
|
||||
new(
|
||||
ErrorKind::NoAsyncSupport,
|
||||
String::from("op doesn't support async calls"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn no_sync_support() -> DenoError {
|
||||
new(
|
||||
ErrorKind::NoSyncSupport,
|
||||
String::from("op doesn't support sync calls"),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RustOrJsError {
|
||||
Rust(DenoError),
|
||||
Js(JSError),
|
||||
}
|
||||
|
||||
impl From<DenoError> for RustOrJsError {
|
||||
fn from(e: DenoError) -> Self {
|
||||
RustOrJsError::Rust(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JSError> for RustOrJsError {
|
||||
fn from(e: JSError) -> Self {
|
||||
RustOrJsError::Js(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RustOrJsError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RustOrJsError::Rust(e) => e.fmt(f),
|
||||
RustOrJsError::Js(e) => JSErrorColor(e).fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ry) This is ugly. They are essentially the same type.
|
||||
impl From<deno::JSErrorOr<DenoError>> for RustOrJsError {
|
||||
fn from(e: deno::JSErrorOr<DenoError>) -> Self {
|
||||
match e {
|
||||
deno::JSErrorOr::JSError(err) => RustOrJsError::Js(err),
|
||||
deno::JSErrorOr::Other(err) => RustOrJsError::Rust(err),
|
||||
}
|
||||
}
|
||||
}
|
289
cli/fmt_errors.rs
Normal file
289
cli/fmt_errors.rs
Normal file
|
@ -0,0 +1,289 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
//! This mod provides DenoError to unify errors across Deno.
|
||||
use crate::ansi;
|
||||
use deno::JSError;
|
||||
use deno::StackFrame;
|
||||
use std::fmt;
|
||||
|
||||
/// A trait which specifies parts of a diagnostic like item needs to be able to
|
||||
/// generate to conform its display to other diagnostic like items
|
||||
pub trait DisplayFormatter {
|
||||
fn format_category_and_code(&self) -> String;
|
||||
fn format_message(&self, level: usize) -> String;
|
||||
fn format_related_info(&self) -> String;
|
||||
fn format_source_line(&self, level: usize) -> String;
|
||||
fn format_source_name(&self) -> String;
|
||||
}
|
||||
|
||||
fn format_source_name(script_name: String, line: i64, column: i64) -> String {
|
||||
let script_name_c = ansi::cyan(script_name);
|
||||
let line_c = ansi::yellow((1 + line).to_string());
|
||||
let column_c = ansi::yellow((1 + column).to_string());
|
||||
format!("{}:{}:{}", script_name_c, line_c, column_c,)
|
||||
}
|
||||
|
||||
/// Formats optional source, line and column into a single string.
|
||||
pub fn format_maybe_source_name(
|
||||
script_name: Option<String>,
|
||||
line: Option<i64>,
|
||||
column: Option<i64>,
|
||||
) -> String {
|
||||
if script_name.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
assert!(line.is_some());
|
||||
assert!(column.is_some());
|
||||
format_source_name(script_name.unwrap(), line.unwrap(), column.unwrap())
|
||||
}
|
||||
|
||||
/// Take an optional source line and associated information to format it into
|
||||
/// a pretty printed version of that line.
|
||||
pub fn format_maybe_source_line(
|
||||
source_line: Option<String>,
|
||||
line_number: Option<i64>,
|
||||
start_column: Option<i64>,
|
||||
end_column: Option<i64>,
|
||||
is_error: bool,
|
||||
level: usize,
|
||||
) -> String {
|
||||
if source_line.is_none() || line_number.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let source_line = source_line.as_ref().unwrap();
|
||||
// sometimes source_line gets set with an empty string, which then outputs
|
||||
// an empty source line when displayed, so need just short circuit here
|
||||
if source_line.is_empty() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
assert!(start_column.is_some());
|
||||
assert!(end_column.is_some());
|
||||
let line = (1 + line_number.unwrap()).to_string();
|
||||
let line_color = ansi::black_on_white(line.to_string());
|
||||
let line_len = line.clone().len();
|
||||
let line_padding =
|
||||
ansi::black_on_white(format!("{:indent$}", "", indent = line_len))
|
||||
.to_string();
|
||||
let mut s = String::new();
|
||||
let start_column = start_column.unwrap();
|
||||
let end_column = end_column.unwrap();
|
||||
// TypeScript uses `~` always, but V8 would utilise `^` always, even when
|
||||
// doing ranges, so here, if we only have one marker (very common with V8
|
||||
// errors) we will use `^` instead.
|
||||
let underline_char = if (end_column - start_column) <= 1 {
|
||||
'^'
|
||||
} else {
|
||||
'~'
|
||||
};
|
||||
for i in 0..end_column {
|
||||
if i >= start_column {
|
||||
s.push(underline_char);
|
||||
} else {
|
||||
s.push(' ');
|
||||
}
|
||||
}
|
||||
let color_underline = if is_error {
|
||||
ansi::red(s).to_string()
|
||||
} else {
|
||||
ansi::cyan(s).to_string()
|
||||
};
|
||||
|
||||
let indent = format!("{:indent$}", "", indent = level);
|
||||
|
||||
format!(
|
||||
"\n\n{}{} {}\n{}{} {}\n",
|
||||
indent, line_color, source_line, indent, line_padding, color_underline
|
||||
)
|
||||
}
|
||||
|
||||
/// Format a message to preface with `error: ` with ansi codes for red.
|
||||
pub fn format_error_message(msg: String) -> String {
|
||||
let preamble = ansi::red("error:".to_string());
|
||||
format!("{} {}", preamble, msg)
|
||||
}
|
||||
|
||||
/// Wrapper around JSError which provides color to_string.
|
||||
pub struct JSErrorColor<'a>(pub &'a JSError);
|
||||
|
||||
impl<'a> DisplayFormatter for JSErrorColor<'a> {
|
||||
fn format_category_and_code(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
fn format_message(&self, _level: usize) -> String {
|
||||
format!(
|
||||
"{}{}",
|
||||
ansi::red_bold("error: ".to_string()),
|
||||
self.0.message.clone()
|
||||
)
|
||||
}
|
||||
|
||||
fn format_related_info(&self) -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
fn format_source_line(&self, level: usize) -> String {
|
||||
format_maybe_source_line(
|
||||
self.0.source_line.clone(),
|
||||
self.0.line_number,
|
||||
self.0.start_column,
|
||||
self.0.end_column,
|
||||
true,
|
||||
level,
|
||||
)
|
||||
}
|
||||
|
||||
fn format_source_name(&self) -> String {
|
||||
let e = self.0;
|
||||
if e.script_resource_name.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
format!(
|
||||
"\n► {}",
|
||||
format_maybe_source_name(
|
||||
e.script_resource_name.clone(),
|
||||
e.line_number,
|
||||
e.start_column,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for JSErrorColor<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}{}{}",
|
||||
self.format_message(0),
|
||||
self.format_source_name(),
|
||||
self.format_source_line(0),
|
||||
)?;
|
||||
|
||||
for frame in &self.0.frames {
|
||||
write!(f, "\n{}", StackFrameColor(&frame).to_string())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct StackFrameColor<'a>(&'a StackFrame);
|
||||
|
||||
impl<'a> fmt::Display for StackFrameColor<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let frame = self.0;
|
||||
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
||||
let function_name = ansi::italic_bold(frame.function_name.clone());
|
||||
let script_line_column =
|
||||
format_source_name(frame.script_name.clone(), frame.line, frame.column);
|
||||
|
||||
if !frame.function_name.is_empty() {
|
||||
write!(f, " at {} ({})", function_name, script_line_column)
|
||||
} else if frame.is_eval {
|
||||
write!(f, " at eval ({})", script_line_column)
|
||||
} else {
|
||||
write!(f, " at {}", script_line_column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ansi::strip_ansi_codes;
|
||||
|
||||
fn error1() -> JSError {
|
||||
JSError {
|
||||
message: "Error: foo bar".to_string(),
|
||||
source_line: None,
|
||||
script_resource_name: None,
|
||||
line_number: None,
|
||||
start_position: None,
|
||||
end_position: None,
|
||||
error_level: None,
|
||||
start_column: None,
|
||||
end_column: None,
|
||||
frames: vec![
|
||||
StackFrame {
|
||||
line: 4,
|
||||
column: 16,
|
||||
script_name: "foo_bar.ts".to_string(),
|
||||
function_name: "foo".to_string(),
|
||||
is_eval: false,
|
||||
is_constructor: false,
|
||||
is_wasm: false,
|
||||
},
|
||||
StackFrame {
|
||||
line: 5,
|
||||
column: 20,
|
||||
script_name: "bar_baz.ts".to_string(),
|
||||
function_name: "qat".to_string(),
|
||||
is_eval: false,
|
||||
is_constructor: false,
|
||||
is_wasm: false,
|
||||
},
|
||||
StackFrame {
|
||||
line: 1,
|
||||
column: 1,
|
||||
script_name: "deno_main.js".to_string(),
|
||||
function_name: "".to_string(),
|
||||
is_eval: false,
|
||||
is_constructor: false,
|
||||
is_wasm: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn js_error_to_string() {
|
||||
let e = error1();
|
||||
assert_eq!("error: Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2", strip_ansi_codes(&JSErrorColor(&e).to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_none_source_name() {
|
||||
let actual = format_maybe_source_name(None, None, None);
|
||||
assert_eq!(actual, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_some_source_name() {
|
||||
let actual = format_maybe_source_name(
|
||||
Some("file://foo/bar.ts".to_string()),
|
||||
Some(1),
|
||||
Some(2),
|
||||
);
|
||||
assert_eq!(strip_ansi_codes(&actual), "file://foo/bar.ts:2:3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_none_source_line() {
|
||||
let actual = format_maybe_source_line(None, None, None, None, false, 0);
|
||||
assert_eq!(actual, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_some_source_line() {
|
||||
let actual = format_maybe_source_line(
|
||||
Some("console.log('foo');".to_string()),
|
||||
Some(8),
|
||||
Some(8),
|
||||
Some(11),
|
||||
true,
|
||||
0,
|
||||
);
|
||||
assert_eq!(
|
||||
strip_ansi_codes(&actual),
|
||||
"\n\n9 console.log(\'foo\');\n ~~~\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_error_message() {
|
||||
let actual = format_error_message("foo".to_string());
|
||||
assert_eq!(strip_ansi_codes(&actual), "error: foo");
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use std::os::unix::fs::DirBuilderExt;
|
|||
#[cfg(any(unix))]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error::DenoResult;
|
||||
|
||||
pub fn write_file<T: AsRef<[u8]>>(
|
||||
filename: &Path,
|
||||
|
@ -115,7 +115,7 @@ pub fn normalize_path(path: &Path) -> String {
|
|||
|
||||
#[cfg(unix)]
|
||||
pub fn chown(path: &str, uid: u32, gid: u32) -> DenoResult<()> {
|
||||
use crate::errors::DenoError;
|
||||
use crate::deno_error::DenoError;
|
||||
let nix_uid = Uid::from_raw(uid);
|
||||
let nix_gid = Gid::from_raw(gid);
|
||||
unix_chown(path, Option::Some(nix_uid), Option::Some(nix_gid))
|
||||
|
@ -126,6 +126,6 @@ pub fn chown(path: &str, uid: u32, gid: u32) -> DenoResult<()> {
|
|||
pub fn chown(_path: &str, _uid: u32, _gid: u32) -> DenoResult<()> {
|
||||
// Noop
|
||||
// TODO: implement chown for Windows
|
||||
use crate::errors;
|
||||
Err(errors::op_not_implemented())
|
||||
use crate::deno_error;
|
||||
Err(deno_error::op_not_implemented())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::errors;
|
||||
use crate::errors::DenoError;
|
||||
use crate::deno_error;
|
||||
use crate::deno_error::DenoError;
|
||||
#[cfg(test)]
|
||||
use futures::future::{loop_fn, Loop};
|
||||
use futures::{future, Future, Stream};
|
||||
|
@ -58,7 +58,7 @@ fn resolve_uri_from_location(base_uri: &Uri, location: &str) -> Uri {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error::DenoResult;
|
||||
#[cfg(test)]
|
||||
use crate::tokio_util;
|
||||
#[cfg(test)]
|
||||
|
@ -108,8 +108,8 @@ pub fn fetch_string_once(
|
|||
} else if response.status().is_client_error()
|
||||
|| response.status().is_server_error()
|
||||
{
|
||||
return Box::new(future::err(errors::new(
|
||||
errors::ErrorKind::Other,
|
||||
return Box::new(future::err(deno_error::new(
|
||||
deno_error::ErrorKind::Other,
|
||||
format!("Import '{}' failed: {}", &url, response.status()),
|
||||
)));
|
||||
}
|
||||
|
@ -165,8 +165,8 @@ pub fn fetch_string(
|
|||
return Ok(Loop::Continue((client, new_url)));
|
||||
}
|
||||
if !response.status().is_success() {
|
||||
return Err(errors::new(
|
||||
errors::ErrorKind::NotFound,
|
||||
return Err(deno_error::new(
|
||||
deno_error::ErrorKind::NotFound,
|
||||
"module not found".to_string(),
|
||||
));
|
||||
}
|
||||
|
|
19
cli/main.rs
19
cli/main.rs
|
@ -17,16 +17,16 @@ extern crate rand;
|
|||
mod ansi;
|
||||
pub mod compiler;
|
||||
pub mod deno_dir;
|
||||
pub mod deno_error;
|
||||
pub mod diagnostics;
|
||||
mod dispatch_minimal;
|
||||
pub mod errors;
|
||||
pub mod flags;
|
||||
pub mod fmt_errors;
|
||||
mod fs;
|
||||
mod global_timer;
|
||||
mod http_body;
|
||||
mod http_util;
|
||||
mod import_map;
|
||||
pub mod js_errors;
|
||||
pub mod msg;
|
||||
pub mod msg_util;
|
||||
pub mod ops;
|
||||
|
@ -36,6 +36,7 @@ mod repl;
|
|||
pub mod resolve_addr;
|
||||
pub mod resources;
|
||||
mod signal;
|
||||
pub mod source_maps;
|
||||
mod startup_data;
|
||||
pub mod state;
|
||||
mod tokio_util;
|
||||
|
@ -44,7 +45,7 @@ pub mod version;
|
|||
pub mod worker;
|
||||
|
||||
use crate::compiler::bundle_async;
|
||||
use crate::errors::RustOrJsError;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::progress::Progress;
|
||||
use crate::state::ThreadSafeState;
|
||||
use crate::worker::Worker;
|
||||
|
@ -82,14 +83,14 @@ impl log::Log for Logger {
|
|||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
fn print_err_and_exit(err: RustOrJsError) {
|
||||
fn print_err_and_exit(err: DenoError) {
|
||||
eprintln!("{}", err.to_string());
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn js_check<E>(r: Result<(), E>)
|
||||
where
|
||||
E: Into<RustOrJsError>,
|
||||
E: Into<DenoError>,
|
||||
{
|
||||
if let Err(err) = r {
|
||||
print_err_and_exit(err.into());
|
||||
|
@ -258,9 +259,7 @@ fn xeval_command(flags: DenoFlags, argv: Vec<String>) {
|
|||
.then(|result| {
|
||||
js_check(result);
|
||||
Ok(())
|
||||
}).map_err(|(err, _worker): (RustOrJsError, Worker)| {
|
||||
print_err_and_exit(err)
|
||||
})
|
||||
}).map_err(|(err, _worker): (DenoError, Worker)| print_err_and_exit(err))
|
||||
});
|
||||
tokio_util::run(main_future);
|
||||
}
|
||||
|
@ -295,9 +294,7 @@ fn run_repl(flags: DenoFlags, argv: Vec<String>) {
|
|||
.then(|result| {
|
||||
js_check(result);
|
||||
Ok(())
|
||||
}).map_err(|(err, _worker): (RustOrJsError, Worker)| {
|
||||
print_err_and_exit(err)
|
||||
})
|
||||
}).map_err(|(err, _worker): (DenoError, Worker)| print_err_and_exit(err))
|
||||
});
|
||||
tokio_util::run(main_future);
|
||||
}
|
||||
|
|
|
@ -133,12 +133,16 @@ enum ErrorKind: byte {
|
|||
// custom errors
|
||||
InvalidUri,
|
||||
InvalidSeekMode,
|
||||
OpNotAvaiable,
|
||||
OpNotAvailable,
|
||||
WorkerInitFailed,
|
||||
UnixError,
|
||||
NoAsyncSupport,
|
||||
NoSyncSupport,
|
||||
ImportMapError,
|
||||
|
||||
// other kinds
|
||||
Diagnostic,
|
||||
JSError,
|
||||
}
|
||||
|
||||
table Cwd {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
// Helpers for serialization.
|
||||
use crate::errors;
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error;
|
||||
use crate::deno_error::DenoResult;
|
||||
use crate::msg;
|
||||
|
||||
use flatbuffers;
|
||||
|
@ -104,7 +104,7 @@ pub fn deserialize_request(
|
|||
|
||||
let u = header_msg.url().unwrap();
|
||||
let u = Uri::from_str(u)
|
||||
.map_err(|e| errors::new(msg::ErrorKind::InvalidUri, e.to_string()))?;
|
||||
.map_err(|e| deno_error::new(msg::ErrorKind::InvalidUri, e.to_string()))?;
|
||||
*r.uri_mut() = u;
|
||||
|
||||
if let Some(method) = header_msg.method() {
|
||||
|
|
101
cli/ops.rs
101
cli/ops.rs
|
@ -2,14 +2,15 @@
|
|||
use atty;
|
||||
use crate::ansi;
|
||||
use crate::deno_dir::resolve_path;
|
||||
use crate::deno_error;
|
||||
use crate::deno_error::err_check;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::deno_error::DenoResult;
|
||||
use crate::deno_error::ErrorKind;
|
||||
use crate::dispatch_minimal::dispatch_minimal;
|
||||
use crate::dispatch_minimal::parse_min_record;
|
||||
use crate::errors;
|
||||
use crate::errors::{DenoError, DenoResult, ErrorKind};
|
||||
use crate::fs as deno_fs;
|
||||
use crate::http_util;
|
||||
use crate::js_errors::apply_source_map;
|
||||
use crate::js_errors::JSErrorColor;
|
||||
use crate::msg;
|
||||
use crate::msg_util;
|
||||
use crate::rand;
|
||||
|
@ -25,7 +26,6 @@ use crate::tokio_util;
|
|||
use crate::tokio_write;
|
||||
use crate::version;
|
||||
use crate::worker::Worker;
|
||||
use deno::js_check;
|
||||
use deno::Buf;
|
||||
use deno::CoreOp;
|
||||
use deno::JSError;
|
||||
|
@ -401,11 +401,11 @@ fn op_format_error(
|
|||
let orig_error = String::from(inner.error().unwrap());
|
||||
|
||||
let js_error = JSError::from_v8_exception(&orig_error).unwrap();
|
||||
let js_error_mapped = apply_source_map(&js_error, &state.dir);
|
||||
let js_error_string = JSErrorColor(&js_error_mapped).to_string();
|
||||
let error_mapped = DenoError::from(js_error).apply_source_map(&state.dir);
|
||||
let error_string = error_mapped.to_string();
|
||||
|
||||
let mut builder = FlatBufferBuilder::new();
|
||||
let new_error = builder.create_string(&js_error_string);
|
||||
let new_error = builder.create_string(&error_string);
|
||||
|
||||
let inner = msg::FormatErrorRes::create(
|
||||
&mut builder,
|
||||
|
@ -496,7 +496,7 @@ fn op_fetch_module_meta_data(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if !base.sync() {
|
||||
return Err(errors::no_async_support());
|
||||
return Err(deno_error::no_async_support());
|
||||
}
|
||||
assert!(data.is_none());
|
||||
let inner = base.inner_as_fetch_module_meta_data().unwrap();
|
||||
|
@ -563,7 +563,7 @@ fn op_global_timer_stop(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if !base.sync() {
|
||||
return Err(errors::no_async_support());
|
||||
return Err(deno_error::no_async_support());
|
||||
}
|
||||
assert!(data.is_none());
|
||||
let state = state;
|
||||
|
@ -578,7 +578,7 @@ fn op_global_timer(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if base.sync() {
|
||||
return Err(errors::no_sync_support());
|
||||
return Err(deno_error::no_sync_support());
|
||||
}
|
||||
assert!(data.is_none());
|
||||
let cmd_id = base.cmd_id();
|
||||
|
@ -1002,7 +1002,7 @@ fn op_close(
|
|||
let inner = base.inner_as_close().unwrap();
|
||||
let rid = inner.rid();
|
||||
match resources::lookup(rid) {
|
||||
None => Err(errors::bad_resource()),
|
||||
None => Err(deno_error::bad_resource()),
|
||||
Some(resource) => {
|
||||
resource.close();
|
||||
ok_buf(empty_buf())
|
||||
|
@ -1033,7 +1033,7 @@ fn op_shutdown(
|
|||
let rid = inner.rid();
|
||||
let how = inner.how();
|
||||
match resources::lookup(rid) {
|
||||
None => Err(errors::bad_resource()),
|
||||
None => Err(deno_error::bad_resource()),
|
||||
Some(mut resource) => {
|
||||
let shutdown_mode = match how {
|
||||
0 => Shutdown::Read,
|
||||
|
@ -1059,7 +1059,7 @@ fn op_read(
|
|||
let rid = inner.rid();
|
||||
|
||||
match resources::lookup(rid) {
|
||||
None => Err(errors::bad_resource()),
|
||||
None => Err(deno_error::bad_resource()),
|
||||
Some(resource) => {
|
||||
let op = tokio::io::read(resource, data.unwrap())
|
||||
.map_err(DenoError::from)
|
||||
|
@ -1102,7 +1102,7 @@ fn op_write(
|
|||
let rid = inner.rid();
|
||||
|
||||
match resources::lookup(rid) {
|
||||
None => Err(errors::bad_resource()),
|
||||
None => Err(deno_error::bad_resource()),
|
||||
Some(resource) => {
|
||||
let op = tokio_write::write(resource, data.unwrap())
|
||||
.map_err(DenoError::from)
|
||||
|
@ -1146,7 +1146,7 @@ fn op_seek(
|
|||
let whence = inner.whence();
|
||||
|
||||
match resources::lookup(rid) {
|
||||
None => Err(errors::bad_resource()),
|
||||
None => Err(deno_error::bad_resource()),
|
||||
Some(resource) => {
|
||||
let op = resources::seek(resource, offset, whence)
|
||||
.and_then(move |_| Ok(empty_buf()));
|
||||
|
@ -1205,7 +1205,7 @@ fn op_copy_file(
|
|||
// See https://github.com/rust-lang/rust/issues/54800
|
||||
// Once the issue is reolved, we should remove this workaround.
|
||||
if cfg!(unix) && !from.is_file() {
|
||||
return Err(errors::new(
|
||||
return Err(deno_error::new(
|
||||
ErrorKind::NotFound,
|
||||
"File not found".to_string(),
|
||||
));
|
||||
|
@ -1417,7 +1417,10 @@ fn op_symlink(
|
|||
state.check_write(&newname_)?;
|
||||
// TODO Use type for Windows.
|
||||
if cfg!(windows) {
|
||||
return Err(errors::new(ErrorKind::Other, "Not implemented".to_string()));
|
||||
return Err(deno_error::new(
|
||||
ErrorKind::Other,
|
||||
"Not implemented".to_string(),
|
||||
));
|
||||
}
|
||||
blocking(base.sync(), move || {
|
||||
debug!("op_symlink {} {}", oldname.display(), newname.display());
|
||||
|
@ -1638,7 +1641,7 @@ fn op_accept(
|
|||
let server_rid = inner.rid();
|
||||
|
||||
match resources::lookup(server_rid) {
|
||||
None => Err(errors::bad_resource()),
|
||||
None => Err(deno_error::bad_resource()),
|
||||
Some(server_resource) => {
|
||||
let op = tokio_util::accept(server_resource)
|
||||
.map_err(DenoError::from)
|
||||
|
@ -1767,7 +1770,7 @@ fn op_run(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if !base.sync() {
|
||||
return Err(errors::no_async_support());
|
||||
return Err(deno_error::no_async_support());
|
||||
}
|
||||
let cmd_id = base.cmd_id();
|
||||
|
||||
|
@ -1906,7 +1909,7 @@ fn op_worker_get_message(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if base.sync() {
|
||||
return Err(errors::no_sync_support());
|
||||
return Err(deno_error::no_sync_support());
|
||||
}
|
||||
assert!(data.is_none());
|
||||
let cmd_id = base.cmd_id();
|
||||
|
@ -1952,7 +1955,7 @@ fn op_worker_post_message(
|
|||
};
|
||||
tx.send(d)
|
||||
.wait()
|
||||
.map_err(|e| errors::new(ErrorKind::Other, e.to_string()))?;
|
||||
.map_err(|e| deno_error::new(ErrorKind::Other, e.to_string()))?;
|
||||
let builder = &mut FlatBufferBuilder::new();
|
||||
|
||||
ok_buf(serialize_response(
|
||||
|
@ -1988,34 +1991,32 @@ fn op_create_worker(
|
|||
|
||||
let mut worker =
|
||||
Worker::new(name, startup_data::deno_isolate_init(), child_state);
|
||||
js_check(worker.execute("denoMain()"));
|
||||
js_check(worker.execute("workerMain()"));
|
||||
err_check(worker.execute("denoMain()"));
|
||||
err_check(worker.execute("workerMain()"));
|
||||
|
||||
let module_specifier = ModuleSpecifier::resolve_root(specifier)?;
|
||||
|
||||
let op = worker
|
||||
.execute_mod_async(&module_specifier, false)
|
||||
.and_then(move |()| {
|
||||
let mut workers_tl = parent_state.workers.lock().unwrap();
|
||||
workers_tl.insert(rid, worker.shared());
|
||||
let builder = &mut FlatBufferBuilder::new();
|
||||
let msg_inner = msg::CreateWorkerRes::create(
|
||||
builder,
|
||||
&msg::CreateWorkerResArgs { rid },
|
||||
);
|
||||
Ok(serialize_response(
|
||||
cmd_id,
|
||||
builder,
|
||||
msg::BaseArgs {
|
||||
inner: Some(msg_inner.as_union_value()),
|
||||
inner_type: msg::Any::CreateWorkerRes,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
}).map_err(|err| match err {
|
||||
errors::RustOrJsError::Js(_) => errors::worker_init_failed(),
|
||||
errors::RustOrJsError::Rust(err) => err,
|
||||
});
|
||||
let op =
|
||||
worker
|
||||
.execute_mod_async(&module_specifier, false)
|
||||
.and_then(move |()| {
|
||||
let mut workers_tl = parent_state.workers.lock().unwrap();
|
||||
workers_tl.insert(rid, worker.shared());
|
||||
let builder = &mut FlatBufferBuilder::new();
|
||||
let msg_inner = msg::CreateWorkerRes::create(
|
||||
builder,
|
||||
&msg::CreateWorkerResArgs { rid },
|
||||
);
|
||||
Ok(serialize_response(
|
||||
cmd_id,
|
||||
builder,
|
||||
msg::BaseArgs {
|
||||
inner: Some(msg_inner.as_union_value()),
|
||||
inner_type: msg::Any::CreateWorkerRes,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
});
|
||||
|
||||
let result = op.wait()?;
|
||||
Ok(Op::Sync(result))
|
||||
|
@ -2028,7 +2029,7 @@ fn op_host_get_worker_closed(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if base.sync() {
|
||||
return Err(errors::no_sync_support());
|
||||
return Err(deno_error::no_sync_support());
|
||||
}
|
||||
assert!(data.is_none());
|
||||
let cmd_id = base.cmd_id();
|
||||
|
@ -2063,7 +2064,7 @@ fn op_host_get_message(
|
|||
data: Option<PinnedBuf>,
|
||||
) -> CliOpResult {
|
||||
if base.sync() {
|
||||
return Err(errors::no_sync_support());
|
||||
return Err(deno_error::no_sync_support());
|
||||
}
|
||||
assert!(data.is_none());
|
||||
let cmd_id = base.cmd_id();
|
||||
|
@ -2107,7 +2108,7 @@ fn op_host_post_message(
|
|||
|
||||
resources::post_message_to_worker(rid, d)
|
||||
.wait()
|
||||
.map_err(|e| errors::new(ErrorKind::Other, e.to_string()))?;
|
||||
.map_err(|e| deno_error::new(ErrorKind::Other, e.to_string()))?;
|
||||
let builder = &mut FlatBufferBuilder::new();
|
||||
|
||||
ok_buf(serialize_response(
|
||||
|
|
|
@ -4,8 +4,8 @@ use atty;
|
|||
use crate::flags::DenoFlags;
|
||||
|
||||
use ansi_term::Style;
|
||||
use crate::errors::permission_denied;
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error::permission_denied;
|
||||
use crate::deno_error::DenoResult;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
|
|
@ -5,8 +5,8 @@ use crate::msg::ErrorKind;
|
|||
use std::error::Error;
|
||||
|
||||
use crate::deno_dir::DenoDir;
|
||||
use crate::errors::new as deno_error;
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error::new as deno_error;
|
||||
use crate::deno_error::DenoResult;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
// descriptors". This module implements a global resource table. Ops (AKA
|
||||
// handlers) look up resources by their integer id here.
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::bad_resource;
|
||||
use crate::errors::DenoError;
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error;
|
||||
use crate::deno_error::bad_resource;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::deno_error::DenoResult;
|
||||
use crate::http_body::HttpBody;
|
||||
use crate::repl::Repl;
|
||||
use crate::state::WorkerChannels;
|
||||
|
@ -372,10 +372,9 @@ impl Future for WorkerReceiver {
|
|||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||
let maybe_repr = table.get_mut(&self.rid);
|
||||
match maybe_repr {
|
||||
Some(Repr::Worker(ref mut wc)) => wc
|
||||
.1
|
||||
.poll()
|
||||
.map_err(|err| errors::new(errors::ErrorKind::Other, err.to_string())),
|
||||
Some(Repr::Worker(ref mut wc)) => wc.1.poll().map_err(|err| {
|
||||
deno_error::new(deno_error::ErrorKind::Other, err.to_string())
|
||||
}),
|
||||
_ => Err(bad_resource()),
|
||||
}
|
||||
}
|
||||
|
@ -398,10 +397,9 @@ impl Stream for WorkerReceiverStream {
|
|||
let mut table = RESOURCE_TABLE.lock().unwrap();
|
||||
let maybe_repr = table.get_mut(&self.rid);
|
||||
match maybe_repr {
|
||||
Some(Repr::Worker(ref mut wc)) => wc
|
||||
.1
|
||||
.poll()
|
||||
.map_err(|err| errors::new(errors::ErrorKind::Other, err.to_string())),
|
||||
Some(Repr::Worker(ref mut wc)) => wc.1.poll().map_err(|err| {
|
||||
deno_error::new(deno_error::ErrorKind::Other, err.to_string())
|
||||
}),
|
||||
_ => Err(bad_resource()),
|
||||
}
|
||||
}
|
||||
|
@ -535,8 +533,8 @@ pub fn seek(
|
|||
1 => SeekFrom::Current(i64::from(offset)),
|
||||
2 => SeekFrom::End(i64::from(offset)),
|
||||
_ => {
|
||||
return Box::new(futures::future::err(errors::new(
|
||||
errors::ErrorKind::InvalidSeekMode,
|
||||
return Box::new(futures::future::err(deno_error::new(
|
||||
deno_error::ErrorKind::InvalidSeekMode,
|
||||
format!("Invalid seek mode: {}", whence),
|
||||
)));
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@ use nix::sys::signal::{kill as unix_kill, Signal};
|
|||
#[cfg(unix)]
|
||||
use nix::unistd::Pid;
|
||||
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error::DenoResult;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn kill(pid: i32, signo: i32) -> DenoResult<()> {
|
||||
use crate::errors::DenoError;
|
||||
use crate::deno_error::DenoError;
|
||||
let sig = Signal::from_c_int(signo)?;
|
||||
unix_kill(Pid::from_raw(pid), Option::Some(sig)).map_err(DenoError::from)
|
||||
}
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
//! This mod adds source maps and ANSI color display to deno::JSError.
|
||||
use crate::ansi;
|
||||
//! This mod provides functions to remap a deno::JSError based on a source map
|
||||
use deno::JSError;
|
||||
use deno::StackFrame;
|
||||
use serde_json;
|
||||
use source_map_mappings::parse_mappings;
|
||||
use source_map_mappings::Bias;
|
||||
use source_map_mappings::Mappings;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
/// Wrapper around JSError which provides color to_string.
|
||||
pub struct JSErrorColor<'a>(pub &'a JSError);
|
||||
|
||||
struct StackFrameColor<'a>(&'a StackFrame);
|
||||
|
||||
pub trait SourceMapGetter {
|
||||
/// Returns the raw source map file.
|
||||
fn get_source_map(&self, script_name: &str) -> Option<Vec<u8>>;
|
||||
fn get_source_line(&self, script_name: &str, line: usize) -> Option<String>;
|
||||
}
|
||||
|
||||
/// Cached filename lookups. The key can be None if a previous lookup failed to
|
||||
|
@ -29,80 +24,9 @@ struct SourceMap {
|
|||
sources: Vec<String>,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for StackFrameColor<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let frame = self.0;
|
||||
// Note when we print to string, we change from 0-indexed to 1-indexed.
|
||||
let function_name = ansi::italic_bold(frame.function_name.clone());
|
||||
let script_line_column =
|
||||
format_script_line_column(&frame.script_name, frame.line, frame.column);
|
||||
|
||||
if !frame.function_name.is_empty() {
|
||||
write!(f, " at {} ({})", function_name, script_line_column)
|
||||
} else if frame.is_eval {
|
||||
write!(f, " at eval ({})", script_line_column)
|
||||
} else {
|
||||
write!(f, " at {}", script_line_column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_script_line_column(
|
||||
script_name: &str,
|
||||
line: i64,
|
||||
column: i64,
|
||||
) -> String {
|
||||
// TODO match this style with how typescript displays errors.
|
||||
let line = ansi::yellow((1 + line).to_string());
|
||||
let column = ansi::yellow((1 + column).to_string());
|
||||
let script_name = ansi::cyan(script_name.to_string());
|
||||
format!("{}:{}:{}", script_name, line, column)
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for JSErrorColor<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let e = self.0;
|
||||
if e.script_resource_name.is_some() {
|
||||
let script_resource_name = e.script_resource_name.as_ref().unwrap();
|
||||
// Avoid showing internal code from gen/cli/bundle/main.js
|
||||
if script_resource_name != "gen/cli/bundle/main.js"
|
||||
&& script_resource_name != "gen/cli/bundle/compiler.js"
|
||||
{
|
||||
if e.line_number.is_some() && e.start_column.is_some() {
|
||||
assert!(e.line_number.is_some());
|
||||
assert!(e.start_column.is_some());
|
||||
let script_line_column = format_script_line_column(
|
||||
script_resource_name,
|
||||
e.line_number.unwrap() - 1,
|
||||
e.start_column.unwrap() - 1,
|
||||
);
|
||||
write!(f, "{}", script_line_column)?;
|
||||
}
|
||||
if e.source_line.is_some() {
|
||||
write!(f, "\n{}\n", e.source_line.as_ref().unwrap())?;
|
||||
let mut s = String::new();
|
||||
for i in 0..e.end_column.unwrap() {
|
||||
if i >= e.start_column.unwrap() {
|
||||
s.push('^');
|
||||
} else {
|
||||
s.push(' ');
|
||||
}
|
||||
}
|
||||
writeln!(f, "{}", ansi::red_bold(s))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "{}", ansi::bold(e.message.clone()))?;
|
||||
|
||||
for frame in &e.frames {
|
||||
write!(f, "\n{}", StackFrameColor(&frame).to_string())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SourceMap {
|
||||
/// Take a JSON string and attempt to decode it, returning an optional
|
||||
/// instance of `SourceMap`.
|
||||
fn from_json(json_str: &str) -> Option<Self> {
|
||||
// Ugly. Maybe use serde_derive.
|
||||
match serde_json::from_str::<serde_json::Value>(json_str) {
|
||||
|
@ -137,77 +61,11 @@ impl SourceMap {
|
|||
}
|
||||
}
|
||||
|
||||
fn frame_apply_source_map<G: SourceMapGetter>(
|
||||
frame: &StackFrame,
|
||||
mappings_map: &mut CachedMaps,
|
||||
getter: &G,
|
||||
) -> StackFrame {
|
||||
let maybe_sm = get_mappings(frame.script_name.as_ref(), mappings_map, getter);
|
||||
let frame_pos = (
|
||||
frame.script_name.to_owned(),
|
||||
frame.line as i64,
|
||||
frame.column as i64,
|
||||
);
|
||||
let (script_name, line, column) = match maybe_sm {
|
||||
None => frame_pos,
|
||||
Some(sm) => match sm.mappings.original_location_for(
|
||||
frame.line as u32,
|
||||
frame.column as u32,
|
||||
Bias::default(),
|
||||
) {
|
||||
None => frame_pos,
|
||||
Some(mapping) => match &mapping.original {
|
||||
None => frame_pos,
|
||||
Some(original) => {
|
||||
let orig_source = sm.sources[original.source as usize].clone();
|
||||
(
|
||||
orig_source,
|
||||
i64::from(original.original_line),
|
||||
i64::from(original.original_column),
|
||||
)
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
StackFrame {
|
||||
script_name,
|
||||
function_name: frame.function_name.clone(),
|
||||
line,
|
||||
column,
|
||||
is_eval: frame.is_eval,
|
||||
is_constructor: frame.is_constructor,
|
||||
is_wasm: frame.is_wasm,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_source_map<G: SourceMapGetter>(
|
||||
js_error: &JSError,
|
||||
getter: &G,
|
||||
) -> JSError {
|
||||
let mut mappings_map: CachedMaps = HashMap::new();
|
||||
let mut frames = Vec::<StackFrame>::new();
|
||||
for frame in &js_error.frames {
|
||||
let f = frame_apply_source_map(&frame, &mut mappings_map, getter);
|
||||
frames.push(f);
|
||||
}
|
||||
JSError {
|
||||
message: js_error.message.clone(),
|
||||
frames,
|
||||
error_level: js_error.error_level,
|
||||
source_line: js_error.source_line.clone(),
|
||||
// TODO the following need to be source mapped:
|
||||
script_resource_name: js_error.script_resource_name.clone(),
|
||||
line_number: js_error.line_number,
|
||||
start_position: js_error.start_position,
|
||||
end_position: js_error.end_position,
|
||||
start_column: js_error.start_column,
|
||||
end_column: js_error.end_column,
|
||||
}
|
||||
}
|
||||
|
||||
// The bundle does not get built for 'cargo check', so we don't embed the
|
||||
// bundle source map.
|
||||
// bundle source map. The built in source map is the source map for the main
|
||||
// JavaScript bundle which is then used to create the snapshot. Runtime stack
|
||||
// traces can contain positions within the bundle which we will map to the
|
||||
// original Deno TypeScript code.
|
||||
#[cfg(feature = "check-only")]
|
||||
fn builtin_source_map(_: &str) -> Option<Vec<u8>> {
|
||||
None
|
||||
|
@ -232,15 +90,149 @@ fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_map_string<G: SourceMapGetter>(
|
||||
script_name: &str,
|
||||
/// Apply a source map to a JSError, returning a JSError where the filenames,
|
||||
/// the lines and the columns point to their original source location, not their
|
||||
/// transpiled location if applicable.
|
||||
pub fn apply_source_map<G: SourceMapGetter>(
|
||||
js_error: &JSError,
|
||||
getter: &G,
|
||||
) -> Option<SourceMap> {
|
||||
builtin_source_map(script_name)
|
||||
.or_else(|| getter.get_source_map(script_name))
|
||||
.and_then(|raw_source_map| {
|
||||
SourceMap::from_json(str::from_utf8(&raw_source_map).unwrap())
|
||||
})
|
||||
) -> JSError {
|
||||
let mut mappings_map: CachedMaps = HashMap::new();
|
||||
|
||||
let mut frames = Vec::<StackFrame>::new();
|
||||
for frame in &js_error.frames {
|
||||
let f = frame_apply_source_map(&frame, &mut mappings_map, getter);
|
||||
frames.push(f);
|
||||
}
|
||||
|
||||
let (script_resource_name, line_number, start_column) =
|
||||
get_maybe_orig_position(
|
||||
js_error.script_resource_name.clone(),
|
||||
js_error.line_number,
|
||||
js_error.start_column,
|
||||
&mut mappings_map,
|
||||
getter,
|
||||
);
|
||||
// It is better to just move end_column to be the same distance away from
|
||||
// start column because sometimes the code point is not available in the
|
||||
// source file map.
|
||||
let end_column = match js_error.end_column {
|
||||
Some(ec) => {
|
||||
if start_column.is_some() {
|
||||
Some(ec - (js_error.start_column.unwrap() - start_column.unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
// if there is a source line that we might be different in the source file, we
|
||||
// will go fetch it from the getter
|
||||
let source_line = if js_error.source_line.is_some()
|
||||
&& script_resource_name.is_some()
|
||||
&& line_number.is_some()
|
||||
{
|
||||
getter.get_source_line(
|
||||
&js_error.script_resource_name.clone().unwrap(),
|
||||
line_number.unwrap() as usize,
|
||||
)
|
||||
} else {
|
||||
js_error.source_line.clone()
|
||||
};
|
||||
|
||||
JSError {
|
||||
message: js_error.message.clone(),
|
||||
frames,
|
||||
error_level: js_error.error_level,
|
||||
source_line,
|
||||
script_resource_name,
|
||||
line_number,
|
||||
start_column,
|
||||
end_column,
|
||||
// These are difficult to map to their original position and they are not
|
||||
// currently used in any output, so we don't remap them.
|
||||
start_position: js_error.start_position,
|
||||
end_position: js_error.end_position,
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_apply_source_map<G: SourceMapGetter>(
|
||||
frame: &StackFrame,
|
||||
mappings_map: &mut CachedMaps,
|
||||
getter: &G,
|
||||
) -> StackFrame {
|
||||
let (script_name, line, column) = get_orig_position(
|
||||
frame.script_name.to_string(),
|
||||
frame.line,
|
||||
frame.column,
|
||||
mappings_map,
|
||||
getter,
|
||||
);
|
||||
|
||||
StackFrame {
|
||||
script_name,
|
||||
function_name: frame.function_name.clone(),
|
||||
line,
|
||||
column,
|
||||
is_eval: frame.is_eval,
|
||||
is_constructor: frame.is_constructor,
|
||||
is_wasm: frame.is_wasm,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_maybe_orig_position<G: SourceMapGetter>(
|
||||
script_name: Option<String>,
|
||||
line: Option<i64>,
|
||||
column: Option<i64>,
|
||||
mappings_map: &mut CachedMaps,
|
||||
getter: &G,
|
||||
) -> (Option<String>, Option<i64>, Option<i64>) {
|
||||
match (script_name, line, column) {
|
||||
(Some(script_name_v), Some(line_v), Some(column_v)) => {
|
||||
let (script_name, line, column) = get_orig_position(
|
||||
script_name_v,
|
||||
line_v - 1,
|
||||
column_v,
|
||||
mappings_map,
|
||||
getter,
|
||||
);
|
||||
(Some(script_name), Some(line), Some(column))
|
||||
}
|
||||
_ => (None, None, None),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_orig_position<G: SourceMapGetter>(
|
||||
script_name: String,
|
||||
line: i64,
|
||||
column: i64,
|
||||
mappings_map: &mut CachedMaps,
|
||||
getter: &G,
|
||||
) -> (String, i64, i64) {
|
||||
let maybe_sm = get_mappings(&script_name, mappings_map, getter);
|
||||
let default_pos = (script_name, line, column);
|
||||
|
||||
match maybe_sm {
|
||||
None => default_pos,
|
||||
Some(sm) => match sm.mappings.original_location_for(
|
||||
line as u32,
|
||||
column as u32,
|
||||
Bias::default(),
|
||||
) {
|
||||
None => default_pos,
|
||||
Some(mapping) => match &mapping.original {
|
||||
None => default_pos,
|
||||
Some(original) => {
|
||||
let orig_source = sm.sources[original.source as usize].clone();
|
||||
(
|
||||
orig_source,
|
||||
i64::from(original.original_line),
|
||||
i64::from(original.original_column),
|
||||
)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mappings<'a, G: SourceMapGetter>(
|
||||
|
@ -253,10 +245,57 @@ fn get_mappings<'a, G: SourceMapGetter>(
|
|||
.or_insert_with(|| parse_map_string(script_name, getter))
|
||||
}
|
||||
|
||||
// TODO(kitsonk) parsed source maps should probably be cached in state in
|
||||
// the module meta data.
|
||||
fn parse_map_string<G: SourceMapGetter>(
|
||||
script_name: &str,
|
||||
getter: &G,
|
||||
) -> Option<SourceMap> {
|
||||
builtin_source_map(script_name)
|
||||
.or_else(|| getter.get_source_map(script_name))
|
||||
.and_then(|raw_source_map| {
|
||||
SourceMap::from_json(str::from_utf8(&raw_source_map).unwrap())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ansi::strip_ansi_codes;
|
||||
|
||||
struct MockSourceMapGetter {}
|
||||
|
||||
impl SourceMapGetter for MockSourceMapGetter {
|
||||
fn get_source_map(&self, script_name: &str) -> Option<Vec<u8>> {
|
||||
let s = match script_name {
|
||||
"foo_bar.ts" => r#"{"sources": ["foo_bar.ts"], "mappings":";;;IAIA,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE3C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}"#,
|
||||
"bar_baz.ts" => r#"{"sources": ["bar_baz.ts"], "mappings":";;;IAEA,CAAC,KAAK,IAAI,EAAE;QACV,MAAM,GAAG,GAAG,sDAAa,OAAO,2BAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC,EAAE,CAAC;IAEQ,QAAA,GAAG,GAAG,KAAK,CAAC;IAEzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}"#,
|
||||
_ => return None,
|
||||
};
|
||||
Some(s.as_bytes().to_owned())
|
||||
}
|
||||
|
||||
fn get_source_line(
|
||||
&self,
|
||||
script_name: &str,
|
||||
line: usize,
|
||||
) -> Option<String> {
|
||||
let s = match script_name {
|
||||
"foo_bar.ts" => vec![
|
||||
"console.log('foo');",
|
||||
"console.log('foo');",
|
||||
"console.log('foo');",
|
||||
"console.log('foo');",
|
||||
"console.log('foo');",
|
||||
],
|
||||
_ => return None,
|
||||
};
|
||||
if s.len() > line {
|
||||
Some(s[line].to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn error1() -> JSError {
|
||||
JSError {
|
||||
|
@ -301,25 +340,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
struct MockSourceMapGetter {}
|
||||
|
||||
impl SourceMapGetter for MockSourceMapGetter {
|
||||
fn get_source_map(&self, script_name: &str) -> Option<Vec<u8>> {
|
||||
let s = match script_name {
|
||||
"foo_bar.ts" => r#"{"sources": ["foo_bar.ts"], "mappings":";;;IAIA,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE3C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}"#,
|
||||
"bar_baz.ts" => r#"{"sources": ["bar_baz.ts"], "mappings":";;;IAEA,CAAC,KAAK,IAAI,EAAE;QACV,MAAM,GAAG,GAAG,sDAAa,OAAO,2BAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC,EAAE,CAAC;IAEQ,QAAA,GAAG,GAAG,KAAK,CAAC;IAEzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}"#,
|
||||
_ => return None,
|
||||
};
|
||||
Some(s.as_bytes().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn js_error_to_string() {
|
||||
let e = error1();
|
||||
assert_eq!("Error: foo bar\n at foo (foo_bar.ts:5:17)\n at qat (bar_baz.ts:6:21)\n at deno_main.js:2:2", strip_ansi_codes(&e.to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn js_error_apply_source_map_1() {
|
||||
let e = error1();
|
||||
|
@ -398,6 +418,25 @@ mod tests {
|
|||
assert!(actual.frames[0].script_name.ends_with("js/util.ts"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn js_error_apply_source_map_line() {
|
||||
let e = JSError {
|
||||
message: "TypeError: baz".to_string(),
|
||||
source_line: Some("foo".to_string()),
|
||||
script_resource_name: Some("foo_bar.ts".to_string()),
|
||||
line_number: Some(4),
|
||||
start_position: None,
|
||||
end_position: None,
|
||||
error_level: None,
|
||||
start_column: Some(16),
|
||||
end_column: None,
|
||||
frames: vec![],
|
||||
};
|
||||
let getter = MockSourceMapGetter {};
|
||||
let actual = apply_source_map(&e, &getter);
|
||||
assert_eq!(actual.source_line, Some("console.log('foo');".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_map_from_json() {
|
||||
let json = r#"{"version":3,"file":"error_001.js","sourceRoot":"","sources":["file:///Users/rld/src/deno/tests/error_001.ts"],"names":[],"mappings":"AAAA,SAAS,GAAG;IACV,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;AACrB,CAAC;AAED,SAAS,GAAG;IACV,GAAG,EAAE,CAAC;AACR,CAAC;AAED,GAAG,EAAE,CAAC"}"#;
|
|
@ -2,8 +2,8 @@
|
|||
use crate::compiler::compile_async;
|
||||
use crate::compiler::ModuleMetaData;
|
||||
use crate::deno_dir;
|
||||
use crate::errors::DenoError;
|
||||
use crate::errors::DenoResult;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::deno_error::DenoResult;
|
||||
use crate::flags;
|
||||
use crate::global_timer::GlobalTimer;
|
||||
use crate::import_map::ImportMap;
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::errors::DenoError;
|
||||
use crate::errors::RustOrJsError;
|
||||
use crate::js_errors;
|
||||
use crate::deno_error::DenoError;
|
||||
use crate::state::ThreadSafeState;
|
||||
use crate::tokio_util;
|
||||
use deno;
|
||||
use deno::JSError;
|
||||
use deno::ModuleSpecifier;
|
||||
use deno::StartupData;
|
||||
use futures::Async;
|
||||
|
@ -39,7 +36,7 @@ impl Worker {
|
|||
}
|
||||
|
||||
/// Same as execute2() but the filename defaults to "<anonymous>".
|
||||
pub fn execute(&mut self, js_source: &str) -> Result<(), JSError> {
|
||||
pub fn execute(&mut self, js_source: &str) -> Result<(), DenoError> {
|
||||
self.execute2("<anonymous>", js_source)
|
||||
}
|
||||
|
||||
|
@ -49,9 +46,12 @@ impl Worker {
|
|||
&mut self,
|
||||
js_filename: &str,
|
||||
js_source: &str,
|
||||
) -> Result<(), JSError> {
|
||||
) -> Result<(), DenoError> {
|
||||
let mut isolate = self.isolate.lock().unwrap();
|
||||
isolate.execute(js_filename, js_source)
|
||||
match isolate.execute(js_filename, js_source) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(DenoError::from(err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes the provided JavaScript module.
|
||||
|
@ -59,7 +59,7 @@ impl Worker {
|
|||
&mut self,
|
||||
module_specifier: &ModuleSpecifier,
|
||||
is_prefetch: bool,
|
||||
) -> impl Future<Item = (), Error = RustOrJsError> {
|
||||
) -> impl Future<Item = (), Error = DenoError> {
|
||||
let worker = self.clone();
|
||||
let worker_ = worker.clone();
|
||||
let loader = self.state.clone();
|
||||
|
@ -87,12 +87,12 @@ impl Worker {
|
|||
}
|
||||
}).map_err(move |err| {
|
||||
worker_.state.progress.done();
|
||||
// Convert to RustOrJsError AND apply_source_map.
|
||||
// Convert to DenoError AND apply_source_map.
|
||||
match err {
|
||||
deno::JSErrorOr::JSError(err) => {
|
||||
RustOrJsError::Js(worker_.apply_source_map(err))
|
||||
worker_.apply_source_map(DenoError::from(err))
|
||||
}
|
||||
deno::JSErrorOr::Other(err) => RustOrJsError::Rust(err),
|
||||
deno::JSErrorOr::Other(err) => err,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -102,29 +102,32 @@ impl Worker {
|
|||
&mut self,
|
||||
module_specifier: &ModuleSpecifier,
|
||||
is_prefetch: bool,
|
||||
) -> Result<(), RustOrJsError> {
|
||||
) -> Result<(), DenoError> {
|
||||
tokio_util::block_on(self.execute_mod_async(module_specifier, is_prefetch))
|
||||
}
|
||||
|
||||
/// Applies source map to the error.
|
||||
fn apply_source_map(&self, err: JSError) -> JSError {
|
||||
js_errors::apply_source_map(&err, &self.state.dir)
|
||||
fn apply_source_map(&self, err: DenoError) -> DenoError {
|
||||
err.apply_source_map(&self.state.dir)
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for Worker {
|
||||
type Item = ();
|
||||
type Error = JSError;
|
||||
type Error = DenoError;
|
||||
|
||||
fn poll(&mut self) -> Result<Async<()>, Self::Error> {
|
||||
let mut isolate = self.isolate.lock().unwrap();
|
||||
isolate.poll().map_err(|err| self.apply_source_map(err))
|
||||
isolate
|
||||
.poll()
|
||||
.map_err(|err| self.apply_source_map(DenoError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::deno_error::err_check;
|
||||
use crate::flags;
|
||||
use crate::ops::op_selector_std;
|
||||
use crate::progress::Progress;
|
||||
|
@ -132,7 +135,6 @@ mod tests {
|
|||
use crate::startup_data;
|
||||
use crate::state::ThreadSafeState;
|
||||
use crate::tokio_util;
|
||||
use deno::js_check;
|
||||
use futures::future::lazy;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
@ -208,7 +210,7 @@ mod tests {
|
|||
startup_data::deno_isolate_init(),
|
||||
state,
|
||||
);
|
||||
js_check(worker.execute("denoMain()"));
|
||||
err_check(worker.execute("denoMain()"));
|
||||
let result = worker.execute_mod(&module_specifier, false);
|
||||
if let Err(err) = result {
|
||||
eprintln!("execute_mod err {:?}", err);
|
||||
|
@ -229,8 +231,8 @@ mod tests {
|
|||
]);
|
||||
let mut worker =
|
||||
Worker::new("TEST".to_string(), startup_data::deno_isolate_init(), state);
|
||||
js_check(worker.execute("denoMain()"));
|
||||
js_check(worker.execute("workerMain()"));
|
||||
err_check(worker.execute("denoMain()"));
|
||||
err_check(worker.execute("workerMain()"));
|
||||
worker
|
||||
}
|
||||
|
||||
|
@ -251,7 +253,7 @@ mod tests {
|
|||
console.log("after postMessage");
|
||||
}
|
||||
"#;
|
||||
js_check(worker.execute(source));
|
||||
err_check(worker.execute(source));
|
||||
|
||||
let resource = worker.state.resource.clone();
|
||||
let resource_ = resource.clone();
|
||||
|
@ -259,7 +261,7 @@ mod tests {
|
|||
tokio::spawn(lazy(move || {
|
||||
worker.then(move |r| -> Result<(), ()> {
|
||||
resource_.close();
|
||||
js_check(r);
|
||||
err_check(r);
|
||||
Ok(())
|
||||
})
|
||||
}));
|
||||
|
@ -289,7 +291,7 @@ mod tests {
|
|||
fn removed_from_resource_table_on_close() {
|
||||
tokio_util::init(|| {
|
||||
let mut worker = create_test_worker();
|
||||
js_check(
|
||||
err_check(
|
||||
worker.execute("onmessage = () => { delete window.onmessage; }"),
|
||||
);
|
||||
|
||||
|
@ -300,7 +302,7 @@ mod tests {
|
|||
.then(move |r| -> Result<(), ()> {
|
||||
resource.close();
|
||||
println!("workers.rs after resource close");
|
||||
js_check(r);
|
||||
err_check(r);
|
||||
Ok(())
|
||||
}).shared();
|
||||
|
||||
|
@ -322,7 +324,7 @@ mod tests {
|
|||
#[test]
|
||||
fn execute_mod_resolve_error() {
|
||||
tokio_util::init(|| {
|
||||
// "foo" is not a vailid module specifier so this should return an error.
|
||||
// "foo" is not a valid module specifier so this should return an error.
|
||||
let mut worker = create_test_worker();
|
||||
let module_specifier =
|
||||
ModuleSpecifier::resolve_root("does-not-exist").unwrap();
|
||||
|
|
|
@ -142,8 +142,6 @@ impl<L: Loader> RecursiveLoad<L> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(ry) This is basically the same thing as RustOrJsError. They should be
|
||||
// combined into one type.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum JSErrorOr<E> {
|
||||
JSError(JSError),
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
[WILDCARD]hello
|
||||
before error
|
||||
world
|
||||
[WILDCARD]tests/async_error.ts:4:10
|
||||
throw Error("error");
|
||||
error: Uncaught Error: error
|
||||
[WILDCARD]tests/async_error.ts:4:9
|
||||
|
||||
4 throw Error("error");
|
||||
^
|
||||
Uncaught Error: error
|
||||
|
||||
at foo ([WILDCARD]tests/async_error.ts:4:9)
|
||||
at [WILDCARD]tests/async_error.ts:7:1
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[WILDCARD]Unsupported compiler options in "[WILDCARD]config.tsconfig.json"
|
||||
The following options were ignored:
|
||||
module, target
|
||||
[WILDCARD]tests/config.ts:3:5 - error TS2532: Object is possibly 'undefined'.
|
||||
[WILDCARD]error TS2532: Object is possibly 'undefined'.
|
||||
|
||||
[WILDCARD]tests/config.ts:3:5
|
||||
|
||||
3 if (map.get("bar").foo) {
|
||||
~~~~~~~~~~~~~~
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
[WILDCARD]Error: bad
|
||||
at foo (file://[WILDCARD]tests/error_001.ts:2:9)
|
||||
at bar (file://[WILDCARD]tests/error_001.ts:6:3)
|
||||
at file://[WILDCARD]tests/error_001.ts:9:1
|
||||
[WILDCARD]error: Uncaught Error: bad
|
||||
[WILDCARD]tests/error_001.ts:2:9
|
||||
|
||||
2 throw Error("bad");
|
||||
^
|
||||
|
||||
at foo ([WILDCARD]tests/error_001.ts:2:9)
|
||||
at bar ([WILDCARD]tests/error_001.ts:6:3)
|
||||
at [WILDCARD]tests/error_001.ts:9:1
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
[WILDCARD]Error: exception from mod1
|
||||
at throwsError (file://[WILDCARD]/tests/subdir/mod1.ts:16:9)
|
||||
at foo (file://[WILDCARD]/tests/error_002.ts:4:3)
|
||||
at file://[WILDCARD]/tests/error_002.ts:7:1
|
||||
[WILDCARD]error: Uncaught Error: exception from mod1
|
||||
[WILDCARD]tests/subdir/mod1.ts:16:9
|
||||
|
||||
16 throw Error("exception from mod1");
|
||||
^
|
||||
|
||||
at throwsError ([WILDCARD]tests/subdir/mod1.ts:16:9)
|
||||
at foo ([WILDCARD]tests/error_002.ts:4:3)
|
||||
at [WILDCARD]tests/error_002.ts:7:1
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
[WILDCARD]/tests/error_003_typescript.ts:20:3 - error TS2322: Type '(o: T) => { v: any; f: (x: B) => string; }[]' is not assignable to type '(r: B) => Value<B>[]'.
|
||||
[WILDCARD]error TS2322: Type '(o: T) => { v: any; f: (x: B) => string; }[]' is not assignable to type '(r: B) => Value<B>[]'.
|
||||
Types of parameters 'o' and 'r' are incompatible.
|
||||
Type 'B' is not assignable to type 'T'.
|
||||
'B' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.
|
||||
|
||||
[WILDCARD]tests/error_003_typescript.ts:20:3
|
||||
|
||||
20 values: o => [
|
||||
~~~~~~
|
||||
|
||||
[WILDCARD]/tests/error_003_typescript.ts:8:3
|
||||
The expected type comes from property 'values' which is declared here on type 'C<B>'
|
||||
|
||||
[WILDCARD]tests/error_003_typescript.ts:8:3
|
||||
|
||||
8 values?: (r: T) => Array<Value<T>>;
|
||||
~~~~~~
|
||||
The expected type comes from property 'values' which is declared here on type 'C<B>'
|
||||
|
||||
[WILDCARD]/tests/error_003_typescript.ts:22:12 - error TS2339: Property 't' does not exist on type 'T'.
|
||||
|
||||
error TS2339: Property 't' does not exist on type 'T'.
|
||||
|
||||
[WILDCARD]tests/error_003_typescript.ts:22:12
|
||||
|
||||
22 v: o.t,
|
||||
^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[WILDCARD]Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/tests/error_004_missing_module.ts"
|
||||
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]tests/error_004_missing_module.ts"
|
||||
[WILDCARD] js/errors.ts:[WILDCARD]
|
||||
at DenoError (js/errors.ts:[WILDCARD])
|
||||
at maybeError (js/errors.ts:[WILDCARD])
|
||||
at maybeThrowError (js/errors.ts:[WILDCARD])
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[WILDCARD]NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]/tests/error_005_missing_dynamic_import.ts"
|
||||
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/bad-module.ts" from "[WILDCARD]tests/error_005_missing_dynamic_import.ts"
|
||||
[WILDCARD] js/errors.ts:[WILDCARD]
|
||||
at DenoError (js/errors.ts:[WILDCARD])
|
||||
at maybeError (js/errors.ts:[WILDCARD])
|
||||
at maybeThrowError (js/errors.ts:[WILDCARD])
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[WILDCARD]Uncaught NotFound: Cannot resolve module "[WILDCARD]/non-existent" from "[WILDCARD]/tests/error_006_import_ext_failure.ts"
|
||||
[WILDCARD]error: Uncaught NotFound: Cannot resolve module "[WILDCARD]/non-existent" from "[WILDCARD]tests/error_006_import_ext_failure.ts"
|
||||
[WILDCARD] js/errors.ts:[WILDCARD]
|
||||
at DenoError (js/errors.ts:[WILDCARD])
|
||||
at maybeError (js/errors.ts:[WILDCARD])
|
||||
at maybeThrowError (js/errors.ts:[WILDCARD])
|
||||
|
|
|
@ -1 +1 @@
|
|||
[WILDCARD]Uncaught #<Object>
|
||||
[WILDCARD]error: Uncaught #<Object>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[WILDCARD]tests/error_008_checkjs.js:2:0
|
||||
consol.log("hello world!");
|
||||
^
|
||||
Uncaught ReferenceError: consol is not defined
|
||||
[WILDCARD]error: Uncaught ReferenceError: consol is not defined
|
||||
[WILDCARD]tests/error_008_checkjs.js:2:1
|
||||
|
||||
2 consol.log("hello world!");
|
||||
^
|
||||
|
||||
at [WILDCARD]tests/error_008_checkjs.js:2:1
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[WILDCARD]Uncaught RelativeUrlWithCannotBeABaseBase: relative URL with a cannot-be-a-base base
|
||||
[WILDCARD]error: Uncaught RelativeUrlWithCannotBeABaseBase: relative URL with a cannot-be-a-base base
|
||||
[WILDCARD] js/errors.ts:[WILDCARD]
|
||||
at DenoError (js/errors.ts:[WILDCARD])
|
||||
at maybeError (js/errors.ts:[WILDCARD])
|
||||
at maybeThrowError (js/errors.ts:[WILDCARD])
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[WILDCARD]Uncaught RelativeUrlWithCannotBeABaseBase: relative URL with a cannot-be-a-base base
|
||||
[WILDCARD]error: Uncaught RelativeUrlWithCannotBeABaseBase: relative URL with a cannot-be-a-base base
|
||||
[WILDCARD] js/errors.ts:[WILDCARD]
|
||||
at DenoError (js/errors.ts:[WILDCARD])
|
||||
at maybeError (js/errors.ts:[WILDCARD])
|
||||
at maybeThrowError (js/errors.ts:[WILDCARD])
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
[WILDCARD]tests/error_syntax.js:3:5
|
||||
(the following is a syntax error ^^ ! )
|
||||
^^^^^^^^^
|
||||
Uncaught SyntaxError: Unexpected identifier
|
||||
error: Uncaught SyntaxError: Unexpected identifier
|
||||
[WILDCARD]tests/error_syntax.js:3:6
|
||||
|
||||
3 (the following is a syntax error ^^ ! )
|
||||
~~~~~~~~~
|
||||
|
||||
|
|
Loading…
Reference in a new issue