1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00

refactor: update deno_core for error refactor (#26867)

Closes #26171

---------

Co-authored-by: David Sherret <dsherret@gmail.com>
This commit is contained in:
Leo Kettmeir 2025-01-08 14:52:32 -08:00 committed by GitHub
parent 814da49dff
commit ea30e188a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
214 changed files with 3787 additions and 4210 deletions

157
Cargo.lock generated
View file

@ -1275,7 +1275,7 @@ dependencies = [
"deno_npm",
"deno_npm_cache",
"deno_package_json",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_resolver",
"deno_runtime",
"deno_semver",
@ -1434,6 +1434,7 @@ version = "0.178.0"
dependencies = [
"async-trait",
"deno_core",
"deno_error",
"thiserror 2.0.3",
"tokio",
"uuid",
@ -1445,6 +1446,7 @@ version = "0.116.0"
dependencies = [
"async-trait",
"deno_core",
"deno_error",
"rusqlite",
"serde",
"sha2",
@ -1467,7 +1469,7 @@ dependencies = [
"data-url",
"deno_error",
"deno_media_type",
"deno_path_util 0.3.0",
"deno_path_util",
"http 1.1.0",
"indexmap 2.3.0",
"log",
@ -1486,6 +1488,7 @@ name = "deno_canvas"
version = "0.53.0"
dependencies = [
"deno_core",
"deno_error",
"deno_webgpu",
"image",
"serde",
@ -1494,13 +1497,14 @@ dependencies = [
[[package]]
name = "deno_config"
version = "0.42.0"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45aaf31e58ca915d5c0746bf8e2d07b94635154ad9e5afe5ff265cae6187b19"
checksum = "6c4c11bd51ef6738cabfc3c53f16c209a0b8615cb1e4e5bf3b14e3b5deebfe21"
dependencies = [
"anyhow",
"boxed_error",
"deno_error",
"deno_package_json",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_semver",
"glob",
"ignore",
@ -1513,7 +1517,7 @@ dependencies = [
"serde",
"serde_json",
"sys_traits",
"thiserror 1.0.64",
"thiserror 2.0.3",
"url",
]
@ -1526,9 +1530,9 @@ dependencies = [
[[package]]
name = "deno_core"
version = "0.327.0"
version = "0.330.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf8dff204b9c2415deb47b9f30d4d38b0925d0d88f1f9074e8e76f59e6d7ded"
checksum = "fd38bbbd68ed873165ccb630322704b44140d3a8c8d50f898beac4d1a8a3358c"
dependencies = [
"anyhow",
"az",
@ -1539,6 +1543,7 @@ dependencies = [
"capacity_builder 0.1.3",
"cooked-waker",
"deno_core_icudata",
"deno_error",
"deno_ops",
"deno_unsync",
"futures",
@ -1554,6 +1559,7 @@ dependencies = [
"smallvec",
"sourcemap 8.0.1",
"static_assertions",
"thiserror 2.0.3",
"tokio",
"url",
"v8",
@ -1574,6 +1580,7 @@ dependencies = [
"async-trait",
"chrono",
"deno_core",
"deno_error",
"saffron",
"thiserror 2.0.3",
"tokio",
@ -1592,6 +1599,7 @@ dependencies = [
"ctr",
"curve25519-dalek",
"deno_core",
"deno_error",
"deno_web",
"ed448-goldilocks",
"elliptic-curve",
@ -1618,16 +1626,17 @@ dependencies = [
[[package]]
name = "deno_doc"
version = "0.161.3"
version = "0.164.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "353a39c70d248af04600928cefc8066a9e4535fb6e7d7c518411e5efc822819f"
checksum = "ad1edb02603c7e8a4003c84af2482a05e5eda3a14f1af275434fda89223f054d"
dependencies = [
"anyhow",
"cfg-if",
"comrak",
"deno_ast",
"deno_graph",
"deno_path_util 0.2.2",
"deno_path_util",
"deno_terminal 0.2.0",
"handlebars",
"html-escape",
"import_map",
@ -1647,22 +1656,23 @@ dependencies = [
[[package]]
name = "deno_error"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "199c66ffd17ee1a948904d33f3d3f364573951c1f9fb3f859bfe7770bf33862a"
checksum = "c4da6a58de6932a96f84e133c072fd3b525966ee122a71f3efd48bbff2eed5ac"
dependencies = [
"deno_error_macro",
"libc",
"serde",
"serde_json",
"tokio",
"url",
]
[[package]]
name = "deno_error_macro"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd99df6ae75443907e1f959fc42ec6dcea67a7bd083e76cf23a117102c9a2ce"
checksum = "46351dff93aed2039407c91e2ded2a5591e42d2795ab3d111288625bb710d3d2"
dependencies = [
"proc-macro2",
"quote",
@ -1677,7 +1687,8 @@ dependencies = [
"bytes",
"data-url",
"deno_core",
"deno_path_util 0.3.0",
"deno_error",
"deno_path_util",
"deno_permissions",
"deno_tls",
"dyn-clone",
@ -1710,6 +1721,7 @@ name = "deno_ffi"
version = "0.171.0"
dependencies = [
"deno_core",
"deno_error",
"deno_permissions",
"dlopen2",
"dynasmrt",
@ -1733,8 +1745,9 @@ dependencies = [
"base32",
"boxed_error",
"deno_core",
"deno_error",
"deno_io",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_permissions",
"filetime",
"junction",
@ -1750,17 +1763,17 @@ dependencies = [
[[package]]
name = "deno_graph"
version = "0.86.9"
version = "0.87.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa96b7d353c0d36b108ec504272b148792f48dccaf29f302b39c46b43457bb94"
checksum = "f56d4eb4b7c81ae920b6d18c45a1866924f93110caee80bbbc362dc28143f2bb"
dependencies = [
"anyhow",
"async-trait",
"capacity_builder 0.5.0",
"data-url",
"deno_ast",
"deno_error",
"deno_media_type",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_semver",
"deno_unsync",
"encoding_rs",
@ -1794,6 +1807,7 @@ dependencies = [
"bytes",
"cache_control",
"deno_core",
"deno_error",
"deno_net",
"deno_websocket",
"flate2",
@ -1827,6 +1841,7 @@ version = "0.94.0"
dependencies = [
"async-trait",
"deno_core",
"deno_error",
"filetime",
"fs3",
"libc",
@ -1853,8 +1868,9 @@ dependencies = [
"bytes",
"chrono",
"deno_core",
"deno_error",
"deno_fetch",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_permissions",
"deno_tls",
"denokv_proto",
@ -1920,6 +1936,7 @@ name = "deno_napi"
version = "0.115.0"
dependencies = [
"deno_core",
"deno_error",
"deno_permissions",
"libc",
"libloading 0.7.4",
@ -1948,6 +1965,7 @@ name = "deno_net"
version = "0.176.0"
dependencies = [
"deno_core",
"deno_error",
"deno_permissions",
"deno_tls",
"hickory-proto",
@ -1977,13 +1995,14 @@ dependencies = [
"const-oid",
"data-encoding",
"deno_core",
"deno_error",
"deno_fetch",
"deno_fs",
"deno_io",
"deno_media_type",
"deno_net",
"deno_package_json",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_permissions",
"deno_whoami",
"der",
@ -2085,7 +2104,7 @@ dependencies = [
"deno_core",
"deno_error",
"deno_npm",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_semver",
"deno_unsync",
"faster-hex",
@ -2107,10 +2126,11 @@ dependencies = [
[[package]]
name = "deno_ops"
version = "0.203.0"
version = "0.206.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b146ca74cac431843486ade58e2accc16c11315fb2c6934590a52a73c56b7ec3"
checksum = "4c25ffa9d088ea00748dbef870bba110ac22ebf8cf7b2e9eb288409c5d852af3"
dependencies = [
"indexmap 2.3.0",
"proc-macro-rules",
"proc-macro2",
"quote",
@ -2118,7 +2138,7 @@ dependencies = [
"strum",
"strum_macros",
"syn 2.0.87",
"thiserror 1.0.64",
"thiserror 2.0.3",
]
[[package]]
@ -2129,7 +2149,7 @@ checksum = "e1d3c0f699ba2040669204ce24ab73720499fc290af843e4ce0fc8a9b3d67735"
dependencies = [
"boxed_error",
"deno_error",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_semver",
"indexmap 2.3.0",
"serde",
@ -2139,18 +2159,6 @@ dependencies = [
"url",
]
[[package]]
name = "deno_path_util"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b02c7d341e1b2cf089daff0f4fb2b4be8f3b5511b1d96040b3f7ed63a66c737b"
dependencies = [
"deno_error",
"percent-encoding",
"thiserror 2.0.3",
"url",
]
[[package]]
name = "deno_path_util"
version = "0.3.0"
@ -2170,7 +2178,8 @@ version = "0.43.0"
dependencies = [
"capacity_builder 0.5.0",
"deno_core",
"deno_path_util 0.3.0",
"deno_error",
"deno_path_util",
"deno_terminal 0.2.0",
"fqdn",
"libc",
@ -2192,9 +2201,10 @@ dependencies = [
"boxed_error",
"dashmap",
"deno_config",
"deno_error",
"deno_media_type",
"deno_package_json",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_semver",
"node_resolver",
"sys_traits",
@ -2216,6 +2226,7 @@ dependencies = [
"deno_core",
"deno_cron",
"deno_crypto",
"deno_error",
"deno_fetch",
"deno_ffi",
"deno_fs",
@ -2225,7 +2236,7 @@ dependencies = [
"deno_napi",
"deno_net",
"deno_node",
"deno_path_util 0.3.0",
"deno_path_util",
"deno_permissions",
"deno_telemetry",
"deno_terminal 0.2.0",
@ -2314,6 +2325,7 @@ version = "0.6.0"
dependencies = [
"async-trait",
"deno_core",
"deno_error",
"http-body-util",
"hyper 1.4.1",
"hyper-util",
@ -2326,6 +2338,7 @@ dependencies = [
"opentelemetry_sdk",
"pin-project",
"serde",
"thiserror 2.0.3",
"tokio",
]
@ -2354,6 +2367,7 @@ name = "deno_tls"
version = "0.171.0"
dependencies = [
"deno_core",
"deno_error",
"deno_native_certs",
"rustls",
"rustls-pemfile",
@ -2406,6 +2420,7 @@ dependencies = [
"deno_bench_util",
"deno_console",
"deno_core",
"deno_error",
"deno_webidl",
"thiserror 2.0.3",
"urlpattern",
@ -2421,6 +2436,7 @@ dependencies = [
"deno_bench_util",
"deno_console",
"deno_core",
"deno_error",
"deno_permissions",
"deno_url",
"deno_webidl",
@ -2438,6 +2454,7 @@ name = "deno_webgpu"
version = "0.151.0"
dependencies = [
"deno_core",
"deno_error",
"raw-window-handle",
"serde",
"thiserror 2.0.3",
@ -2460,6 +2477,7 @@ version = "0.189.0"
dependencies = [
"bytes",
"deno_core",
"deno_error",
"deno_net",
"deno_permissions",
"deno_tls",
@ -2481,6 +2499,7 @@ name = "deno_webstorage"
version = "0.179.0"
dependencies = [
"deno_core",
"deno_error",
"deno_web",
"rusqlite",
"thiserror 2.0.3",
@ -2498,13 +2517,13 @@ dependencies = [
[[package]]
name = "denokv_proto"
version = "0.8.4"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7ba1f99ed11a9c11e868a8521b1f71a7e1aba785d7f42ea9ecbdc01146c89ec"
checksum = "d5b77de4d3b9215e14624d4f4eb16cb38c0810e3f5860ba3b3fc47d0537f9a4d"
dependencies = [
"anyhow",
"async-trait",
"chrono",
"deno_error",
"futures",
"num-bigint",
"prost",
@ -2514,15 +2533,15 @@ dependencies = [
[[package]]
name = "denokv_remote"
version = "0.8.4"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ed833073189e8f6d03155fe3b05a024e75e29d8a28a4c2e9ec3b5c925e727b"
checksum = "c6497c28eec268ed99f1e8664f0842935f02d1508529c67d94c57ca5d893d743"
dependencies = [
"anyhow",
"async-stream",
"async-trait",
"bytes",
"chrono",
"deno_error",
"denokv_proto",
"futures",
"http 1.1.0",
@ -2531,6 +2550,7 @@ dependencies = [
"rand",
"serde",
"serde_json",
"thiserror 2.0.3",
"tokio",
"tokio-util",
"url",
@ -2539,14 +2559,14 @@ dependencies = [
[[package]]
name = "denokv_sqlite"
version = "0.8.4"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b790f01d1302d53a0c3cbd27de88a06b3abd64ec8ab8673924e490541c7c713"
checksum = "dc0f21a450a35eb85760761401fddf9bfff9840127be07a6ca5c31863127913d"
dependencies = [
"anyhow",
"async-stream",
"async-trait",
"chrono",
"deno_error",
"denokv_proto",
"futures",
"hex",
@ -2555,7 +2575,7 @@ dependencies = [
"rand",
"rusqlite",
"serde_json",
"thiserror 1.0.64",
"thiserror 2.0.3",
"tokio",
"tokio-stream",
"uuid",
@ -4331,16 +4351,18 @@ dependencies = [
[[package]]
name = "import_map"
version = "0.20.1"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "351a787decc56f38d65d16d32687265045d6d6a4531b4a0e1b649def3590354e"
checksum = "1215d4d92511fbbdaea50e750e91f2429598ef817f02b579158e92803b52c00a"
dependencies = [
"boxed_error",
"deno_error",
"indexmap 2.3.0",
"log",
"percent-encoding",
"serde",
"serde_json",
"thiserror 1.0.64",
"thiserror 2.0.3",
"url",
]
@ -5106,9 +5128,10 @@ dependencies = [
"anyhow",
"async-trait",
"boxed_error",
"deno_error",
"deno_media_type",
"deno_package_json",
"deno_path_util 0.3.0",
"deno_path_util",
"futures",
"lazy-regex",
"once_cell",
@ -6846,14 +6869,15 @@ dependencies = [
[[package]]
name = "serde_v8"
version = "0.236.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e23b3abce64010612f88f4ff689a959736f99eb3dc0dbf1c7903434b8bd8cda5"
checksum = "3caa6d882827148e5d9052d9d8d6d1c9d6ad426ed00cab46cafb8c07a0e7126a"
dependencies = [
"deno_error",
"num-bigint",
"serde",
"smallvec",
"thiserror 1.0.64",
"thiserror 2.0.3",
"v8",
]
@ -8506,9 +8530,9 @@ dependencies = [
[[package]]
name = "v8"
version = "130.0.2"
version = "130.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee0be58935708fa4d7efb970c6cf9f2d9511d24ee24246481a65b6ee167348d"
checksum = "a511192602f7b435b0a241c1947aa743eb7717f20a9195f4b5e8ed1952e01db1"
dependencies = [
"bindgen",
"bitflags 2.6.0",
@ -8706,11 +8730,12 @@ dependencies = [
[[package]]
name = "wasm_dep_analyzer"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f270206a91783fd90625c8bb0d8fbd459d0b1d1bf209b656f713f01ae7c04b8"
checksum = "2eeee3bdea6257cc36d756fa745a70f9d393571e47d69e0ed97581676a5369ca"
dependencies = [
"thiserror 1.0.64",
"deno_error",
"thiserror 2.0.3",
]
[[package]]

View file

@ -48,10 +48,10 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies]
deno_ast = { version = "=0.44.0", features = ["transpiling"] }
deno_core = { version = "0.327.0" }
deno_core = { version = "0.330.0" }
deno_bench_util = { version = "0.178.0", path = "./bench_util" }
deno_config = { version = "=0.42.0", features = ["workspace", "sync"] }
deno_config = { version = "=0.43.0", features = ["workspace", "sync"] }
deno_lockfile = "=0.24.0"
deno_media_type = { version = "0.2.3", features = ["module_specifier"] }
deno_npm = "=0.27.0"
@ -63,10 +63,10 @@ deno_terminal = "0.2.0"
napi_sym = { version = "0.114.0", path = "./ext/napi/sym" }
test_util = { package = "test_server", path = "./tests/util/server" }
denokv_proto = "0.8.4"
denokv_remote = "0.8.4"
denokv_proto = "0.9.0"
denokv_remote = "0.9.0"
# denokv_sqlite brings in bundled sqlite if we don't disable the default features
denokv_sqlite = { default-features = false, version = "0.8.4" }
denokv_sqlite = { default-features = false, version = "0.9.0" }
# exts
deno_broadcast_channel = { version = "0.178.0", path = "./ext/broadcast_channel" }
@ -119,7 +119,7 @@ dashmap = "5.5.3"
data-encoding = "2.3.3"
data-url = "=0.3.1"
deno_cache_dir = "=0.16.0"
deno_error = "=0.5.2"
deno_error = "=0.5.3"
deno_package_json = { version = "0.4.0", default-features = false }
deno_unsync = "0.4.2"
dlopen2 = "0.6.1"

View file

@ -62,6 +62,7 @@ serde_json.workspace = true
zstd.workspace = true
glibc_version = "0.1.2"
flate2 = { workspace = true, features = ["default"] }
deno_error.workspace = true
[target.'cfg(windows)'.build-dependencies]
winapi.workspace = true
@ -72,9 +73,9 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposa
deno_cache_dir.workspace = true
deno_config.workspace = true
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
deno_doc = { version = "=0.161.3", features = ["rust", "comrak"] }
deno_doc = { version = "=0.164.0", features = ["rust", "comrak"] }
deno_error.workspace = true
deno_graph = { version = "=0.86.9" }
deno_graph = { version = "=0.87.0" }
deno_lint = { version = "=0.68.2", features = ["docs"] }
deno_lockfile.workspace = true
deno_npm.workspace = true
@ -124,7 +125,7 @@ http.workspace = true
http-body.workspace = true
http-body-util.workspace = true
hyper-util.workspace = true
import_map = { version = "=0.20.1", features = ["ext"] }
import_map = { version = "=0.21.0", features = ["ext"] }
indexmap.workspace = true
jsonc-parser = { workspace = true, features = ["cst", "serde"] }
jupyter_runtime = { package = "runtimelib", version = "=0.19.0", features = ["tokio-runtime"] }

View file

@ -10,6 +10,7 @@ use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::parking_lot::MutexGuard;
use deno_core::serde_json;
use deno_error::JsErrorBox;
use deno_lockfile::Lockfile;
use deno_lockfile::WorkspaceMemberConfig;
use deno_package_json::PackageJsonDepValue;
@ -59,6 +60,14 @@ impl<'a, T> std::ops::DerefMut for Guard<'a, T> {
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[error("Failed writing lockfile")]
#[class(inherit)]
struct AtomicWriteFileWithRetriesError {
#[source]
source: std::io::Error,
}
impl CliLockfile {
/// Get the inner deno_lockfile::Lockfile.
pub fn lock(&self) -> Guard<Lockfile> {
@ -78,7 +87,7 @@ impl CliLockfile {
self.lockfile.lock().overwrite
}
pub fn write_if_changed(&self) -> Result<(), AnyError> {
pub fn write_if_changed(&self) -> Result<(), JsErrorBox> {
if self.skip_write {
return Ok(());
}
@ -96,7 +105,9 @@ impl CliLockfile {
&bytes,
cache::CACHE_PERM,
)
.context("Failed writing lockfile.")?;
.map_err(|source| {
JsErrorBox::from_err(AtomicWriteFileWithRetriesError { source })
})?;
lockfile.has_content_changed = false;
Ok(())
}
@ -255,7 +266,7 @@ impl CliLockfile {
})
}
pub fn error_if_changed(&self) -> Result<(), AnyError> {
pub fn error_if_changed(&self) -> Result<(), JsErrorBox> {
if !self.frozen {
return Ok(());
}
@ -267,9 +278,7 @@ impl CliLockfile {
let diff = crate::util::diff::diff(&contents, &new_contents);
// has an extra newline at the end
let diff = diff.trim_end();
Err(deno_core::anyhow::anyhow!(
"The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.\nchanges:\n{diff}"
))
Err(JsErrorBox::generic(format!("The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.\nchanges:\n{diff}")))
} else {
Ok(())
}

View file

@ -26,6 +26,7 @@ use deno_ast::SourceMapOption;
use deno_cache_dir::file_fetcher::CacheSetting;
pub use deno_config::deno_json::BenchConfig;
pub use deno_config::deno_json::ConfigFile;
use deno_config::deno_json::ConfigFileError;
use deno_config::deno_json::FmtConfig;
pub use deno_config::deno_json::FmtOptionsConfig;
use deno_config::deno_json::LintConfig;
@ -55,6 +56,7 @@ use deno_core::error::AnyError;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_graph::GraphKind;
pub use deno_json::check_warn_tsconfig;
use deno_lint::linter::LintConfig as DenoLintConfig;
@ -604,7 +606,8 @@ pub fn create_default_npmrc() -> Arc<ResolvedNpmRc> {
})
}
#[derive(Error, Debug, Clone)]
#[derive(Error, Debug, Clone, deno_error::JsError)]
#[class(generic)]
pub enum RootCertStoreLoadError {
#[error(
"Unknown certificate store \"{0}\" specified (allowed: \"system,mozilla\")"
@ -1104,7 +1107,7 @@ impl CliOptions {
pkg_json_dep_resolution,
specified_import_map: cli_arg_specified_import_map,
},
|path| Ok(std::fs::read_to_string(path)?),
|path| std::fs::read_to_string(path).map_err(JsErrorBox::from_err),
)?)
}
@ -1246,11 +1249,14 @@ impl CliOptions {
pub fn node_modules_dir(
&self,
) -> Result<Option<NodeModulesDirMode>, AnyError> {
) -> Result<
Option<NodeModulesDirMode>,
deno_config::deno_json::NodeModulesDirParseError,
> {
if let Some(flag) = self.flags.node_modules_dir {
return Ok(Some(flag));
}
self.workspace().node_modules_dir().map_err(Into::into)
self.workspace().node_modules_dir()
}
pub fn vendor_dir_path(&self) -> Option<&PathBuf> {
@ -1260,7 +1266,7 @@ impl CliOptions {
pub fn resolve_ts_config_for_emit(
&self,
config_type: TsConfigType,
) -> Result<TsConfigForEmit, AnyError> {
) -> Result<TsConfigForEmit, ConfigFileError> {
self.workspace().resolve_ts_config_for_emit(config_type)
}
@ -1289,7 +1295,7 @@ impl CliOptions {
pub fn to_compiler_option_types(
&self,
) -> Result<Vec<deno_graph::ReferrerImports>, AnyError> {
) -> Result<Vec<deno_graph::ReferrerImports>, serde_json::Error> {
self
.workspace()
.to_compiler_option_types()

View file

@ -13,10 +13,9 @@ mod ts {
use std::path::Path;
use std::path::PathBuf;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::OpState;
use deno_error::JsErrorBox;
use serde::Serialize;
use super::*;
@ -53,7 +52,7 @@ mod ts {
fn op_script_version(
_state: &mut OpState,
#[string] _arg: &str,
) -> Result<Option<String>, AnyError> {
) -> Result<Option<String>, JsErrorBox> {
Ok(Some("1".to_string()))
}
@ -72,7 +71,7 @@ mod ts {
fn op_load(
state: &mut OpState,
#[string] load_specifier: &str,
) -> Result<LoadResponse, AnyError> {
) -> Result<LoadResponse, JsErrorBox> {
let op_crate_libs = state.borrow::<HashMap<&str, PathBuf>>();
let path_dts = state.borrow::<PathBuf>();
let re_asset = lazy_regex::regex!(r"asset:/{3}lib\.(\S+)\.d\.ts");
@ -93,12 +92,15 @@ mod ts {
// if it comes from an op crate, we were supplied with the path to the
// file.
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) {
PathBuf::from(op_crate_lib).canonicalize()?
PathBuf::from(op_crate_lib)
.canonicalize()
.map_err(JsErrorBox::from_err)?
// otherwise we will generate the path ourself
} else {
path_dts.join(format!("lib.{lib}.d.ts"))
};
let data = std::fs::read_to_string(path)?;
let data =
std::fs::read_to_string(path).map_err(JsErrorBox::from_err)?;
Ok(LoadResponse {
data,
version: "1".to_string(),
@ -106,13 +108,13 @@ mod ts {
script_kind: 3,
})
} else {
Err(custom_error(
Err(JsErrorBox::new(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", load_specifier),
))
}
} else {
Err(custom_error(
Err(JsErrorBox::new(
"InvalidSpecifier",
format!("An invalid specifier was requested: {}", load_specifier),
))

17
cli/cache/mod.rs vendored
View file

@ -8,7 +8,6 @@ use deno_ast::MediaType;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind;
use deno_cache_dir::file_fetcher::FileOrRedirect;
use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::futures::FutureExt;
use deno_core::ModuleSpecifier;
@ -62,6 +61,7 @@ pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache<CliSys>;
pub type LocalHttpCache = deno_cache_dir::LocalHttpCache<CliSys>;
pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache<CliSys>;
pub use deno_cache_dir::HttpCache;
use deno_error::JsErrorBox;
pub struct FetchCacherOptions {
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
@ -194,9 +194,9 @@ impl Loader for FetchCacher {
LoaderCacheSetting::Use => None,
LoaderCacheSetting::Reload => {
if matches!(file_fetcher.cache_setting(), CacheSetting::Only) {
return Err(deno_core::anyhow::anyhow!(
return Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::generic(
"Could not resolve version constraint using only cached data. Try running again without --cached-only"
));
))));
}
Some(CacheSetting::ReloadAll)
}
@ -262,28 +262,27 @@ impl Loader for FetchCacher {
FetchNoFollowErrorKind::CacheSave { .. } |
FetchNoFollowErrorKind::UnsupportedScheme { .. } |
FetchNoFollowErrorKind::RedirectHeaderParse { .. } |
FetchNoFollowErrorKind::InvalidHeader { .. } => Err(AnyError::from(err)),
FetchNoFollowErrorKind::InvalidHeader { .. } => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err)))),
FetchNoFollowErrorKind::NotCached { .. } => {
if options.cache_setting == LoaderCacheSetting::Only {
Ok(None)
} else {
Err(AnyError::from(err))
Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err))))
}
},
FetchNoFollowErrorKind::ChecksumIntegrity(err) => {
// convert to the equivalent deno_graph error so that it
// enhances it if this is passed to deno_graph
Err(
deno_graph::source::ChecksumIntegrityError {
deno_graph::source::LoadError::ChecksumIntegrity(deno_graph::source::ChecksumIntegrityError {
actual: err.actual,
expected: err.expected,
}
.into(),
}),
)
}
}
},
CliFetchNoFollowErrorKind::PermissionCheck(permission_check_error) => Err(AnyError::from(permission_check_error)),
CliFetchNoFollowErrorKind::PermissionCheck(permission_check_error) => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(permission_check_error)))),
}
})
}

View file

@ -11,10 +11,12 @@ use deno_ast::SourceRangedForSpanned;
use deno_ast::TranspileModuleOptions;
use deno_ast::TranspileResult;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::MediaType;
use deno_graph::Module;
use deno_graph::ModuleGraph;
@ -124,7 +126,7 @@ impl Emitter {
let transpiled_source = deno_core::unsync::spawn_blocking({
let specifier = specifier.clone();
let source = source.clone();
move || -> Result<_, AnyError> {
move || {
EmitParsedSourceHelper::transpile(
&parsed_source_cache,
&specifier,
@ -155,7 +157,7 @@ impl Emitter {
media_type: MediaType,
module_kind: deno_ast::ModuleKind,
source: &Arc<str>,
) -> Result<String, AnyError> {
) -> Result<String, EmitParsedSourceHelperError> {
// Note: keep this in sync with the async version above
let helper = EmitParsedSourceHelper(self);
match helper.pre_emit_parsed_source(specifier, module_kind, source) {
@ -210,7 +212,7 @@ impl Emitter {
pub async fn load_and_emit_for_hmr(
&self,
specifier: &ModuleSpecifier,
) -> Result<String, AnyError> {
) -> Result<String, CoreError> {
let media_type = MediaType::from_specifier(specifier);
let source_code = tokio::fs::read_to_string(
ModuleSpecifier::to_file_path(specifier).unwrap(),
@ -225,17 +227,21 @@ impl Emitter {
let source_arc: Arc<str> = source_code.into();
let parsed_source = self
.parsed_source_cache
.remove_or_parse_module(specifier, source_arc, media_type)?;
.remove_or_parse_module(specifier, source_arc, media_type)
.map_err(JsErrorBox::from_err)?;
// HMR doesn't work with embedded source maps for some reason, so set
// the option to not use them (though you should test this out because
// this statement is probably wrong)
let mut options = self.transpile_and_emit_options.1.clone();
options.source_map = SourceMapOption::None;
let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script(
specifier,
media_type,
parsed_source.compute_is_script(),
)?;
let is_cjs = self
.cjs_tracker
.is_cjs_with_known_is_script(
specifier,
media_type,
parsed_source.compute_is_script(),
)
.map_err(JsErrorBox::from_err)?;
let transpiled_source = parsed_source
.transpile(
&self.transpile_and_emit_options.0,
@ -243,7 +249,8 @@ impl Emitter {
module_kind: Some(ModuleKind::from_is_cjs(is_cjs)),
},
&options,
)?
)
.map_err(JsErrorBox::from_err)?
.into_source();
Ok(transpiled_source.text)
}
@ -282,6 +289,19 @@ enum PreEmitResult {
NotCached { source_hash: u64 },
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum EmitParsedSourceHelperError {
#[class(inherit)]
#[error(transparent)]
ParseDiagnostic(#[from] deno_ast::ParseDiagnostic),
#[class(inherit)]
#[error(transparent)]
Transpile(#[from] deno_ast::TranspileError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
/// Helper to share code between async and sync emit_parsed_source methods.
struct EmitParsedSourceHelper<'a>(&'a Emitter);
@ -311,7 +331,7 @@ impl<'a> EmitParsedSourceHelper<'a> {
source: Arc<str>,
transpile_options: &deno_ast::TranspileOptions,
emit_options: &deno_ast::EmitOptions,
) -> Result<EmittedSourceText, AnyError> {
) -> Result<EmittedSourceText, EmitParsedSourceHelperError> {
// nothing else needs the parsed source at this point, so remove from
// the cache in order to not transpile owned
let parsed_source = parsed_source_cache
@ -351,7 +371,7 @@ impl<'a> EmitParsedSourceHelper<'a> {
// todo(dsherret): this is a temporary measure until we have swc erroring for this
fn ensure_no_import_assertion(
parsed_source: &deno_ast::ParsedSource,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
fn has_import_assertion(text: &str) -> bool {
// good enough
text.contains(" assert ") && !text.contains(" with ")
@ -360,7 +380,7 @@ fn ensure_no_import_assertion(
fn create_err(
parsed_source: &deno_ast::ParsedSource,
range: SourceRange,
) -> AnyError {
) -> JsErrorBox {
let text_info = parsed_source.text_info_lazy();
let loc = text_info.line_and_column_display(range.start);
let mut msg = "Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.".to_string();
@ -373,7 +393,7 @@ fn ensure_no_import_assertion(
loc.line_number,
loc.column_number,
));
deno_core::anyhow::anyhow!("{}", msg)
JsErrorBox::generic(msg)
}
let deno_ast::ProgramRef::Module(module) = parsed_source.program_ref() else {

View file

@ -1,123 +0,0 @@
// Copyright 2018-2025 the Deno authors. MIT license.
//! There are many types of errors in Deno:
//! - AnyError: a generic wrapper that can encapsulate any type of error.
//! - JsError: a container for the error message and stack trace for exceptions
//! thrown in JavaScript code. We use this to pretty-print stack traces.
//! - Diagnostic: these are errors that originate in TypeScript's compiler.
//! They're similar to JsError, in that they have line numbers. But
//! Diagnostics are compile-time type errors, whereas JsErrors are runtime
//! exceptions.
use deno_ast::ParseDiagnostic;
use deno_core::error::AnyError;
use deno_graph::source::ResolveError;
use deno_graph::ModuleError;
use deno_graph::ModuleGraphError;
use deno_graph::ModuleLoadError;
use deno_graph::ResolutionError;
use import_map::ImportMapError;
fn get_import_map_error_class(_: &ImportMapError) -> &'static str {
"URIError"
}
fn get_diagnostic_class(_: &ParseDiagnostic) -> &'static str {
"SyntaxError"
}
pub fn get_module_graph_error_class(err: &ModuleGraphError) -> &'static str {
match err {
ModuleGraphError::ResolutionError(err)
| ModuleGraphError::TypesResolutionError(err) => {
get_resolution_error_class(err)
}
ModuleGraphError::ModuleError(err) => get_module_error_class(err),
}
}
pub fn get_module_error_class(err: &ModuleError) -> &'static str {
use deno_graph::JsrLoadError;
use deno_graph::NpmLoadError;
match err {
ModuleError::InvalidTypeAssertion { .. } => "SyntaxError",
ModuleError::ParseErr(_, diagnostic) => get_diagnostic_class(diagnostic),
ModuleError::WasmParseErr(..) => "SyntaxError",
ModuleError::UnsupportedMediaType { .. }
| ModuleError::UnsupportedImportAttributeType { .. } => "TypeError",
ModuleError::Missing(_, _) | ModuleError::MissingDynamic(_, _) => {
"NotFound"
}
ModuleError::LoadingErr(_, _, err) => match err {
ModuleLoadError::Loader(err) => get_error_class_name(err.as_ref()),
ModuleLoadError::HttpsChecksumIntegrity(_)
| ModuleLoadError::TooManyRedirects => "Error",
ModuleLoadError::NodeUnknownBuiltinModule(_) => "NotFound",
ModuleLoadError::Decode(_) => "TypeError",
ModuleLoadError::Npm(err) => match err {
NpmLoadError::NotSupportedEnvironment
| NpmLoadError::PackageReqResolution(_)
| NpmLoadError::RegistryInfo(_) => "Error",
NpmLoadError::PackageReqReferenceParse(_) => "TypeError",
},
ModuleLoadError::Jsr(err) => match err {
JsrLoadError::UnsupportedManifestChecksum
| JsrLoadError::PackageFormat(_) => "TypeError",
JsrLoadError::ContentLoadExternalSpecifier
| JsrLoadError::ContentLoad(_)
| JsrLoadError::ContentChecksumIntegrity(_)
| JsrLoadError::PackageManifestLoad(_, _)
| JsrLoadError::PackageVersionManifestChecksumIntegrity(..)
| JsrLoadError::PackageVersionManifestLoad(_, _)
| JsrLoadError::RedirectInPackage(_) => "Error",
JsrLoadError::PackageNotFound(_)
| JsrLoadError::PackageReqNotFound(_)
| JsrLoadError::PackageVersionNotFound(_)
| JsrLoadError::UnknownExport { .. } => "NotFound",
},
},
}
}
fn get_resolution_error_class(err: &ResolutionError) -> &'static str {
match err {
ResolutionError::ResolverError { error, .. } => {
use ResolveError::*;
match error.as_ref() {
Specifier(_) => "TypeError",
Other(e) => get_error_class_name(e),
}
}
_ => "TypeError",
}
}
fn get_try_from_int_error_class(_: &std::num::TryFromIntError) -> &'static str {
"TypeError"
}
pub fn get_error_class_name(e: &AnyError) -> &'static str {
deno_runtime::errors::get_error_class_name(e)
.or_else(|| {
e.downcast_ref::<ImportMapError>()
.map(get_import_map_error_class)
})
.or_else(|| {
e.downcast_ref::<ParseDiagnostic>()
.map(get_diagnostic_class)
})
.or_else(|| {
e.downcast_ref::<ModuleGraphError>()
.map(get_module_graph_error_class)
})
.or_else(|| {
e.downcast_ref::<ResolutionError>()
.map(get_resolution_error_class)
})
.or_else(|| {
e.downcast_ref::<std::num::TryFromIntError>()
.map(get_try_from_int_error_class)
})
.unwrap_or("Error")
}

View file

@ -10,6 +10,7 @@ use deno_config::workspace::WorkspaceResolver;
use deno_core::error::AnyError;
use deno_core::futures::FutureExt;
use deno_core::FeatureChecker;
use deno_error::JsErrorBox;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions;
@ -118,7 +119,7 @@ impl CliRootCertStoreProvider {
}
impl RootCertStoreProvider for CliRootCertStoreProvider {
fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> {
fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox> {
self
.cell
.get_or_try_init(|| {
@ -128,7 +129,7 @@ impl RootCertStoreProvider for CliRootCertStoreProvider {
self.maybe_ca_data.clone(),
)
})
.map_err(|e| e.into())
.map_err(JsErrorBox::from_err)
}
}

View file

@ -2,17 +2,18 @@
use std::collections::HashSet;
use std::error::Error;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
use deno_config::deno_json;
use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::JsrPackageConfig;
use deno_core::anyhow::bail;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
use deno_graph::source::Loader;
use deno_graph::source::LoaderChecksum;
use deno_graph::source::ResolutionKind;
@ -49,8 +50,6 @@ use crate::cache::GlobalHttpCache;
use crate::cache::ModuleInfoCache;
use crate::cache::ParsedSourceCache;
use crate::colors;
use crate::errors::get_error_class_name;
use crate::errors::get_module_graph_error_class;
use crate::file_fetcher::CliFileFetcher;
use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker;
@ -59,6 +58,7 @@ use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::SloppyImportsCachedFs;
use crate::sys::CliSys;
use crate::tools::check;
use crate::tools::check::CheckError;
use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path;
@ -85,7 +85,7 @@ pub fn graph_valid(
sys: &CliSys,
roots: &[ModuleSpecifier],
options: GraphValidOptions,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
if options.exit_integrity_errors {
graph_exit_integrity_errors(graph);
}
@ -104,9 +104,9 @@ pub fn graph_valid(
} else {
// finally surface the npm resolution result
if let Err(err) = &graph.npm_dep_graph_result {
return Err(custom_error(
get_error_class_name(err),
format_deno_graph_error(err.as_ref().deref()),
return Err(JsErrorBox::new(
err.get_class(),
format_deno_graph_error(err),
));
}
Ok(())
@ -145,7 +145,7 @@ pub fn graph_walk_errors<'a>(
sys: &'a CliSys,
roots: &'a [ModuleSpecifier],
options: GraphWalkErrorsOptions,
) -> impl Iterator<Item = AnyError> + 'a {
) -> impl Iterator<Item = JsErrorBox> + 'a {
graph
.walk(
roots.iter(),
@ -197,7 +197,7 @@ pub fn graph_walk_errors<'a>(
return None;
}
Some(custom_error(get_module_graph_error_class(&error), message))
Some(JsErrorBox::new(error.get_class(), message))
})
}
@ -437,14 +437,14 @@ impl ModuleGraphCreator {
}
}
pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), AnyError> {
pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), JsErrorBox> {
self.module_graph_builder.graph_valid(graph)
}
async fn type_check_graph(
&self,
graph: ModuleGraph,
) -> Result<Arc<ModuleGraph>, AnyError> {
) -> Result<Arc<ModuleGraph>, CheckError> {
self
.type_checker
.check(
@ -467,6 +467,27 @@ pub struct BuildFastCheckGraphOptions<'a> {
pub workspace_fast_check: deno_graph::WorkspaceFastCheckOption<'a>,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum BuildGraphWithNpmResolutionError {
#[class(inherit)]
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),
#[class(inherit)]
#[error(transparent)]
ToMaybeJsxImportSourceConfig(
#[from] deno_json::ToMaybeJsxImportSourceConfigError,
),
#[class(inherit)]
#[error(transparent)]
NodeModulesDirParse(#[from] deno_json::NodeModulesDirParseError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
#[class(generic)]
#[error("Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead")]
UnsupportedNpmSpecifierEntrypointResolutionWay,
}
pub struct ModuleGraphBuilder {
caches: Arc<cache::Caches>,
cjs_tracker: Arc<CjsTracker>,
@ -524,7 +545,7 @@ impl ModuleGraphBuilder {
&self,
graph: &mut ModuleGraph,
options: CreateGraphOptions<'a>,
) -> Result<(), AnyError> {
) -> Result<(), BuildGraphWithNpmResolutionError> {
enum MutLoaderRef<'a> {
Borrowed(&'a mut dyn Loader),
Owned(cache::FetchCacher),
@ -652,7 +673,7 @@ impl ModuleGraphBuilder {
loader: &'a mut dyn deno_graph::source::Loader,
options: deno_graph::BuildOptions<'a>,
npm_caching: NpmCachingStrategy,
) -> Result<(), AnyError> {
) -> Result<(), BuildGraphWithNpmResolutionError> {
// ensure an "npm install" is done if the user has explicitly
// opted into using a node_modules directory
if self
@ -689,7 +710,7 @@ impl ModuleGraphBuilder {
if roots.iter().any(|r| r.scheme() == "npm")
&& self.npm_resolver.as_byonm().is_some()
{
bail!("Resolving npm specifier entrypoints this way is currently not supported with \"nodeModules\": \"manual\". In the meantime, try with --node-modules-dir=auto instead");
return Err(BuildGraphWithNpmResolutionError::UnsupportedNpmSpecifierEntrypointResolutionWay);
}
graph.build(roots, loader, options).await;
@ -740,7 +761,7 @@ impl ModuleGraphBuilder {
&self,
graph: &mut ModuleGraph,
options: BuildFastCheckGraphOptions,
) -> Result<(), AnyError> {
) -> Result<(), deno_json::ToMaybeJsxImportSourceConfigError> {
if !graph.graph_kind().include_types() {
return Ok(());
}
@ -804,7 +825,7 @@ impl ModuleGraphBuilder {
/// Check if `roots` and their deps are available. Returns `Ok(())` if
/// so. Returns `Err(_)` if there is a known module graph or resolution
/// error statically reachable from `roots` and not a dynamic import.
pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), AnyError> {
pub fn graph_valid(&self, graph: &ModuleGraph) -> Result<(), JsErrorBox> {
self.graph_roots_valid(
graph,
&graph.roots.iter().cloned().collect::<Vec<_>>(),
@ -815,7 +836,7 @@ impl ModuleGraphBuilder {
&self,
graph: &ModuleGraph,
roots: &[ModuleSpecifier],
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
graph_valid(
graph,
&self.sys,
@ -832,7 +853,10 @@ impl ModuleGraphBuilder {
)
}
fn create_graph_resolver(&self) -> Result<CliGraphResolver, AnyError> {
fn create_graph_resolver(
&self,
) -> Result<CliGraphResolver, deno_json::ToMaybeJsxImportSourceConfigError>
{
let jsx_import_source_config = self
.cli_options
.workspace()
@ -1001,8 +1025,13 @@ fn get_resolution_error_bare_specifier(
Some(specifier.as_str())
} else if let ResolutionError::ResolverError { error, .. } = error {
if let ResolveError::Other(error) = (*error).as_ref() {
if let Some(ImportMapError::UnmappedBareSpecifier(specifier, _)) =
error.downcast_ref::<ImportMapError>()
if let Some(import_map::ImportMapErrorKind::UnmappedBareSpecifier(
specifier,
_,
)) = error
.as_any()
.downcast_ref::<ImportMapError>()
.map(|e| &**e)
{
Some(specifier.as_str())
} else {
@ -1039,11 +1068,12 @@ fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> {
ResolveError::Other(other_error) => {
if let Some(SpecifierError::ImportPrefixMissing {
specifier, ..
}) = other_error.downcast_ref::<SpecifierError>()
}) = other_error.as_any().downcast_ref::<SpecifierError>()
{
maybe_specifier = Some(specifier);
}
}
ResolveError::ImportMap(_) => {}
}
}
}
@ -1294,7 +1324,7 @@ mod test {
let specifier = ModuleSpecifier::parse("file:///file.ts").unwrap();
let err = import_map.resolve(input, &specifier).err().unwrap();
let err = ResolutionError::ResolverError {
error: Arc::new(ResolveError::Other(err.into())),
error: Arc::new(ResolveError::Other(JsErrorBox::from_err(err))),
specifier: input.to_string(),
range: Range {
specifier,

View file

@ -6,13 +6,14 @@ use std::thread::ThreadId;
use boxed_error::Boxed;
use deno_cache_dir::file_fetcher::RedirectHeaderParseError;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::futures::StreamExt;
use deno_core::parking_lot::Mutex;
use deno_core::serde;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsError;
use deno_error::JsErrorBox;
use deno_runtime::deno_fetch;
use deno_runtime::deno_fetch::create_http_client;
use deno_runtime::deno_fetch::CreateHttpClientOptions;
@ -94,34 +95,49 @@ impl HttpClientProvider {
}
}
#[derive(Debug, Error)]
#[derive(Debug, Error, JsError)]
#[class(type)]
#[error("Bad response: {:?}{}", .status_code, .response_text.as_ref().map(|s| format!("\n\n{}", s)).unwrap_or_else(String::new))]
pub struct BadResponseError {
pub status_code: StatusCode,
pub response_text: Option<String>,
}
#[derive(Debug, Boxed)]
#[derive(Debug, Boxed, JsError)]
pub struct DownloadError(pub Box<DownloadErrorKind>);
#[derive(Debug, Error)]
#[derive(Debug, Error, JsError)]
pub enum DownloadErrorKind {
#[class(inherit)]
#[error(transparent)]
Fetch(AnyError),
Fetch(deno_fetch::ClientSendError),
#[class(inherit)]
#[error(transparent)]
UrlParse(#[from] deno_core::url::ParseError),
#[class(generic)]
#[error(transparent)]
HttpParse(#[from] http::Error),
#[class(inherit)]
#[error(transparent)]
Json(#[from] serde_json::Error),
#[class(generic)]
#[error(transparent)]
ToStr(#[from] http::header::ToStrError),
#[class(inherit)]
#[error(transparent)]
RedirectHeaderParse(RedirectHeaderParseError),
#[class(type)]
#[error("Too many redirects.")]
TooManyRedirects,
#[class(inherit)]
#[error(transparent)]
BadResponse(#[from] BadResponseError),
#[class("Http")]
#[error("Not Found.")]
NotFound,
#[class(inherit)]
#[error(transparent)]
Other(JsErrorBox),
}
#[derive(Debug)]
@ -208,11 +224,11 @@ impl HttpClient {
Ok(String::from_utf8(bytes)?)
}
pub async fn download(&self, url: Url) -> Result<Vec<u8>, AnyError> {
pub async fn download(&self, url: Url) -> Result<Vec<u8>, DownloadError> {
let maybe_bytes = self.download_inner(url, None, None).await?;
match maybe_bytes {
Some(bytes) => Ok(bytes),
None => Err(custom_error("Http", "Not found.")),
None => Err(DownloadErrorKind::NotFound.into_box()),
}
}
@ -276,7 +292,7 @@ impl HttpClient {
get_response_body_with_progress(response, progress_guard)
.await
.map(|(_, body)| Some(body))
.map_err(|err| DownloadErrorKind::Fetch(err).into_box())
.map_err(|err| DownloadErrorKind::Other(err).into_box())
}
async fn get_redirected_response(
@ -293,7 +309,7 @@ impl HttpClient {
.clone()
.send(req)
.await
.map_err(|e| DownloadErrorKind::Fetch(e.into()).into_box())?;
.map_err(|e| DownloadErrorKind::Fetch(e).into_box())?;
let status = response.status();
if status.is_redirection() {
for _ in 0..5 {
@ -313,7 +329,7 @@ impl HttpClient {
.clone()
.send(req)
.await
.map_err(|e| DownloadErrorKind::Fetch(e.into()).into_box())?;
.map_err(|e| DownloadErrorKind::Fetch(e).into_box())?;
let status = new_response.status();
if status.is_redirection() {
response = new_response;
@ -332,7 +348,7 @@ impl HttpClient {
pub async fn get_response_body_with_progress(
response: http::Response<deno_fetch::ResBody>,
progress_guard: Option<&UpdateGuard>,
) -> Result<(HeaderMap, Vec<u8>), AnyError> {
) -> Result<(HeaderMap, Vec<u8>), JsErrorBox> {
use http_body::Body as _;
if let Some(progress_guard) = progress_guard {
let mut total_size = response.body().size_hint().exact();

View file

@ -10,13 +10,13 @@ use deno_ast::SourceRange;
use deno_ast::SourceRangedForSpanned;
use deno_ast::SourceTextInfo;
use deno_config::workspace::MappedResolution;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_lint::diagnostic::LintDiagnosticRange;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_node::PathClean;
@ -1070,10 +1070,13 @@ impl CodeActionCollection {
// we wrap tsc, we can't handle the asynchronous response, so it is
// actually easier to return errors if we ever encounter one of these,
// which we really wouldn't expect from the Deno lsp.
return Err(custom_error(
"UnsupportedFix",
"The action returned from TypeScript is unsupported.",
));
return Err(
JsErrorBox::new(
"UnsupportedFix",
"The action returned from TypeScript is unsupported.",
)
.into(),
);
}
let Some(action) =
fix_ts_import_action(specifier, resolution_mode, action, language_server)

View file

@ -41,6 +41,7 @@ use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_package_json::PackageJsonCache;
@ -1575,7 +1576,7 @@ impl ConfigData {
pkg_json_dep_resolution,
specified_import_map,
},
|path| Ok(std::fs::read_to_string(path)?),
|path| std::fs::read_to_string(path).map_err(JsErrorBox::from_err),
)
.inspect_err(|err| {
lsp_warn!(

View file

@ -34,7 +34,7 @@ use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq;
use import_map::ImportMap;
use import_map::ImportMapError;
use import_map::ImportMapErrorKind;
use log::error;
use tokio::sync::mpsc;
use tokio::sync::Mutex;
@ -1297,8 +1297,8 @@ impl DenoDiagnostic {
let mut message;
message = enhanced_resolution_error_message(err);
if let deno_graph::ResolutionError::ResolverError {error, ..} = err{
if let ResolveError::Other(resolve_error, ..) = (*error).as_ref() {
if let Some(ImportMapError::UnmappedBareSpecifier(specifier, _)) = resolve_error.downcast_ref::<ImportMapError>() {
if let ResolveError::ImportMap(importmap) = (*error).as_ref() {
if let ImportMapErrorKind::UnmappedBareSpecifier(specifier, _) = &**importmap {
if specifier.chars().next().unwrap_or('\0') == '@'{
let hint = format!("\nHint: Use [deno add {}] to add the dependency.", specifier);
message.push_str(hint.as_str());

View file

@ -18,13 +18,13 @@ use deno_ast::swc::visit::VisitWith;
use deno_ast::MediaType;
use deno_ast::ParsedSource;
use deno_ast::SourceTextInfo;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::futures::future;
use deno_core::futures::future::Shared;
use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::Resolution;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_node;
@ -1081,7 +1081,7 @@ impl Documents {
.or_else(|| self.file_system_docs.remove_document(specifier))
.map(Ok)
.unwrap_or_else(|| {
Err(custom_error(
Err(JsErrorBox::new(
"NotFound",
format!("The specifier \"{specifier}\" was not found."),
))

View file

@ -122,7 +122,7 @@ use crate::util::sync::AsyncFlag;
struct LspRootCertStoreProvider(RootCertStore);
impl RootCertStoreProvider for LspRootCertStoreProvider {
fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> {
fn get_or_try_init(&self) -> Result<&RootCertStore, deno_error::JsErrorBox> {
Ok(&self.0)
}
}

View file

@ -2,8 +2,8 @@
use std::collections::HashMap;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use dissimilar::diff;
use dissimilar::Chunk;
use text_size::TextRange;
@ -137,7 +137,7 @@ impl LineIndex {
if let Some(line_offset) = self.utf8_offsets.get(position.line as usize) {
Ok(line_offset + col)
} else {
Err(custom_error("OutOfRange", "The position is out of range."))
Err(JsErrorBox::new("OutOfRange", "The position is out of range.").into())
}
}
@ -157,7 +157,7 @@ impl LineIndex {
if let Some(line_offset) = self.utf16_offsets.get(position.line as usize) {
Ok(line_offset + TextSize::from(position.character))
} else {
Err(custom_error("OutOfRange", "The position is out of range."))
Err(JsErrorBox::new("OutOfRange", "The position is out of range.").into())
}
}

View file

@ -20,7 +20,6 @@ use deno_core::anyhow::Context as _;
use deno_core::convert::Smi;
use deno_core::convert::ToV8;
use deno_core::error::AnyError;
use deno_core::error::StdAnyError;
use deno_core::futures::stream::FuturesOrdered;
use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt;
@ -4331,7 +4330,7 @@ impl TscSpecifierMap {
pub fn normalize<S: AsRef<str>>(
&self,
specifier: S,
) -> Result<ModuleSpecifier, AnyError> {
) -> Result<ModuleSpecifier, deno_core::url::ParseError> {
let original = specifier.as_ref();
if let Some(specifier) = self.normalized_specifiers.get(original) {
return Ok(specifier.clone());
@ -4339,7 +4338,7 @@ impl TscSpecifierMap {
let specifier_str = original.replace(".d.ts.d.ts", ".d.ts");
let specifier = match ModuleSpecifier::parse(&specifier_str) {
Ok(s) => s,
Err(err) => return Err(err.into()),
Err(err) => return Err(err),
};
if specifier.as_str() != original {
self
@ -4437,6 +4436,16 @@ fn op_is_node_file(state: &mut OpState, #[string] path: String) -> bool {
r
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
enum LoadError {
#[error("{0}")]
#[class(inherit)]
UrlParse(#[from] deno_core::url::ParseError),
#[error("{0}")]
#[class(inherit)]
SerdeV8(#[from] serde_v8::Error),
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct LoadResponse {
@ -4451,7 +4460,7 @@ fn op_load<'s>(
scope: &'s mut v8::HandleScope,
state: &mut OpState,
#[string] specifier: &str,
) -> Result<v8::Local<'s, v8::Value>, AnyError> {
) -> Result<v8::Local<'s, v8::Value>, LoadError> {
let state = state.borrow_mut::<State>();
let mark = state
.performance
@ -4482,7 +4491,7 @@ fn op_load<'s>(
fn op_release(
state: &mut OpState,
#[string] specifier: &str,
) -> Result<(), AnyError> {
) -> Result<(), deno_core::url::ParseError> {
let state = state.borrow_mut::<State>();
let mark = state
.performance
@ -4499,7 +4508,7 @@ fn op_resolve(
state: &mut OpState,
#[string] base: String,
#[serde] specifiers: Vec<(bool, String)>,
) -> Result<Vec<Option<(String, String)>>, AnyError> {
) -> Result<Vec<Option<(String, String)>>, deno_core::url::ParseError> {
op_resolve_inner(state, ResolveArgs { base, specifiers })
}
@ -4511,7 +4520,7 @@ struct TscRequestArray {
}
impl<'a> ToV8<'a> for TscRequestArray {
type Error = StdAnyError;
type Error = serde_v8::Error;
fn to_v8(
self,
@ -4526,9 +4535,7 @@ impl<'a> ToV8<'a> for TscRequestArray {
.unwrap()
.into();
let args = args.unwrap_or_else(|| v8::Array::new(scope, 0).into());
let scope_url = serde_v8::to_v8(scope, self.scope)
.map_err(AnyError::from)
.map_err(StdAnyError::from)?;
let scope_url = serde_v8::to_v8(scope, self.scope)?;
let change = self.change.to_v8(scope).unwrap_infallible();
@ -4586,7 +4593,7 @@ async fn op_poll_requests(
fn op_resolve_inner(
state: &mut OpState,
args: ResolveArgs,
) -> Result<Vec<Option<(String, String)>>, AnyError> {
) -> Result<Vec<Option<(String, String)>>, deno_core::url::ParseError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark_with_args("tsc.op.op_resolve", &args);
let referrer = state.specifier_map.normalize(&args.base)?;
@ -4743,7 +4750,7 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
fn op_script_version(
state: &mut OpState,
#[string] specifier: &str,
) -> Result<Option<String>, AnyError> {
) -> Result<Option<String>, deno_core::url::ParseError> {
let state = state.borrow_mut::<State>();
let mark = state.performance.mark("tsc.op.op_script_version");
let specifier = state.specifier_map.normalize(specifier)?;
@ -5398,7 +5405,8 @@ impl TscRequest {
fn to_server_request<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
) -> Result<(&'static str, Option<v8::Local<'s, v8::Value>>), AnyError> {
) -> Result<(&'static str, Option<v8::Local<'s, v8::Value>>), serde_v8::Error>
{
let args = match self {
TscRequest::GetDiagnostics(args) => {
("$getDiagnostics", Some(serde_v8::to_v8(scope, args)?))

View file

@ -4,7 +4,6 @@ mod args;
mod cache;
mod cdp;
mod emit;
mod errors;
mod factory;
mod file_fetcher;
mod graph_container;
@ -38,7 +37,7 @@ use std::sync::Arc;
use args::TaskFlags;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::error::CoreError;
use deno_core::futures::FutureExt;
use deno_core::unsync::JoinHandle;
use deno_npm::resolution::SnapshotFromLockfileError;
@ -202,7 +201,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
match result {
Ok(v) => Ok(v),
Err(script_err) => {
if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = script_err.downcast_ref::<ResolvePkgFolderFromDenoReqError>() {
if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = util::result::any_and_jserrorbox_downcast_ref::<ResolvePkgFolderFromDenoReqError>(&script_err) {
if flags.node_modules_dir.is_none() {
let mut flags = flags.deref().clone();
let watch = match &flags.subcommand {
@ -373,10 +372,14 @@ fn exit_for_error(error: AnyError) -> ! {
let mut error_string = format!("{error:?}");
let mut error_code = 1;
if let Some(e) = error.downcast_ref::<JsError>() {
if let Some(CoreError::Js(e)) =
util::result::any_and_jserrorbox_downcast_ref::<CoreError>(&error)
{
error_string = format_js_error(e);
} else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) =
error.downcast_ref::<SnapshotFromLockfileError>()
util::result::any_and_jserrorbox_downcast_ref::<SnapshotFromLockfileError>(
&error,
)
{
error_string = e.to_string();
error_code = 10;

View file

@ -10,7 +10,6 @@ mod standalone;
mod args;
mod cache;
mod emit;
mod errors;
mod file_fetcher;
mod http_util;
mod js;
@ -30,8 +29,8 @@ use std::env;
use std::env::current_exe;
use std::sync::Arc;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::error::JsError;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
@ -41,6 +40,7 @@ use indexmap::IndexMap;
use standalone::DenoCompileFileSystem;
use crate::args::Flags;
use crate::util::result::any_and_jserrorbox_downcast_ref;
pub(crate) fn unstable_exit_cb(feature: &str, api_name: &str) {
log::error!(
@ -65,8 +65,10 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
Err(error) => {
let mut error_string = format!("{:?}", error);
if let Some(e) = error.downcast_ref::<JsError>() {
error_string = format_js_error(e);
if let Some(CoreError::Js(js_error)) =
any_and_jserrorbox_downcast_ref::<CoreError>(&error)
{
error_string = format_js_error(js_error);
}
exit_with_message(&error_string, 1);

View file

@ -14,11 +14,9 @@ use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleKind;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::future::FutureExt;
use deno_core::futures::Future;
use deno_core::parking_lot::Mutex;
@ -31,6 +29,8 @@ use deno_core::ModuleSpecifier;
use deno_core::ModuleType;
use deno_core::RequestedModuleType;
use deno_core::SourceCodeCacheInfo;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
use deno_graph::GraphKind;
use deno_graph::JsModule;
use deno_graph::JsonModule;
@ -59,7 +59,6 @@ use crate::cache::CodeCache;
use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
use crate::errors::get_module_error_class;
use crate::graph_container::MainModuleGraphContainer;
use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
@ -79,6 +78,7 @@ use crate::resolver::NotSupportedKindInNpmError;
use crate::resolver::NpmModuleLoader;
use crate::sys::CliSys;
use crate::tools::check;
use crate::tools::check::CheckError;
use crate::tools::check::TypeChecker;
use crate::util::progress_bar::ProgressBar;
use crate::util::text_encoding::code_without_source_map;
@ -86,6 +86,21 @@ use crate::util::text_encoding::source_map_from_code;
use crate::worker::CreateModuleLoaderResult;
use crate::worker::ModuleLoaderFactory;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum PrepareModuleLoadError {
#[class(inherit)]
#[error(transparent)]
BuildGraphWithNpmResolution(
#[from] crate::graph_util::BuildGraphWithNpmResolutionError,
),
#[class(inherit)]
#[error(transparent)]
Check(#[from] CheckError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
pub struct ModuleLoadPreparer {
options: Arc<CliOptions>,
lockfile: Option<Arc<CliLockfile>>,
@ -125,7 +140,7 @@ impl ModuleLoadPreparer {
lib: TsTypeLib,
permissions: PermissionsContainer,
ext_overwrite: Option<&String>,
) -> Result<(), AnyError> {
) -> Result<(), PrepareModuleLoadError> {
log::debug!("Preparing module load.");
let _pb_clear_guard = self.progress_bar.clear_guard();
@ -206,7 +221,7 @@ impl ModuleLoadPreparer {
&self,
graph: &ModuleGraph,
roots: &[ModuleSpecifier],
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
self.module_graph_builder.graph_roots_valid(graph, roots)
}
}
@ -423,7 +438,7 @@ impl<TGraphContainer: ModuleGraphContainer>
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
requested_module_type: RequestedModuleType,
) -> Result<ModuleSource, AnyError> {
) -> Result<ModuleSource, ModuleLoaderError> {
let code_source = self.load_code_source(specifier, maybe_referrer).await?;
let code = if self.shared.is_inspecting
|| code_source.media_type == MediaType::Wasm
@ -446,7 +461,7 @@ impl<TGraphContainer: ModuleGraphContainer>
if module_type == ModuleType::Json
&& requested_module_type != RequestedModuleType::Json
{
return Err(generic_error("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement."));
return Err(JsErrorBox::generic("Attempted to load JSON module without specifying \"type\": \"json\" attribute in the import statement.").into());
}
let code_cache = if module_type == ModuleType::JavaScript {
@ -507,7 +522,7 @@ impl<TGraphContainer: ModuleGraphContainer>
fn resolve_referrer(
&self,
referrer: &str,
) -> Result<ModuleSpecifier, AnyError> {
) -> Result<ModuleSpecifier, ModuleLoaderError> {
let referrer = if referrer.is_empty() && self.shared.is_repl {
// FIXME(bartlomieju): this is a hacky way to provide compatibility with REPL
// and `Deno.core.evalContext` API. Ideally we should always have a referrer filled
@ -533,7 +548,7 @@ impl<TGraphContainer: ModuleGraphContainer>
&self,
raw_specifier: &str,
referrer: &ModuleSpecifier,
) -> Result<ModuleSpecifier, AnyError> {
) -> Result<ModuleSpecifier, ModuleLoaderError> {
let graph = self.graph_container.graph();
let resolution = match graph.get(referrer) {
Some(Module::Js(module)) => module
@ -547,19 +562,25 @@ impl<TGraphContainer: ModuleGraphContainer>
let specifier = match resolution {
Resolution::Ok(resolved) => Cow::Borrowed(&resolved.specifier),
Resolution::Err(err) => {
return Err(custom_error(
"TypeError",
format!("{}\n", err.to_string_with_range()),
));
return Err(
JsErrorBox::type_error(format!("{}\n", err.to_string_with_range()))
.into(),
);
}
Resolution::None => Cow::Owned(self.shared.resolver.resolve(
raw_specifier,
referrer,
deno_graph::Position::zeroed(),
// if we're here, that means it's resolving a dynamic import
ResolutionMode::Import,
NodeResolutionKind::Execution,
)?),
Resolution::None => Cow::Owned(
self
.shared
.resolver
.resolve(
raw_specifier,
referrer,
deno_graph::Position::zeroed(),
// if we're here, that means it's resolving a dynamic import
ResolutionMode::Import,
NodeResolutionKind::Execution,
)
.map_err(JsErrorBox::from_err)?,
),
};
if self.shared.is_repl {
@ -574,7 +595,7 @@ impl<TGraphContainer: ModuleGraphContainer>
ResolutionMode::Import,
NodeResolutionKind::Execution,
)
.map_err(AnyError::from);
.map_err(|e| JsErrorBox::from_err(e).into());
}
}
@ -585,7 +606,8 @@ impl<TGraphContainer: ModuleGraphContainer>
.npm_resolver
.as_managed()
.unwrap() // byonm won't create a Module::Npm
.resolve_pkg_folder_from_deno_module(module.nv_reference.nv())?;
.resolve_pkg_folder_from_deno_module(module.nv_reference.nv())
.map_err(JsErrorBox::from_err)?;
self
.shared
.node_resolver
@ -701,7 +723,7 @@ impl<TGraphContainer: ModuleGraphContainer>
&self,
graph: &'graph ModuleGraph,
specifier: &ModuleSpecifier,
) -> Result<Option<CodeOrDeferredEmit<'graph>>, AnyError> {
) -> Result<Option<CodeOrDeferredEmit<'graph>>, JsErrorBox> {
if specifier.scheme() == "node" {
// Node built-in modules should be handled internally.
unreachable!("Deno bug. {} was misconfigured internally.", specifier);
@ -710,8 +732,8 @@ impl<TGraphContainer: ModuleGraphContainer>
let maybe_module = match graph.try_get(specifier) {
Ok(module) => module,
Err(err) => {
return Err(custom_error(
get_module_error_class(err),
return Err(JsErrorBox::new(
err.get_class(),
enhance_graph_error(
&self.shared.sys,
&ModuleGraphError::ModuleError(err.clone()),
@ -739,11 +761,12 @@ impl<TGraphContainer: ModuleGraphContainer>
is_script,
..
})) => {
if self.shared.cjs_tracker.is_cjs_with_known_is_script(
specifier,
*media_type,
*is_script,
)? {
if self
.shared
.cjs_tracker
.is_cjs_with_known_is_script(specifier, *media_type, *is_script)
.map_err(JsErrorBox::from_err)?
{
return Ok(Some(CodeOrDeferredEmit::Cjs {
specifier,
media_type: *media_type,
@ -875,16 +898,16 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
specifier: &str,
referrer: &str,
_kind: deno_core::ResolutionKind,
) -> Result<ModuleSpecifier, AnyError> {
) -> Result<ModuleSpecifier, ModuleLoaderError> {
fn ensure_not_jsr_non_jsr_remote_import(
specifier: &ModuleSpecifier,
referrer: &ModuleSpecifier,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
if referrer.as_str().starts_with(jsr_url().as_str())
&& !specifier.as_str().starts_with(jsr_url().as_str())
&& matches!(specifier.scheme(), "http" | "https")
{
bail!("Importing {} blocked. JSR packages cannot import non-JSR remote modules for security reasons.", specifier);
return Err(JsErrorBox::generic(format!("Importing {} blocked. JSR packages cannot import non-JSR remote modules for security reasons.", specifier)));
}
Ok(())
}
@ -937,7 +960,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
specifier: &ModuleSpecifier,
_maybe_referrer: Option<String>,
is_dynamic: bool,
) -> Pin<Box<dyn Future<Output = Result<(), AnyError>>>> {
) -> Pin<Box<dyn Future<Output = Result<(), ModuleLoaderError>>>> {
self.0.shared.in_flight_loads_tracker.increase();
if self.0.shared.in_npm_pkg_checker.in_npm_package(specifier) {
return Box::pin(deno_core::futures::future::ready(Ok(())));
@ -986,7 +1009,8 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
permissions,
None,
)
.await?;
.await
.map_err(JsErrorBox::from_err)?;
update_permit.commit();
Ok(())
}
@ -1130,35 +1154,37 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
&self,
permissions: &mut dyn deno_runtime::deno_node::NodePermissions,
path: &'a Path,
) -> Result<std::borrow::Cow<'a, Path>, AnyError> {
) -> Result<Cow<'a, Path>, JsErrorBox> {
if let Ok(url) = deno_path_util::url_from_file_path(path) {
// allow reading if it's in the module graph
if self.graph_container.graph().get(&url).is_some() {
return Ok(std::borrow::Cow::Borrowed(path));
return Ok(Cow::Borrowed(path));
}
}
self
.npm_registry_permission_checker
.ensure_read_permission(permissions, path)
.map_err(JsErrorBox::from_err)
}
fn load_text_file_lossy(
&self,
path: &Path,
) -> Result<Cow<'static, str>, AnyError> {
) -> Result<Cow<'static, str>, JsErrorBox> {
// todo(dsherret): use the preloaded module from the graph if available?
let media_type = MediaType::from_path(path);
let text = self.sys.fs_read_to_string_lossy(path)?;
let text = self
.sys
.fs_read_to_string_lossy(path)
.map_err(JsErrorBox::from_err)?;
if media_type.is_emittable() {
let specifier = deno_path_util::url_from_file_path(path)?;
let specifier = deno_path_util::url_from_file_path(path)
.map_err(JsErrorBox::from_err)?;
if self.in_npm_pkg_checker.in_npm_package(&specifier) {
return Err(
NotSupportedKindInNpmError {
media_type,
specifier,
}
.into(),
);
return Err(JsErrorBox::from_err(NotSupportedKindInNpmError {
media_type,
specifier,
}));
}
self
.emitter
@ -1172,6 +1198,7 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
&text.into(),
)
.map(Cow::Owned)
.map_err(JsErrorBox::from_err)
} else {
Ok(text)
}

View file

@ -11,6 +11,7 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo;
use deno_npm::registry::NpmRegistryApi;
@ -322,6 +323,28 @@ impl std::fmt::Debug for ManagedCliNpmResolver {
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ResolvePkgFolderFromPkgIdError {
#[class(inherit)]
#[error("{0}")]
NpmPackageFsResolverPackageFolder(
#[from] resolvers::NpmPackageFsResolverPackageFolderError,
),
#[class(inherit)]
#[error("{0}")]
Io(#[from] std::io::Error),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ResolvePkgFolderFromDenoModuleError {
#[class(inherit)]
#[error("{0}")]
PackageNvNotFound(#[from] deno_npm::resolution::PackageNvNotFoundError),
#[class(inherit)]
#[error("{0}")]
ResolvePkgFolderFromPkgId(#[from] ResolvePkgFolderFromPkgIdError),
}
impl ManagedCliNpmResolver {
#[allow(clippy::too_many_arguments)]
pub fn new(
@ -356,7 +379,7 @@ impl ManagedCliNpmResolver {
pub fn resolve_pkg_folder_from_pkg_id(
&self,
pkg_id: &NpmPackageId,
) -> Result<PathBuf, AnyError> {
) -> Result<PathBuf, ResolvePkgFolderFromPkgIdError> {
let path = self.fs_resolver.package_folder(pkg_id)?;
let path = canonicalize_path_maybe_not_exists(&self.sys, &path)?;
log::debug!(
@ -423,7 +446,7 @@ impl ManagedCliNpmResolver {
pub async fn add_and_cache_package_reqs(
&self,
packages: &[PackageReq],
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
self
.add_package_reqs_raw(
packages,
@ -436,7 +459,7 @@ impl ManagedCliNpmResolver {
pub async fn add_package_reqs_no_cache(
&self,
packages: &[PackageReq],
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
self
.add_package_reqs_raw(packages, None)
.await
@ -447,7 +470,7 @@ impl ManagedCliNpmResolver {
&self,
packages: &[PackageReq],
caching: PackageCaching<'_>,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
self
.add_package_reqs_raw(packages, Some(caching))
.await
@ -517,7 +540,7 @@ impl ManagedCliNpmResolver {
pub async fn inject_synthetic_types_node_package(
&self,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
let reqs = &[PackageReq::from_str("@types/node").unwrap()];
// add and ensure this isn't added to the lockfile
self
@ -530,16 +553,16 @@ impl ManagedCliNpmResolver {
pub async fn cache_packages(
&self,
caching: PackageCaching<'_>,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
self.fs_resolver.cache_packages(caching).await
}
pub fn resolve_pkg_folder_from_deno_module(
&self,
nv: &PackageNv,
) -> Result<PathBuf, AnyError> {
) -> Result<PathBuf, ResolvePkgFolderFromDenoModuleError> {
let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(nv)?;
self.resolve_pkg_folder_from_pkg_id(&pkg_id)
Ok(self.resolve_pkg_folder_from_pkg_id(&pkg_id)?)
}
pub fn resolve_pkg_id_from_pkg_req(
@ -580,7 +603,7 @@ impl ManagedCliNpmResolver {
/// return value of `false` means that new packages were added to the NPM resolution.
pub async fn ensure_top_level_package_json_install(
&self,
) -> Result<bool, AnyError> {
) -> Result<bool, JsErrorBox> {
if !self.top_level_install_flag.raise() {
return Ok(true); // already did this
}
@ -687,12 +710,12 @@ impl CliNpmReqResolver for ManagedCliNpmResolver {
req: &PackageReq,
_referrer: &ModuleSpecifier,
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
let pkg_id = self
.resolve_pkg_id_from_pkg_req(req)
.map_err(|err| ResolvePkgFolderFromDenoReqError::Managed(err.into()))?;
let pkg_id = self.resolve_pkg_id_from_pkg_req(req).map_err(|err| {
ResolvePkgFolderFromDenoReqError::Managed(Box::new(err))
})?;
self
.resolve_pkg_folder_from_pkg_id(&pkg_id)
.map_err(ResolvePkgFolderFromDenoReqError::Managed)
.map_err(|err| ResolvePkgFolderFromDenoReqError::Managed(Box::new(err)))
}
}

View file

@ -6,6 +6,7 @@ use std::sync::Arc;
use capacity_builder::StringBuilder;
use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use deno_lockfile::NpmPackageDependencyLockfileInfo;
use deno_lockfile::NpmPackageLockfileInfo;
use deno_npm::registry::NpmRegistryApi;
@ -39,7 +40,7 @@ pub struct AddPkgReqsResult {
/// package requirements.
pub results: Vec<Result<PackageNv, NpmResolutionError>>,
/// The final result of resolving and caching all the package requirements.
pub dependencies_result: Result<(), AnyError>,
pub dependencies_result: Result<(), JsErrorBox>,
}
/// Handles updating and storing npm resolution in memory where the underlying
@ -106,7 +107,7 @@ impl NpmResolution {
*snapshot_lock.write() = snapshot;
Ok(())
}
Err(err) => Err(err.into()),
Err(err) => Err(JsErrorBox::from_err(err)),
},
}
}

View file

@ -8,13 +8,18 @@ use std::path::PathBuf;
use async_trait::async_trait;
use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use node_resolver::errors::PackageFolderResolveError;
use super::super::PackageCaching;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(generic)]
#[error("Package folder not found for '{0}'")]
pub struct NpmPackageFsResolverPackageFolderError(deno_semver::StackString);
/// Part of the resolution that interacts with the file system.
#[async_trait(?Send)]
pub trait NpmPackageFsResolver: Send + Sync {
@ -26,12 +31,9 @@ pub trait NpmPackageFsResolver: Send + Sync {
fn package_folder(
&self,
package_id: &NpmPackageId,
) -> Result<PathBuf, AnyError> {
) -> Result<PathBuf, NpmPackageFsResolverPackageFolderError> {
self.maybe_package_folder(package_id).ok_or_else(|| {
deno_core::anyhow::anyhow!(
"Package folder not found for '{}'",
package_id.as_serialized()
)
NpmPackageFsResolverPackageFolderError(package_id.as_serialized())
})
}
@ -44,10 +46,10 @@ pub trait NpmPackageFsResolver: Send + Sync {
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageCacheFolderId>, AnyError>;
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error>;
async fn cache_packages<'a>(
&self,
caching: PackageCaching<'a>,
) -> Result<(), AnyError>;
) -> Result<(), JsErrorBox>;
}

View file

@ -6,8 +6,6 @@ use std::collections::VecDeque;
use std::path::Path;
use std::path::PathBuf;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::NpmPackageId;
@ -50,6 +48,48 @@ pub fn warn_missing_entrypoint(
);
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum BinEntriesError {
#[class(inherit)]
#[error("Creating '{path}'")]
Creating {
path: PathBuf,
#[source]
#[inherit]
source: std::io::Error,
},
#[cfg(unix)]
#[class(inherit)]
#[error("Setting permissions on '{path}'")]
Permissions {
path: PathBuf,
#[source]
#[inherit]
source: std::io::Error,
},
#[class(inherit)]
#[error("Can't set up '{name}' bin at {path}")]
SetUpBin {
name: String,
path: PathBuf,
#[source]
#[inherit]
source: Box<Self>,
},
#[cfg(unix)]
#[class(inherit)]
#[error("Setting permissions on '{path}'")]
RemoveBinSymlink {
path: PathBuf,
#[source]
#[inherit]
source: std::io::Error,
},
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
}
impl<'a> BinEntries<'a> {
pub fn new() -> Self {
Self::default()
@ -92,15 +132,15 @@ impl<'a> BinEntries<'a> {
mut already_seen: impl FnMut(
&Path,
&str, // bin script
) -> Result<(), AnyError>,
) -> Result<(), BinEntriesError>,
mut new: impl FnMut(
&NpmResolutionPackage,
&Path,
&str, // bin name
&str, // bin script
) -> Result<(), AnyError>,
) -> Result<(), BinEntriesError>,
mut filter: impl FnMut(&NpmResolutionPackage) -> bool,
) -> Result<(), AnyError> {
) -> Result<(), BinEntriesError> {
if !self.collisions.is_empty() && !self.sorted {
// walking the dependency tree to find out the depth of each package
// is sort of expensive, so we only do it if there's a collision
@ -168,11 +208,14 @@ impl<'a> BinEntries<'a> {
bin_node_modules_dir_path: &Path,
filter: impl FnMut(&NpmResolutionPackage) -> bool,
mut handler: impl FnMut(&EntrySetupOutcome<'_>),
) -> Result<(), AnyError> {
) -> Result<(), BinEntriesError> {
if !self.entries.is_empty() && !bin_node_modules_dir_path.exists() {
std::fs::create_dir_all(bin_node_modules_dir_path).with_context(
|| format!("Creating '{}'", bin_node_modules_dir_path.display()),
)?;
std::fs::create_dir_all(bin_node_modules_dir_path).map_err(|source| {
BinEntriesError::Creating {
path: bin_node_modules_dir_path.to_path_buf(),
source,
}
})?;
}
self.for_each_entry(
@ -209,7 +252,7 @@ impl<'a> BinEntries<'a> {
snapshot: &NpmResolutionSnapshot,
bin_node_modules_dir_path: &Path,
handler: impl FnMut(&EntrySetupOutcome<'_>),
) -> Result<(), AnyError> {
) -> Result<(), BinEntriesError> {
self.set_up_entries_filtered(
snapshot,
bin_node_modules_dir_path,
@ -226,7 +269,7 @@ impl<'a> BinEntries<'a> {
bin_node_modules_dir_path: &Path,
handler: impl FnMut(&EntrySetupOutcome<'_>),
only: &HashSet<&NpmPackageId>,
) -> Result<(), AnyError> {
) -> Result<(), BinEntriesError> {
self.set_up_entries_filtered(
snapshot,
bin_node_modules_dir_path,
@ -301,7 +344,7 @@ pub fn set_up_bin_entry<'a>(
#[allow(unused_variables)] bin_script: &str,
#[allow(unused_variables)] package_path: &'a Path,
bin_node_modules_dir_path: &Path,
) -> Result<EntrySetupOutcome<'a>, AnyError> {
) -> Result<EntrySetupOutcome<'a>, BinEntriesError> {
#[cfg(windows)]
{
set_up_bin_shim(package, bin_name, bin_node_modules_dir_path)?;
@ -324,14 +367,16 @@ fn set_up_bin_shim(
package: &NpmResolutionPackage,
bin_name: &str,
bin_node_modules_dir_path: &Path,
) -> Result<(), AnyError> {
) -> Result<(), BinEntriesError> {
use std::fs;
let mut cmd_shim = bin_node_modules_dir_path.join(bin_name);
cmd_shim.set_extension("cmd");
let shim = format!("@deno run -A npm:{}/{bin_name} %*", package.id.nv);
fs::write(&cmd_shim, shim).with_context(|| {
format!("Can't set up '{}' bin at {}", bin_name, cmd_shim.display())
fs::write(&cmd_shim, shim).map_err(|err| BinEntriesError::SetUpBin {
name: bin_name.to_string(),
path: cmd_shim.clone(),
source: Box::new(err.into()),
})?;
Ok(())
@ -340,7 +385,7 @@ fn set_up_bin_shim(
#[cfg(unix)]
/// Make the file at `path` executable if it exists.
/// Returns `true` if the file exists, `false` otherwise.
fn make_executable_if_exists(path: &Path) -> Result<bool, AnyError> {
fn make_executable_if_exists(path: &Path) -> Result<bool, BinEntriesError> {
use std::io;
use std::os::unix::fs::PermissionsExt;
let mut perms = match std::fs::metadata(path) {
@ -355,8 +400,11 @@ fn make_executable_if_exists(path: &Path) -> Result<bool, AnyError> {
if perms.mode() & 0o111 == 0 {
// if the original file is not executable, make it executable
perms.set_mode(perms.mode() | 0o111);
std::fs::set_permissions(path, perms).with_context(|| {
format!("Setting permissions on '{}'", path.display())
std::fs::set_permissions(path, perms).map_err(|source| {
BinEntriesError::Permissions {
path: path.to_path_buf(),
source,
}
})?;
}
@ -395,14 +443,18 @@ fn symlink_bin_entry<'a>(
bin_script: &str,
package_path: &'a Path,
bin_node_modules_dir_path: &Path,
) -> Result<EntrySetupOutcome<'a>, AnyError> {
) -> Result<EntrySetupOutcome<'a>, BinEntriesError> {
use std::io;
use std::os::unix::fs::symlink;
let link = bin_node_modules_dir_path.join(bin_name);
let original = package_path.join(bin_script);
let found = make_executable_if_exists(&original).with_context(|| {
format!("Can't set up '{}' bin at {}", bin_name, original.display())
let found = make_executable_if_exists(&original).map_err(|source| {
BinEntriesError::SetUpBin {
name: bin_name.to_string(),
path: original.to_path_buf(),
source: Box::new(source),
}
})?;
if !found {
return Ok(EntrySetupOutcome::MissingEntrypoint {
@ -420,27 +472,25 @@ fn symlink_bin_entry<'a>(
if let Err(err) = symlink(&original_relative, &link) {
if err.kind() == io::ErrorKind::AlreadyExists {
// remove and retry
std::fs::remove_file(&link).with_context(|| {
format!(
"Failed to remove existing bin symlink at {}",
link.display()
)
std::fs::remove_file(&link).map_err(|source| {
BinEntriesError::RemoveBinSymlink {
path: link.clone(),
source,
}
})?;
symlink(&original_relative, &link).with_context(|| {
format!(
"Can't set up '{}' bin at {}",
bin_name,
original_relative.display()
)
symlink(&original_relative, &link).map_err(|source| {
BinEntriesError::SetUpBin {
name: bin_name.to_string(),
path: original_relative.to_path_buf(),
source: Box::new(source.into()),
}
})?;
return Ok(EntrySetupOutcome::Success);
}
return Err(err).with_context(|| {
format!(
"Can't set up '{}' bin at {}",
bin_name,
original_relative.display()
)
return Err(BinEntriesError::SetUpBin {
name: bin_name.to_string(),
path: original_relative.to_path_buf(),
source: Box::new(err.into()),
});
}

View file

@ -6,7 +6,6 @@ use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::NpmResolutionPackage;
@ -29,7 +28,7 @@ pub trait LifecycleScriptsStrategy {
fn warn_on_scripts_not_run(
&self,
packages: &[(&NpmResolutionPackage, PathBuf)],
) -> Result<(), AnyError>;
) -> Result<(), std::io::Error>;
fn has_warned(&self, package: &NpmResolutionPackage) -> bool;
@ -38,7 +37,7 @@ pub trait LifecycleScriptsStrategy {
fn did_run_scripts(
&self,
package: &NpmResolutionPackage,
) -> Result<(), AnyError>;
) -> Result<(), std::io::Error>;
}
pub struct LifecycleScripts<'a> {
@ -84,6 +83,27 @@ fn is_broken_default_install_script(script: &str, package_path: &Path) -> bool {
script == "node-gyp rebuild" && !package_path.join("binding.gyp").exists()
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LifecycleScriptsError {
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
#[class(inherit)]
#[error(transparent)]
BinEntries(#[from] super::bin_entries::BinEntriesError),
#[class(inherit)]
#[error(
"failed to create npm process state tempfile for running lifecycle scripts"
)]
CreateNpmProcessState(#[source] std::io::Error),
#[class(generic)]
#[error(transparent)]
Task(AnyError),
#[class(generic)]
#[error("failed to run scripts for packages: {}", .0.join(", "))]
RunScripts(Vec<String>),
}
impl<'a> LifecycleScripts<'a> {
pub fn can_run_scripts(&self, package_nv: &PackageNv) -> bool {
if !self.strategy.can_run_scripts() {
@ -141,7 +161,7 @@ impl<'a> LifecycleScripts<'a> {
}
}
pub fn warn_not_run_scripts(&self) -> Result<(), AnyError> {
pub fn warn_not_run_scripts(&self) -> Result<(), std::io::Error> {
if !self.packages_with_scripts_not_run.is_empty() {
self
.strategy
@ -156,7 +176,7 @@ impl<'a> LifecycleScripts<'a> {
packages: &[NpmResolutionPackage],
root_node_modules_dir_path: &Path,
progress_bar: &ProgressBar,
) -> Result<(), AnyError> {
) -> Result<(), LifecycleScriptsError> {
let kill_signal = KillSignal::default();
let _drop_signal = kill_signal.clone().drop_guard();
// we don't run with signals forwarded because once signals
@ -179,7 +199,7 @@ impl<'a> LifecycleScripts<'a> {
root_node_modules_dir_path: &Path,
progress_bar: &ProgressBar,
kill_signal: KillSignal,
) -> Result<(), AnyError> {
) -> Result<(), LifecycleScriptsError> {
self.warn_not_run_scripts()?;
let get_package_path =
|p: &NpmResolutionPackage| self.strategy.package_path(p);
@ -198,7 +218,7 @@ impl<'a> LifecycleScripts<'a> {
snapshot,
packages,
get_package_path,
)?;
);
let init_cwd = &self.config.initial_cwd;
let process_state = crate::npm::managed::npm_process_state(
snapshot.as_valid_serialized(),
@ -222,7 +242,8 @@ impl<'a> LifecycleScripts<'a> {
let temp_file_fd =
deno_runtime::ops::process::npm_process_state_tempfile(
process_state.as_bytes(),
).context("failed to create npm process state tempfile for running lifecycle scripts")?;
)
.map_err(LifecycleScriptsError::CreateNpmProcessState)?;
// SAFETY: fd/handle is valid
let _temp_file =
unsafe { std::fs::File::from_raw_io_handle(temp_file_fd) }; // make sure the file gets closed
@ -240,7 +261,7 @@ impl<'a> LifecycleScripts<'a> {
package,
snapshot,
get_package_path,
)?;
);
for script_name in ["preinstall", "install", "postinstall"] {
if let Some(script) = package.scripts.get(script_name) {
if script_name == "install"
@ -273,7 +294,8 @@ impl<'a> LifecycleScripts<'a> {
kill_signal: kill_signal.clone(),
},
)
.await?;
.await
.map_err(LifecycleScriptsError::Task)?;
let stdout = stdout.unwrap();
let stderr = stderr.unwrap();
if exit_code != 0 {
@ -322,14 +344,12 @@ impl<'a> LifecycleScripts<'a> {
if failed_packages.is_empty() {
Ok(())
} else {
Err(AnyError::msg(format!(
"failed to run scripts for packages: {}",
Err(LifecycleScriptsError::RunScripts(
failed_packages
.iter()
.map(|p| p.to_string())
.collect::<Vec<_>>()
.join(", ")
)))
.collect::<Vec<_>>(),
))
}
}
}
@ -349,7 +369,7 @@ fn resolve_baseline_custom_commands<'a>(
snapshot: &'a NpmResolutionSnapshot,
packages: &'a [NpmResolutionPackage],
get_package_path: impl Fn(&NpmResolutionPackage) -> PathBuf,
) -> Result<crate::task_runner::TaskCustomCommands, AnyError> {
) -> crate::task_runner::TaskCustomCommands {
let mut custom_commands = crate::task_runner::TaskCustomCommands::new();
custom_commands
.insert("npx".to_string(), Rc::new(crate::task_runner::NpxCommand));
@ -390,7 +410,7 @@ fn resolve_custom_commands_from_packages<
snapshot: &'a NpmResolutionSnapshot,
packages: P,
get_package_path: impl Fn(&'a NpmResolutionPackage) -> PathBuf,
) -> Result<crate::task_runner::TaskCustomCommands, AnyError> {
) -> crate::task_runner::TaskCustomCommands {
for package in packages {
let package_path = get_package_path(package);
@ -409,7 +429,7 @@ fn resolve_custom_commands_from_packages<
);
}
Ok(commands)
commands
}
// resolves the custom commands from the dependencies of a package
@ -420,7 +440,7 @@ fn resolve_custom_commands_from_deps(
package: &NpmResolutionPackage,
snapshot: &NpmResolutionSnapshot,
get_package_path: impl Fn(&NpmResolutionPackage) -> PathBuf,
) -> Result<crate::task_runner::TaskCustomCommands, AnyError> {
) -> crate::task_runner::TaskCustomCommands {
let mut bin_entries = BinEntries::new();
resolve_custom_commands_from_packages(
&mut bin_entries,

View file

@ -9,9 +9,9 @@ use std::sync::Arc;
use async_trait::async_trait;
use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::StreamExt;
use deno_error::JsErrorBox;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage;
@ -134,7 +134,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageCacheFolderId>, AnyError> {
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
Ok(
self
.cache
@ -145,7 +145,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
async fn cache_packages<'a>(
&self,
caching: PackageCaching<'a>,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
let package_partitions = match caching {
PackageCaching::All => self
.resolution
@ -155,13 +155,16 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
.subset(&reqs)
.all_system_packages_partitioned(&self.system_info),
};
cache_packages(&package_partitions.packages, &self.tarball_cache).await?;
cache_packages(&package_partitions.packages, &self.tarball_cache)
.await
.map_err(JsErrorBox::from_err)?;
// create the copy package folders
for copy in package_partitions.copy_packages {
self
.cache
.ensure_copy_package(&copy.get_package_cache_folder_id())?;
.ensure_copy_package(&copy.get_package_cache_folder_id())
.map_err(JsErrorBox::from_err)?;
}
let mut lifecycle_scripts =
@ -174,7 +177,9 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
lifecycle_scripts.add(package, Cow::Borrowed(&package_folder));
}
lifecycle_scripts.warn_not_run_scripts()?;
lifecycle_scripts
.warn_not_run_scripts()
.map_err(JsErrorBox::from_err)?;
Ok(())
}
@ -183,7 +188,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
async fn cache_packages(
packages: &[NpmResolutionPackage],
tarball_cache: &Arc<CliNpmTarballCache>,
) -> Result<(), AnyError> {
) -> Result<(), deno_npm_cache::EnsurePackageError> {
let mut futures_unordered = FuturesUnordered::new();
for package in packages {
futures_unordered.push(async move {
@ -235,7 +240,7 @@ impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy
fn warn_on_scripts_not_run(
&self,
packages: &[(&NpmResolutionPackage, PathBuf)],
) -> std::result::Result<(), deno_core::anyhow::Error> {
) -> std::result::Result<(), std::io::Error> {
log::warn!("{} The following packages contained npm lifecycle scripts ({}) that were not executed:", colors::yellow("Warning"), colors::gray("preinstall/install/postinstall"));
for (package, _) in packages {
log::warn!("┠─ {}", colors::gray(format!("npm:{}", package.id.nv)));
@ -261,7 +266,7 @@ impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy
fn did_run_scripts(
&self,
_package: &NpmResolutionPackage,
) -> std::result::Result<(), deno_core::anyhow::Error> {
) -> Result<(), std::io::Error> {
Ok(())
}

View file

@ -19,12 +19,11 @@ use std::sync::Arc;
use async_trait::async_trait;
use deno_ast::ModuleSpecifier;
use deno_cache_dir::npm::mixed_case_package_name_decode;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::StreamExt;
use deno_core::parking_lot::Mutex;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
@ -140,7 +139,7 @@ impl LocalNpmPackageResolver {
fn resolve_package_folder_from_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<PathBuf>, AnyError> {
) -> Result<Option<PathBuf>, std::io::Error> {
let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else {
return Ok(None);
};
@ -225,7 +224,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageCacheFolderId>, AnyError> {
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
let Some(folder_path) =
self.resolve_package_folder_from_specifier(specifier)?
else {
@ -251,7 +250,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
async fn cache_packages<'a>(
&self,
caching: PackageCaching<'a>,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
let snapshot = match caching {
PackageCaching::All => self.resolution.snapshot(),
PackageCaching::Only(reqs) => self.resolution.subset(&reqs),
@ -267,6 +266,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
&self.lifecycle_scripts,
)
.await
.map_err(JsErrorBox::from_err)
}
}
@ -285,6 +285,38 @@ fn local_node_modules_package_contents_path(
.join(&package.id.nv.name)
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum SyncResolutionWithFsError {
#[class(inherit)]
#[error("Creating '{path}'")]
Creating {
path: PathBuf,
#[source]
#[inherit]
source: std::io::Error,
},
#[class(inherit)]
#[error(transparent)]
CopyDirRecursive(#[from] crate::util::fs::CopyDirRecursiveError),
#[class(inherit)]
#[error(transparent)]
SymlinkPackageDir(#[from] SymlinkPackageDirError),
#[class(inherit)]
#[error(transparent)]
BinEntries(#[from] bin_entries::BinEntriesError),
#[class(inherit)]
#[error(transparent)]
LifecycleScripts(
#[from] super::common::lifecycle_scripts::LifecycleScriptsError,
),
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
/// Creates a pnpm style folder structure.
#[allow(clippy::too_many_arguments)]
async fn sync_resolution_with_fs(
@ -296,7 +328,7 @@ async fn sync_resolution_with_fs(
root_node_modules_dir_path: &Path,
system_info: &NpmSystemInfo,
lifecycle_scripts: &LifecycleScriptsConfig,
) -> Result<(), AnyError> {
) -> Result<(), SyncResolutionWithFsError> {
if snapshot.is_empty()
&& npm_install_deps_provider.workspace_pkgs().is_empty()
{
@ -311,12 +343,18 @@ async fn sync_resolution_with_fs(
let deno_local_registry_dir = root_node_modules_dir_path.join(".deno");
let deno_node_modules_dir = deno_local_registry_dir.join("node_modules");
fs::create_dir_all(&deno_node_modules_dir).with_context(|| {
format!("Creating '{}'", deno_local_registry_dir.display())
fs::create_dir_all(&deno_node_modules_dir).map_err(|source| {
SyncResolutionWithFsError::Creating {
path: deno_local_registry_dir.to_path_buf(),
source,
}
})?;
let bin_node_modules_dir_path = root_node_modules_dir_path.join(".bin");
fs::create_dir_all(&bin_node_modules_dir_path).with_context(|| {
format!("Creating '{}'", bin_node_modules_dir_path.display())
fs::create_dir_all(&bin_node_modules_dir_path).map_err(|source| {
SyncResolutionWithFsError::Creating {
path: deno_local_registry_dir.to_path_buf(),
source,
}
})?;
let single_process_lock = LaxSingleProcessFsFlag::lock(
@ -420,7 +458,8 @@ async fn sync_resolution_with_fs(
cache_futures.push(async move {
tarball_cache
.ensure_package(&package.id.nv, &package.dist)
.await?;
.await
.map_err(JsErrorBox::from_err)?;
let pb_guard = progress_bar.update_with_prompt(
ProgressMessagePrompt::Initialize,
&package.id.nv.to_string(),
@ -441,10 +480,12 @@ async fn sync_resolution_with_fs(
// write out a file that indicates this folder has been initialized
fs::write(initialized_file, tags)?;
Ok::<_, AnyError>(())
Ok::<_, SyncResolutionWithFsError>(())
}
})
.await??;
.await
.map_err(JsErrorBox::from_err)?
.map_err(JsErrorBox::from_err)?;
if package.bin.is_some() {
bin_entries_to_setup.borrow_mut().add(package, package_path);
@ -458,7 +499,7 @@ async fn sync_resolution_with_fs(
// finally stop showing the progress bar
drop(pb_guard); // explicit for clarity
Ok::<_, AnyError>(())
Ok::<_, JsErrorBox>(())
});
} else if matches!(package_state, PackageFolderState::TagsOutdated) {
fs::write(initialized_file, tags)?;
@ -597,8 +638,11 @@ async fn sync_resolution_with_fs(
// symlink the dep into the package's child node_modules folder
let dest_node_modules = remote.base_dir.join("node_modules");
if !existing_child_node_modules_dirs.contains(&dest_node_modules) {
fs::create_dir_all(&dest_node_modules).with_context(|| {
format!("Creating '{}'", dest_node_modules.display())
fs::create_dir_all(&dest_node_modules).map_err(|source| {
SyncResolutionWithFsError::Creating {
path: dest_node_modules.clone(),
source,
}
})?;
existing_child_node_modules_dirs.insert(dest_node_modules.clone());
}
@ -813,7 +857,7 @@ impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy
fn did_run_scripts(
&self,
package: &NpmResolutionPackage,
) -> std::result::Result<(), deno_core::anyhow::Error> {
) -> std::result::Result<(), std::io::Error> {
std::fs::write(self.ran_scripts_file(package), "")?;
Ok(())
}
@ -821,7 +865,7 @@ impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy
fn warn_on_scripts_not_run(
&self,
packages: &[(&NpmResolutionPackage, std::path::PathBuf)],
) -> Result<(), AnyError> {
) -> Result<(), std::io::Error> {
if !packages.is_empty() {
log::warn!("{} The following packages contained npm lifecycle scripts ({}) that were not executed:", colors::yellow("Warning"), colors::gray("preinstall/install/postinstall"));
@ -1041,15 +1085,42 @@ fn get_package_folder_id_from_folder_name(
})
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum SymlinkPackageDirError {
#[class(inherit)]
#[error("Creating '{parent}'")]
Creating {
parent: PathBuf,
#[source]
#[inherit]
source: std::io::Error,
},
#[class(inherit)]
#[error(transparent)]
Other(#[from] std::io::Error),
#[cfg(windows)]
#[class(inherit)]
#[error("Creating junction in node_modules folder")]
FailedCreatingJunction {
#[source]
#[inherit]
source: std::io::Error,
},
}
fn symlink_package_dir(
old_path: &Path,
new_path: &Path,
) -> Result<(), AnyError> {
) -> Result<(), SymlinkPackageDirError> {
let new_parent = new_path.parent().unwrap();
if new_parent.file_name().unwrap() != "node_modules" {
// create the parent folder that will contain the symlink
fs::create_dir_all(new_parent)
.with_context(|| format!("Creating '{}'", new_parent.display()))?;
fs::create_dir_all(new_parent).map_err(|source| {
SymlinkPackageDirError::Creating {
parent: new_parent.to_path_buf(),
source,
}
})?;
}
// need to delete the previous symlink before creating a new one
@ -1075,7 +1146,7 @@ fn junction_or_symlink_dir(
old_path_relative: &Path,
old_path: &Path,
new_path: &Path,
) -> Result<(), AnyError> {
) -> Result<(), SymlinkPackageDirError> {
static USE_JUNCTIONS: std::sync::atomic::AtomicBool =
std::sync::atomic::AtomicBool::new(false);
@ -1084,8 +1155,9 @@ fn junction_or_symlink_dir(
// needing to elevate privileges on Windows.
// Note: junctions don't support relative paths, so we need to use the
// absolute path here.
return junction::create(old_path, new_path)
.context("Failed creating junction in node_modules folder");
return junction::create(old_path, new_path).map_err(|source| {
SymlinkPackageDirError::FailedCreatingJunction { source }
});
}
match symlink_dir(&crate::sys::CliSys::default(), old_path_relative, new_path)
@ -1095,8 +1167,9 @@ fn junction_or_symlink_dir(
if symlink_err.kind() == std::io::ErrorKind::PermissionDenied =>
{
USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed);
junction::create(old_path, new_path)
.context("Failed creating junction in node_modules folder")
junction::create(old_path, new_path).map_err(|source| {
SymlinkPackageDirError::FailedCreatingJunction { source }
})
}
Err(symlink_err) => {
log::warn!(
@ -1104,8 +1177,9 @@ fn junction_or_symlink_dir(
colors::yellow("Warning")
);
USE_JUNCTIONS.store(true, std::sync::atomic::Ordering::Relaxed);
junction::create(old_path, new_path)
.context("Failed creating junction in node_modules folder")
junction::create(old_path, new_path).map_err(|source| {
SymlinkPackageDirError::FailedCreatingJunction { source }
})
}
}
}

View file

@ -10,6 +10,7 @@ use std::sync::Arc;
use deno_npm::NpmSystemInfo;
pub use self::common::NpmPackageFsResolver;
pub use self::common::NpmPackageFsResolverPackageFolderError;
use self::global::GlobalNpmPackageResolver;
use self::local::LocalNpmPackageResolver;
use super::resolution::NpmResolution;

View file

@ -33,6 +33,7 @@ pub use self::managed::CliManagedNpmResolverCreateOptions;
pub use self::managed::CliNpmResolverManagedSnapshotOption;
pub use self::managed::ManagedCliNpmResolver;
pub use self::managed::PackageCaching;
pub use self::managed::ResolvePkgFolderFromDenoModuleError;
pub use self::permission_checker::NpmRegistryReadPermissionChecker;
pub use self::permission_checker::NpmRegistryReadPermissionCheckerMode;
use crate::file_fetcher::CliFileFetcher;
@ -90,7 +91,9 @@ impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient {
| Json { .. }
| ToStr { .. }
| RedirectHeaderParse { .. }
| TooManyRedirects => None,
| TooManyRedirects
| NotFound
| Other(_) => None,
BadResponse(bad_response_error) => {
Some(bad_response_error.status_code)
}

View file

@ -6,9 +6,8 @@ use std::io::ErrorKind;
use std::path::Path;
use std::path::PathBuf;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_error::JsErrorBox;
use deno_runtime::deno_node::NodePermissions;
use sys_traits::FsCanonicalize;
@ -28,6 +27,16 @@ pub struct NpmRegistryReadPermissionChecker {
mode: NpmRegistryReadPermissionCheckerMode,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(inherit)]
#[error("failed canonicalizing '{path}'")]
struct EnsureRegistryReadPermissionError {
path: PathBuf,
#[source]
#[inherit]
source: std::io::Error,
}
impl NpmRegistryReadPermissionChecker {
pub fn new(sys: CliSys, mode: NpmRegistryReadPermissionCheckerMode) -> Self {
Self {
@ -42,7 +51,7 @@ impl NpmRegistryReadPermissionChecker {
&self,
permissions: &mut dyn NodePermissions,
path: &'a Path,
) -> Result<Cow<'a, Path>, AnyError> {
) -> Result<Cow<'a, Path>, JsErrorBox> {
if permissions.query_read_all() {
return Ok(Cow::Borrowed(path)); // skip permissions checks below
}
@ -52,7 +61,9 @@ impl NpmRegistryReadPermissionChecker {
if path.components().any(|c| c.as_os_str() == "node_modules") {
Ok(Cow::Borrowed(path))
} else {
permissions.check_read_path(path).map_err(Into::into)
permissions
.check_read_path(path)
.map_err(JsErrorBox::from_err)
}
}
NpmRegistryReadPermissionCheckerMode::Global(registry_path)
@ -66,7 +77,7 @@ impl NpmRegistryReadPermissionChecker {
if is_path_in_node_modules {
let mut cache = self.cache.lock();
let mut canonicalize =
|path: &Path| -> Result<Option<PathBuf>, AnyError> {
|path: &Path| -> Result<Option<PathBuf>, JsErrorBox> {
match cache.get(path) {
Some(canon) => Ok(Some(canon.clone())),
None => match self.sys.fs_canonicalize(path) {
@ -78,9 +89,12 @@ impl NpmRegistryReadPermissionChecker {
if e.kind() == ErrorKind::NotFound {
return Ok(None);
}
Err(AnyError::from(e)).with_context(|| {
format!("failed canonicalizing '{}'", path.display())
})
Err(JsErrorBox::from_err(
EnsureRegistryReadPermissionError {
path: path.to_path_buf(),
source: e,
},
))
}
},
}
@ -98,7 +112,9 @@ impl NpmRegistryReadPermissionChecker {
}
}
permissions.check_read_path(path).map_err(Into::into)
permissions
.check_read_path(path)
.map_err(JsErrorBox::from_err)
}
}
}

View file

@ -3,13 +3,11 @@
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::ChildPermissionsArg;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_web::StartTime;
@ -78,7 +76,7 @@ pub fn op_pledge_test_permissions(
pub fn op_restore_test_permissions(
state: &mut OpState,
#[serde] token: Uuid,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() {
if token != permissions_holder.0 {
panic!("restore test permissions token does not match the stored token");
@ -88,7 +86,7 @@ pub fn op_restore_test_permissions(
state.put::<PermissionsContainer>(permissions);
Ok(())
} else {
Err(generic_error("no permissions to restore"))
Err(JsErrorBox::generic("no permissions to restore"))
}
}
@ -106,9 +104,9 @@ fn op_register_bench(
only: bool,
warmup: bool,
#[buffer] ret_buf: &mut [u8],
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
if ret_buf.len() != 4 {
return Err(type_error(format!(
return Err(JsErrorBox::type_error(format!(
"Invalid ret_buf length: {}",
ret_buf.len()
)));

View file

@ -94,10 +94,12 @@ pub fn op_jupyter_input(
None
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum JupyterBroadcastError {
#[class(inherit)]
#[error(transparent)]
SerdeJson(serde_json::Error),
#[class(generic)]
#[error(transparent)]
ZeroMq(AnyError),
}

View file

@ -2,25 +2,36 @@
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_ast::ParseDiagnostic;
use deno_core::op2;
use crate::tools::lint;
deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LintError {
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
#[class(inherit)]
#[error(transparent)]
ParseDiagnostic(#[from] ParseDiagnostic),
#[class(type)]
#[error("Failed to parse path as URL: {0}")]
PathParse(std::path::PathBuf),
}
#[op2]
#[buffer]
fn op_lint_create_serialized_ast(
#[string] file_name: &str,
#[string] source: String,
) -> Result<Vec<u8>, AnyError> {
) -> Result<Vec<u8>, LintError> {
let file_text = deno_ast::strip_bom(source);
let path = std::env::current_dir()?.join(file_name);
let specifier = ModuleSpecifier::from_file_path(&path).map_err(|_| {
generic_error(format!("Failed to parse path as URL: {}", path.display()))
})?;
let specifier = ModuleSpecifier::from_file_path(&path)
.map_err(|_| LintError::PathParse(path))?;
let media_type = MediaType::from_specifier(&specifier);
let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
specifier,

View file

@ -3,13 +3,11 @@
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::ChildPermissionsArg;
use deno_runtime::deno_permissions::PermissionsContainer;
use uuid::Uuid;
@ -73,7 +71,7 @@ pub fn op_pledge_test_permissions(
pub fn op_restore_test_permissions(
state: &mut OpState,
#[serde] token: Uuid,
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() {
if token != permissions_holder.0 {
panic!("restore test permissions token does not match the stored token");
@ -83,7 +81,7 @@ pub fn op_restore_test_permissions(
state.put::<PermissionsContainer>(permissions);
Ok(())
} else {
Err(generic_error("no permissions to restore"))
Err(JsErrorBox::generic("no permissions to restore"))
}
}
@ -103,9 +101,9 @@ fn op_register_test(
#[smi] line_number: u32,
#[smi] column_number: u32,
#[buffer] ret_buf: &mut [u8],
) -> Result<(), AnyError> {
) -> Result<(), JsErrorBox> {
if ret_buf.len() != 4 {
return Err(type_error(format!(
return Err(JsErrorBox::type_error(format!(
"Invalid ret_buf length: {}",
ret_buf.len()
)));

View file

@ -11,12 +11,12 @@ use dashmap::DashSet;
use deno_ast::MediaType;
use deno_config::workspace::MappedResolutionDiagnostic;
use deno_config::workspace::MappedResolutionError;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_core::ModuleSourceCode;
use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::source::ResolveError;
use deno_graph::source::UnknownBuiltInNodeModuleError;
use deno_graph::NpmLoadError;
@ -61,7 +61,8 @@ pub struct ModuleCodeStringSource {
pub media_type: MediaType,
}
#[derive(Debug, Error)]
#[derive(Debug, Error, deno_error::JsError)]
#[class(type)]
#[error("{media_type} files are not supported in npm packages: {specifier}")]
pub struct NotSupportedKindInNpmError {
pub media_type: MediaType,
@ -225,10 +226,12 @@ impl CliResolver {
) => match mapped_resolution_error {
MappedResolutionError::Specifier(e) => ResolveError::Specifier(e),
// deno_graph checks specifically for an ImportMapError
MappedResolutionError::ImportMap(e) => ResolveError::Other(e.into()),
err => ResolveError::Other(err.into()),
MappedResolutionError::ImportMap(e) => ResolveError::ImportMap(e),
MappedResolutionError::Workspace(e) => {
ResolveError::Other(JsErrorBox::from_err(e))
}
},
err => ResolveError::Other(err.into()),
err => ResolveError::Other(JsErrorBox::from_err(err)),
})?;
if resolution.found_package_json_dep {
@ -356,26 +359,28 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> {
.map(|r| {
r.map_err(|err| match err {
NpmResolutionError::Registry(e) => {
NpmLoadError::RegistryInfo(Arc::new(e.into()))
NpmLoadError::RegistryInfo(Arc::new(e))
}
NpmResolutionError::Resolution(e) => {
NpmLoadError::PackageReqResolution(Arc::new(e.into()))
NpmLoadError::PackageReqResolution(Arc::new(e))
}
NpmResolutionError::DependencyEntry(e) => {
NpmLoadError::PackageReqResolution(Arc::new(e.into()))
NpmLoadError::PackageReqResolution(Arc::new(e))
}
})
})
.collect(),
dep_graph_result: match top_level_result {
Ok(()) => result.dependencies_result.map_err(Arc::new),
Ok(()) => result
.dependencies_result
.map_err(|e| Arc::new(e) as Arc<dyn deno_error::JsErrorClass>),
Err(err) => Err(Arc::new(err)),
},
}
}
None => {
let err = Arc::new(anyhow!(
"npm specifiers were requested; but --no-npm is specified"
let err = Arc::new(JsErrorBox::generic(
"npm specifiers were requested; but --no-npm is specified",
));
NpmResolvePkgReqsResult {
results: package_reqs

View file

@ -21,9 +21,8 @@ use deno_config::workspace::MappedResolutionError;
use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_config::workspace::WorkspaceResolver;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::future::LocalBoxFuture;
use deno_core::futures::FutureExt;
use deno_core::v8_set_flags;
@ -36,6 +35,7 @@ use deno_core::ModuleType;
use deno_core::RequestedModuleType;
use deno_core::ResolutionKind;
use deno_core::SourceCodeCacheInfo;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_package_json::PackageJsonDepValue;
use deno_resolver::cjs::IsCjsResolutionMode;
@ -182,25 +182,32 @@ impl ModuleLoader for EmbeddedModuleLoader {
raw_specifier: &str,
referrer: &str,
kind: ResolutionKind,
) -> Result<ModuleSpecifier, AnyError> {
) -> Result<ModuleSpecifier, ModuleLoaderError> {
let referrer = if referrer == "." {
if kind != ResolutionKind::MainModule {
return Err(generic_error(format!(
"Expected to resolve main module, got {:?} instead.",
kind
)));
return Err(
JsErrorBox::generic(format!(
"Expected to resolve main module, got {:?} instead.",
kind
))
.into(),
);
}
let current_dir = std::env::current_dir().unwrap();
deno_core::resolve_path(".", &current_dir)?
} else {
ModuleSpecifier::parse(referrer).map_err(|err| {
type_error(format!("Referrer uses invalid specifier: {}", err))
JsErrorBox::type_error(format!(
"Referrer uses invalid specifier: {}",
err
))
})?
};
let referrer_kind = if self
.shared
.cjs_tracker
.is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer))?
.is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer))
.map_err(JsErrorBox::from_err)?
{
ResolutionMode::Require
} else {
@ -217,7 +224,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
&referrer,
referrer_kind,
NodeResolutionKind::Execution,
)?
)
.map_err(JsErrorBox::from_err)?
.into_url(),
);
}
@ -245,14 +253,18 @@ impl ModuleLoader for EmbeddedModuleLoader {
Some(&referrer),
referrer_kind,
NodeResolutionKind::Execution,
)?,
)
.map_err(JsErrorBox::from_err)?,
),
Ok(MappedResolution::PackageJson {
dep_result,
sub_path,
alias,
..
}) => match dep_result.as_ref().map_err(|e| AnyError::from(e.clone()))? {
}) => match dep_result
.as_ref()
.map_err(|e| JsErrorBox::from_err(e.clone()))?
{
PackageJsonDepValue::Req(req) => self
.shared
.npm_req_resolver
@ -263,7 +275,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
referrer_kind,
NodeResolutionKind::Execution,
)
.map_err(AnyError::from),
.map_err(|e| JsErrorBox::from_err(e).into()),
PackageJsonDepValue::Workspace(version_req) => {
let pkg_folder = self
.shared
@ -271,7 +283,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
.resolve_workspace_pkg_json_folder_for_pkg_json_dep(
alias,
version_req,
)?;
)
.map_err(JsErrorBox::from_err)?;
Ok(
self
.shared
@ -282,7 +295,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
Some(&referrer),
referrer_kind,
NodeResolutionKind::Execution,
)?,
)
.map_err(JsErrorBox::from_err)?,
)
}
},
@ -291,12 +305,18 @@ impl ModuleLoader for EmbeddedModuleLoader {
if let Ok(reference) =
NpmPackageReqReference::from_specifier(&specifier)
{
return Ok(self.shared.npm_req_resolver.resolve_req_reference(
&reference,
&referrer,
referrer_kind,
NodeResolutionKind::Execution,
)?);
return Ok(
self
.shared
.npm_req_resolver
.resolve_req_reference(
&reference,
&referrer,
referrer_kind,
NodeResolutionKind::Execution,
)
.map_err(JsErrorBox::from_err)?,
);
}
if specifier.scheme() == "jsr" {
@ -318,18 +338,22 @@ impl ModuleLoader for EmbeddedModuleLoader {
Err(err)
if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" =>
{
let maybe_res = self.shared.npm_req_resolver.resolve_if_for_npm_pkg(
raw_specifier,
&referrer,
referrer_kind,
NodeResolutionKind::Execution,
)?;
let maybe_res = self
.shared
.npm_req_resolver
.resolve_if_for_npm_pkg(
raw_specifier,
&referrer,
referrer_kind,
NodeResolutionKind::Execution,
)
.map_err(JsErrorBox::from_err)?;
if let Some(res) = maybe_res {
return Ok(res.into_url());
}
Err(err.into())
Err(JsErrorBox::from_err(err).into())
}
Err(err) => Err(err.into()),
Err(err) => Err(JsErrorBox::from_err(err).into()),
}
}
@ -360,9 +384,9 @@ impl ModuleLoader for EmbeddedModuleLoader {
{
Ok(response) => response,
Err(err) => {
return deno_core::ModuleLoadResponse::Sync(Err(type_error(
format!("{:#}", err),
)));
return deno_core::ModuleLoadResponse::Sync(Err(
JsErrorBox::type_error(format!("{:#}", err)).into(),
));
}
};
return deno_core::ModuleLoadResponse::Sync(Ok(
@ -420,9 +444,9 @@ impl ModuleLoader for EmbeddedModuleLoader {
{
Ok(is_maybe_cjs) => is_maybe_cjs,
Err(err) => {
return deno_core::ModuleLoadResponse::Sync(Err(type_error(
format!("{:?}", err),
)));
return deno_core::ModuleLoadResponse::Sync(Err(
JsErrorBox::type_error(format!("{:?}", err)).into(),
));
}
};
if is_maybe_cjs {
@ -482,12 +506,16 @@ impl ModuleLoader for EmbeddedModuleLoader {
))
}
}
Ok(None) => deno_core::ModuleLoadResponse::Sync(Err(type_error(
format!("{MODULE_NOT_FOUND}: {}", original_specifier),
))),
Err(err) => deno_core::ModuleLoadResponse::Sync(Err(type_error(
format!("{:?}", err),
))),
Ok(None) => deno_core::ModuleLoadResponse::Sync(Err(
JsErrorBox::type_error(format!(
"{MODULE_NOT_FOUND}: {}",
original_specifier
))
.into(),
)),
Err(err) => deno_core::ModuleLoadResponse::Sync(Err(
JsErrorBox::type_error(format!("{:?}", err)).into(),
)),
}
}
@ -553,7 +581,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
&self,
permissions: &mut dyn deno_runtime::deno_node::NodePermissions,
path: &'a std::path::Path,
) -> Result<Cow<'a, std::path::Path>, AnyError> {
) -> Result<Cow<'a, std::path::Path>, JsErrorBox> {
if self.shared.modules.has_file(path) {
// allow reading if the file is in the snapshot
return Ok(Cow::Borrowed(path));
@ -563,17 +591,23 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
.shared
.npm_registry_permission_checker
.ensure_read_permission(permissions, path)
.map_err(JsErrorBox::from_err)
}
fn load_text_file_lossy(
&self,
path: &std::path::Path,
) -> Result<Cow<'static, str>, AnyError> {
let file_entry = self.shared.vfs.file_entry(path)?;
) -> Result<Cow<'static, str>, JsErrorBox> {
let file_entry = self
.shared
.vfs
.file_entry(path)
.map_err(JsErrorBox::from_err)?;
let file_bytes = self
.shared
.vfs
.read_file_all(file_entry, VfsFileSubDataKind::ModuleGraph)?;
.read_file_all(file_entry, VfsFileSubDataKind::ModuleGraph)
.map_err(JsErrorBox::from_err)?;
Ok(from_utf8_lossy_cow(file_bytes))
}
@ -626,10 +660,10 @@ struct StandaloneRootCertStoreProvider {
}
impl RootCertStoreProvider for StandaloneRootCertStoreProvider {
fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> {
fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox> {
self.cell.get_or_try_init(|| {
get_root_cert_store(None, self.ca_stores.clone(), self.ca_data.clone())
.map_err(|err| err.into())
.map_err(JsErrorBox::from_err)
})
}
}

View file

@ -6,8 +6,9 @@ use std::sync::Arc;
use std::time::Duration;
use deno_config::glob::WalkEntry;
use deno_core::error::generic_error;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::error::JsError;
use deno_core::futures::future;
use deno_core::futures::stream;
@ -18,6 +19,7 @@ use deno_core::unsync::spawn_blocking;
use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::PollEventLoopOptions;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
@ -162,17 +164,14 @@ async fn bench_specifier(
.await
{
Ok(()) => Ok(()),
Err(error) => {
if error.is::<JsError>() {
sender.send(BenchEvent::UncaughtError(
specifier.to_string(),
Box::new(error.downcast::<JsError>().unwrap()),
))?;
Ok(())
} else {
Err(error)
}
Err(CoreError::Js(error)) => {
sender.send(BenchEvent::UncaughtError(
specifier.to_string(),
Box::new(error),
))?;
Ok(())
}
Err(e) => Err(e.into()),
}
}
@ -183,7 +182,7 @@ async fn bench_specifier_inner(
specifier: ModuleSpecifier,
sender: &UnboundedSender<BenchEvent>,
filter: TestFilter,
) -> Result<(), AnyError> {
) -> Result<(), CoreError> {
let mut worker = worker_factory
.create_custom_worker(
WorkerExecutionMode::Bench,
@ -230,14 +229,18 @@ async fn bench_specifier_inner(
.partial_cmp(&groups.get_index_of(&d2.group).unwrap())
.unwrap()
});
sender.send(BenchEvent::Plan(BenchPlan {
origin: specifier.to_string(),
total: benchmarks.len(),
used_only,
names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(),
}))?;
sender
.send(BenchEvent::Plan(BenchPlan {
origin: specifier.to_string(),
total: benchmarks.len(),
used_only,
names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(),
}))
.map_err(JsErrorBox::from_err)?;
for (desc, function) in benchmarks {
sender.send(BenchEvent::Wait(desc.id))?;
sender
.send(BenchEvent::Wait(desc.id))
.map_err(JsErrorBox::from_err)?;
let call = worker.js_runtime.call(&function);
let result = worker
.js_runtime
@ -245,8 +248,11 @@ async fn bench_specifier_inner(
.await?;
let scope = &mut worker.js_runtime.handle_scope();
let result = v8::Local::new(scope, result);
let result = serde_v8::from_v8::<BenchResult>(scope, result)?;
sender.send(BenchEvent::Result(desc.id, result))?;
let result = serde_v8::from_v8::<BenchResult>(scope, result)
.map_err(JsErrorBox::from_err)?;
sender
.send(BenchEvent::Result(desc.id, result))
.map_err(JsErrorBox::from_err)?;
}
// Ignore `defaultPrevented` of the `beforeunload` event. We don't allow the
@ -356,13 +362,13 @@ async fn bench_specifiers(
reporter.report_end(&report);
if used_only {
return Err(generic_error(
return Err(anyhow!(
"Bench failed because the \"only\" option was used",
));
}
if report.failed > 0 {
return Err(generic_error("Bench failed"));
return Err(anyhow!("Bench failed"));
}
Ok(())
@ -440,7 +446,7 @@ pub async fn run_benchmarks(
.collect::<Vec<_>>();
if specifiers.is_empty() {
return Err(generic_error("No bench modules found"));
return Err(anyhow!("No bench modules found"));
}
let main_graph_container = factory.main_module_graph_container().await?;

View file

@ -6,7 +6,9 @@ use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_config::deno_json;
use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use deno_graph::Module;
use deno_graph::ModuleError;
use deno_graph::ModuleGraph;
@ -112,6 +114,27 @@ pub struct TypeChecker {
sys: CliSys,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CheckError {
#[class(inherit)]
#[error(transparent)]
Diagnostics(#[from] Diagnostics),
#[class(inherit)]
#[error(transparent)]
ConfigFile(#[from] deno_json::ConfigFileError),
#[class(inherit)]
#[error(transparent)]
ToMaybeJsxImportSourceConfig(
#[from] deno_json::ToMaybeJsxImportSourceConfigError,
),
#[class(inherit)]
#[error(transparent)]
TscExec(#[from] tsc::ExecError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
impl TypeChecker {
pub fn new(
caches: Arc<Caches>,
@ -141,7 +164,7 @@ impl TypeChecker {
&self,
graph: ModuleGraph,
options: CheckOptions,
) -> Result<Arc<ModuleGraph>, AnyError> {
) -> Result<Arc<ModuleGraph>, CheckError> {
let (graph, mut diagnostics) =
self.check_diagnostics(graph, options).await?;
diagnostics.emit_warnings();
@ -160,7 +183,7 @@ impl TypeChecker {
&self,
mut graph: ModuleGraph,
options: CheckOptions,
) -> Result<(Arc<ModuleGraph>, Diagnostics), AnyError> {
) -> Result<(Arc<ModuleGraph>, Diagnostics), CheckError> {
if !options.type_check_mode.is_true() || graph.roots.is_empty() {
return Ok((graph.into(), Default::default()));
}

View file

@ -8,9 +8,9 @@ use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::resolve_url_or_path;
use deno_graph::GraphKind;
@ -330,7 +330,7 @@ async fn resolve_compile_executable_output_path(
.map(PathBuf::from)
}
output_path.ok_or_else(|| generic_error(
output_path.ok_or_else(|| anyhow!(
"An executable name was not provided. One could not be inferred from the URL. Aborting.",
)).map(|output_path| {
get_os_specific_filepath(output_path, &compile_flags.target)

View file

@ -17,7 +17,6 @@ use deno_config::glob::PathOrPattern;
use deno_config::glob::PathOrPatternSet;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::sourcemap::SourceMap;
@ -430,7 +429,7 @@ fn collect_coverages(
.ignore_git_folder()
.ignore_node_modules()
.set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned))
.collect_file_patterns(&CliSys::default(), file_patterns)?;
.collect_file_patterns(&CliSys::default(), file_patterns);
let coverage_patterns = FilePatterns {
base: initial_cwd.to_path_buf(),
@ -505,7 +504,7 @@ pub fn cover_files(
coverage_flags: CoverageFlags,
) -> Result<(), AnyError> {
if coverage_flags.files.include.is_empty() {
return Err(generic_error("No matching coverage profiles found"));
return Err(anyhow!("No matching coverage profiles found"));
}
let factory = CliFactory::from_flags(flags);
@ -527,7 +526,7 @@ pub fn cover_files(
cli_options.initial_cwd(),
)?;
if script_coverages.is_empty() {
return Err(generic_error("No coverage files found"));
return Err(anyhow!("No coverage files found"));
}
let script_coverages = filter_coverages(
script_coverages,
@ -536,7 +535,7 @@ pub fn cover_files(
in_npm_pkg_checker.as_ref(),
);
if script_coverages.is_empty() {
return Err(generic_error("No covered files included in the report"));
return Err(anyhow!("No covered files included in the report"));
}
let proc_coverages: Vec<_> = script_coverages

View file

@ -62,10 +62,11 @@ async fn generate_doc_nodes_for_builtin_types(
)],
Vec::new(),
);
let roots = vec![source_file_specifier.clone()];
let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly);
graph
.build(
vec![source_file_specifier.clone()],
roots.clone(),
&loader,
deno_graph::BuildOptions {
imports: Vec::new(),
@ -85,14 +86,13 @@ async fn generate_doc_nodes_for_builtin_types(
let doc_parser = doc::DocParser::new(
&graph,
parser,
&roots,
doc::DocParserOptions {
diagnostics: false,
private: doc_flags.private,
},
)?;
let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions;
Ok(IndexMap::from([(source_file_specifier, nodes)]))
Ok(doc_parser.parse()?)
}
pub async fn doc(
@ -158,19 +158,13 @@ pub async fn doc(
let doc_parser = doc::DocParser::new(
&graph,
&capturing_parser,
&module_specifiers,
doc::DocParserOptions {
private: doc_flags.private,
diagnostics: doc_flags.lint,
},
)?;
let mut doc_nodes_by_url =
IndexMap::with_capacity(module_specifiers.len());
for module_specifier in module_specifiers {
let nodes = doc_parser.parse_with_reexports(&module_specifier)?;
doc_nodes_by_url.insert(module_specifier, nodes);
}
let doc_nodes_by_url = doc_parser.parse()?;
if doc_flags.lint {
let diagnostics = doc_parser.take_diagnostics();
@ -191,29 +185,9 @@ pub async fn doc(
.await?;
let (_, deno_ns) = deno_ns.into_iter().next().unwrap();
let short_path = Rc::new(ShortPath::new(
ModuleSpecifier::parse("file:///lib.deno.d.ts").unwrap(),
None,
None,
None,
));
deno_doc::html::compute_namespaced_symbols(
&deno_ns
.into_iter()
.map(|node| deno_doc::html::DocNodeWithContext {
origin: short_path.clone(),
ns_qualifiers: Rc::new([]),
kind_with_drilldown:
deno_doc::html::DocNodeKindWithDrilldown::Other(node.kind()),
inner: Rc::new(node),
drilldown_name: None,
parent: None,
})
.collect::<Vec<_>>(),
)
Some(deno_ns)
} else {
Default::default()
None
};
let mut main_entrypoint = None;
@ -393,7 +367,7 @@ impl UsageComposer for DocComposer {
fn generate_docs_directory(
doc_nodes_by_url: IndexMap<ModuleSpecifier, Vec<doc::DocNode>>,
html_options: &DocHtmlFlag,
deno_ns: std::collections::HashMap<Vec<String>, Option<Rc<ShortPath>>>,
built_in_types: Option<Vec<doc::DocNode>>,
rewrite_map: Option<IndexMap<ModuleSpecifier, String>>,
main_entrypoint: Option<ModuleSpecifier>,
) -> Result<(), AnyError> {
@ -426,12 +400,12 @@ fn generate_docs_directory(
None
};
let options = deno_doc::html::GenerateOptions {
let mut options = deno_doc::html::GenerateOptions {
package_name: html_options.name.clone(),
main_entrypoint,
rewrite_map,
href_resolver: Rc::new(DocResolver {
deno_ns,
deno_ns: Default::default(),
strip_trailing_html: html_options.strip_trailing_html,
}),
usage_composer: Rc::new(DocComposer),
@ -451,7 +425,58 @@ fn generate_docs_directory(
})),
};
let mut files = deno_doc::html::generate(options, doc_nodes_by_url)
if let Some(built_in_types) = built_in_types {
let ctx = deno_doc::html::GenerateCtx::create_basic(
deno_doc::html::GenerateOptions {
package_name: None,
main_entrypoint: Some(
ModuleSpecifier::parse("file:///lib.deno.d.ts").unwrap(),
),
href_resolver: Rc::new(DocResolver {
deno_ns: Default::default(),
strip_trailing_html: false,
}),
usage_composer: Rc::new(DocComposer),
rewrite_map: Default::default(),
category_docs: Default::default(),
disable_search: Default::default(),
symbol_redirect_map: Default::default(),
default_symbol_map: Default::default(),
markdown_renderer: deno_doc::html::comrak::create_renderer(
None, None, None,
),
markdown_stripper: Rc::new(deno_doc::html::comrak::strip),
head_inject: None,
},
IndexMap::from([(
ModuleSpecifier::parse("file:///lib.deno.d.ts").unwrap(),
built_in_types,
)]),
)?;
let deno_ns = deno_doc::html::compute_namespaced_symbols(
&ctx,
Box::new(
ctx
.doc_nodes
.values()
.next()
.unwrap()
.iter()
.map(std::borrow::Cow::Borrowed),
),
);
options.href_resolver = Rc::new(DocResolver {
deno_ns,
strip_trailing_html: html_options.strip_trailing_html,
});
}
let ctx =
deno_doc::html::GenerateCtx::create_basic(options, doc_nodes_by_url)?;
let mut files = deno_doc::html::generate(ctx)
.context("Failed to generate HTML documentation")?;
files.insert("prism.js".to_string(), PRISM_JS.to_string());

View file

@ -26,7 +26,6 @@ use deno_config::glob::FilePatterns;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::parking_lot::Mutex;
@ -167,7 +166,7 @@ fn resolve_paths_with_options_batches(
Vec::with_capacity(members_fmt_options.len());
for (_ctx, member_fmt_options) in members_fmt_options {
let files =
collect_fmt_files(cli_options, member_fmt_options.files.clone())?;
collect_fmt_files(cli_options, member_fmt_options.files.clone());
if !files.is_empty() {
paths_with_options_batches.push(PathsWithOptions {
base: member_fmt_options.files.base.clone(),
@ -177,7 +176,7 @@ fn resolve_paths_with_options_batches(
}
}
if paths_with_options_batches.is_empty() {
return Err(generic_error("No target files found."));
return Err(anyhow!("No target files found."));
}
Ok(paths_with_options_batches)
}
@ -224,7 +223,7 @@ async fn format_files(
fn collect_fmt_files(
cli_options: &CliOptions,
files: FilePatterns,
) -> Result<Vec<PathBuf>, AnyError> {
) -> Vec<PathBuf> {
FileCollector::new(|e| {
is_supported_ext_fmt(e.path)
|| (e.path.extension().is_none() && cli_options.ext_flag().is_some())
@ -484,7 +483,7 @@ pub fn format_html(
}
if let Some(error_msg) = inner(&error, file_path) {
AnyError::from(generic_error(error_msg))
AnyError::msg(error_msg)
} else {
AnyError::from(error)
}
@ -732,9 +731,9 @@ impl Formatter for CheckFormatter {
Ok(())
} else {
let not_formatted_files_str = files_str(not_formatted_files_count);
Err(generic_error(format!(
Err(anyhow!(
"Found {not_formatted_files_count} not formatted {not_formatted_files_str} in {checked_files_str}",
)))
))
}
}
}

View file

@ -11,6 +11,7 @@ use deno_core::error::AnyError;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::url;
use deno_error::JsErrorClass;
use deno_graph::Dependency;
use deno_graph::GraphKind;
use deno_graph::Module;
@ -664,9 +665,10 @@ impl<'a> GraphDisplayContext<'a> {
HttpsChecksumIntegrity(_) => "(checksum integrity error)",
Decode(_) => "(loading decode error)",
Loader(err) => {
match deno_runtime::errors::get_error_class_name(err) {
Some("NotCapable") => "(not capable, requires --allow-import)",
_ => "(loading error)",
if err.get_class() == "NotCapable" {
"(not capable, requires --allow-import)"
} else {
"(loading error)"
}
}
Jsr(_) => "(loading error)",

View file

@ -12,9 +12,9 @@ use std::path::PathBuf;
use std::sync::Arc;
use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::resolve_url_or_path;
use deno_core::url::Url;
@ -54,9 +54,7 @@ fn validate_name(exec_name: &str) -> Result<(), AnyError> {
if EXEC_NAME_RE.is_match(exec_name) {
Ok(())
} else {
Err(generic_error(format!(
"Invalid executable name: {exec_name}"
)))
Err(anyhow!("Invalid executable name: {exec_name}"))
}
}
@ -223,7 +221,7 @@ pub async fn uninstall(
// ensure directory exists
if let Ok(metadata) = fs::metadata(&installation_dir) {
if !metadata.is_dir() {
return Err(generic_error("Installation path is not a directory"));
return Err(anyhow!("Installation path is not a directory"));
}
}
@ -247,10 +245,10 @@ pub async fn uninstall(
}
if !removed {
return Err(generic_error(format!(
return Err(anyhow!(
"No installation found for {}",
uninstall_flags.name
)));
));
}
// There might be some extra files to delete
@ -423,14 +421,14 @@ async fn create_install_shim(
// ensure directory exists
if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) {
if !metadata.is_dir() {
return Err(generic_error("Installation path is not a directory"));
return Err(anyhow!("Installation path is not a directory"));
}
} else {
fs::create_dir_all(&shim_data.installation_dir)?;
};
if shim_data.file_path.exists() && !install_flags_global.force {
return Err(generic_error(
return Err(anyhow!(
"Existing installation found. Aborting (Use -f to overwrite).",
));
};
@ -492,7 +490,7 @@ async fn resolve_shim_data(
let name = match name {
Some(name) => name,
None => return Err(generic_error(
None => return Err(anyhow!(
"An executable name was not provided. One could not be inferred from the URL. Aborting.",
)),
};
@ -524,9 +522,7 @@ async fn resolve_shim_data(
let log_level = match log_level {
Level::Debug => "debug",
Level::Info => "info",
_ => {
return Err(generic_error(format!("invalid log level {log_level}")))
}
_ => return Err(anyhow!(format!("invalid log level {log_level}"))),
};
executable_args.push(log_level.to_string());
}

View file

@ -2,9 +2,9 @@
use std::sync::Arc;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures::FutureExt;
use deno_core::located_script_name;
@ -137,10 +137,10 @@ pub async fn kernel(
}
let cwd_url =
Url::from_directory_path(cli_options.initial_cwd()).map_err(|_| {
generic_error(format!(
anyhow!(
"Unable to construct URL from the path of cwd: {}",
cli_options.initial_cwd().to_string_lossy(),
))
)
})?;
repl_session.set_test_reporter_factory(Box::new(move || {
Box::new(

View file

@ -18,7 +18,6 @@ use deno_config::glob::FileCollector;
use deno_config::glob::FilePatterns;
use deno_config::workspace::WorkspaceDirectory;
use deno_core::anyhow::anyhow;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures::future::LocalBoxFuture;
use deno_core::futures::FutureExt;
@ -77,9 +76,7 @@ pub async fn lint(
) -> Result<(), AnyError> {
if lint_flags.watch.is_some() {
if lint_flags.is_stdin() {
return Err(generic_error(
"Lint watch on standard input is not supported.",
));
return Err(anyhow!("Lint watch on standard input is not supported.",));
}
return lint_with_watch(flags, lint_flags).await;
@ -223,7 +220,7 @@ fn resolve_paths_with_options_batches(
let mut paths_with_options_batches =
Vec::with_capacity(members_lint_options.len());
for (dir, lint_options) in members_lint_options {
let files = collect_lint_files(cli_options, lint_options.files.clone())?;
let files = collect_lint_files(cli_options, lint_options.files.clone());
if !files.is_empty() {
paths_with_options_batches.push(PathsWithOptions {
dir,
@ -233,7 +230,7 @@ fn resolve_paths_with_options_batches(
}
}
if paths_with_options_batches.is_empty() {
return Err(generic_error("No target files found."));
return Err(anyhow!("No target files found."));
}
Ok(paths_with_options_batches)
}
@ -446,7 +443,7 @@ impl WorkspaceLinter {
fn collect_lint_files(
cli_options: &CliOptions,
files: FilePatterns,
) -> Result<Vec<PathBuf>, AnyError> {
) -> Vec<PathBuf> {
FileCollector::new(|e| {
is_script_ext(e.path)
|| (e.path.extension().is_none() && cli_options.ext_flag().is_some())
@ -534,7 +531,7 @@ fn lint_stdin(
}
let mut source_code = String::new();
if stdin().read_to_string(&mut source_code).is_err() {
return Err(generic_error("Failed to read from stdin"));
return Err(anyhow!("Failed to read from stdin"));
}
let linter = CliLinter::new(CliLinterOptions {

View file

@ -7,7 +7,7 @@ use std::sync::Arc;
use deno_ast::SourceRange;
use deno_config::workspace::WorkspaceResolver;
use deno_core::anyhow::anyhow;
use deno_error::JsErrorBox;
use deno_graph::source::ResolutionKind;
use deno_graph::source::ResolveError;
use deno_graph::Range;
@ -187,7 +187,7 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> {
let resolution = self
.workspace_resolver
.resolve(specifier_text, &referrer_range.specifier)
.map_err(|err| ResolveError::Other(err.into()))?;
.map_err(|err| ResolveError::Other(JsErrorBox::from_err(err)))?;
match resolution {
deno_config::workspace::MappedResolution::Normal {
@ -220,7 +220,7 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> {
}
| deno_config::workspace::MappedResolution::PackageJson { .. } => {
// this error is ignored
Err(ResolveError::Other(anyhow!("")))
Err(ResolveError::Other(JsErrorBox::generic("")))
}
}
}

View file

@ -233,7 +233,7 @@ pub fn collect_publish_paths(
) -> Result<Vec<CollectedPublishPath>, AnyError> {
let diagnostics_collector = opts.diagnostics_collector;
let publish_paths =
collect_paths(opts.cli_options, diagnostics_collector, opts.file_patterns)?;
collect_paths(opts.cli_options, diagnostics_collector, opts.file_patterns);
let publish_paths_set = publish_paths.iter().cloned().collect::<HashSet<_>>();
let capacity = publish_paths.len() + opts.force_include_paths.len();
let mut paths = HashSet::with_capacity(capacity);
@ -321,7 +321,7 @@ fn collect_paths(
cli_options: &CliOptions,
diagnostics_collector: &PublishDiagnosticsCollector,
file_patterns: FilePatterns,
) -> Result<Vec<PathBuf>, AnyError> {
) -> Vec<PathBuf> {
FileCollector::new(|e| {
if !e.metadata.file_type().is_file() {
if let Ok(specifier) = ModuleSpecifier::from_file_path(e.path) {

View file

@ -4,8 +4,10 @@ use std::cell::RefCell;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::serde_json;
use deno_core::serde_json::Value;
use deno_error::JsErrorBox;
use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::Receiver;
@ -47,7 +49,7 @@ pub enum RustylineSyncMessage {
}
pub enum RustylineSyncResponse {
PostMessage(Result<Value, AnyError>),
PostMessage(Result<Value, CoreError>),
LspCompletions(Vec<ReplCompletionItem>),
}
@ -61,7 +63,7 @@ impl RustylineSyncMessageSender {
&self,
method: &str,
params: Option<T>,
) -> Result<Value, AnyError> {
) -> Result<Value, CoreError> {
if let Err(err) =
self
.message_tx
@ -69,10 +71,11 @@ impl RustylineSyncMessageSender {
method: method.to_string(),
params: params
.map(|params| serde_json::to_value(params))
.transpose()?,
.transpose()
.map_err(JsErrorBox::from_err)?,
})
{
Err(anyhow!("{}", err))
Err(JsErrorBox::from_err(err).into())
} else {
match self.response_rx.borrow_mut().blocking_recv().unwrap() {
RustylineSyncResponse::PostMessage(result) => result,

View file

@ -16,8 +16,9 @@ use deno_ast::ParsedSource;
use deno_ast::SourcePos;
use deno_ast::SourceRangedForSpanned;
use deno_ast::SourceTextInfo;
use deno_core::error::generic_error;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::channel::mpsc::UnboundedReceiver;
use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt;
@ -27,6 +28,7 @@ use deno_core::unsync::spawn;
use deno_core::url::Url;
use deno_core::LocalInspectorSession;
use deno_core::PollEventLoopOptions;
use deno_error::JsErrorBox;
use deno_graph::Position;
use deno_graph::PositionRange;
use deno_graph::SpecifierWithRange;
@ -250,10 +252,10 @@ impl ReplSession {
let cwd_url =
Url::from_directory_path(cli_options.initial_cwd()).map_err(|_| {
generic_error(format!(
anyhow!(
"Unable to construct URL from the path of cwd: {}",
cli_options.initial_cwd().to_string_lossy(),
))
)
})?;
let ts_config_for_emit = cli_options
.resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?;
@ -322,7 +324,7 @@ impl ReplSession {
&mut self,
method: &str,
params: Option<T>,
) -> Result<Value, AnyError> {
) -> Result<Value, CoreError> {
self
.worker
.js_runtime
@ -339,7 +341,7 @@ impl ReplSession {
.await
}
pub async fn run_event_loop(&mut self) -> Result<(), AnyError> {
pub async fn run_event_loop(&mut self) -> Result<(), CoreError> {
self.worker.run_event_loop(true).await
}
@ -400,21 +402,29 @@ impl ReplSession {
}
Err(err) => {
// handle a parsing diagnostic
match err.downcast_ref::<deno_ast::ParseDiagnostic>() {
match crate::util::result::any_and_jserrorbox_downcast_ref::<
deno_ast::ParseDiagnostic,
>(&err)
{
Some(diagnostic) => {
Ok(EvaluationOutput::Error(format_diagnostic(diagnostic)))
}
None => match err.downcast_ref::<ParseDiagnosticsError>() {
Some(diagnostics) => Ok(EvaluationOutput::Error(
diagnostics
.0
.iter()
.map(format_diagnostic)
.collect::<Vec<_>>()
.join("\n\n"),
)),
None => Err(err),
},
None => {
match crate::util::result::any_and_jserrorbox_downcast_ref::<
ParseDiagnosticsError,
>(&err)
{
Some(diagnostics) => Ok(EvaluationOutput::Error(
diagnostics
.0
.iter()
.map(format_diagnostic)
.collect::<Vec<_>>()
.join("\n\n"),
)),
None => Err(err),
}
}
}
}
}
@ -742,7 +752,7 @@ impl ReplSession {
async fn evaluate_expression(
&mut self,
expression: &str,
) -> Result<cdp::EvaluateResponse, AnyError> {
) -> Result<cdp::EvaluateResponse, CoreError> {
self
.post_message_with_event_loop(
"Runtime.evaluate",
@ -765,7 +775,9 @@ impl ReplSession {
}),
)
.await
.and_then(|res| serde_json::from_value(res).map_err(|e| e.into()))
.and_then(|res| {
serde_json::from_value(res).map_err(|e| JsErrorBox::from_err(e).into())
})
}
}

View file

@ -4,13 +4,13 @@ use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::StreamExt;
use deno_core::serde_json::json;
use deno_core::serde_json::{self};
use deno_core::url::Url;
use deno_core::LocalInspectorSession;
use deno_error::JsErrorBox;
use deno_terminal::colors;
use tokio::select;
@ -66,19 +66,19 @@ pub struct HmrRunner {
#[async_trait::async_trait(?Send)]
impl crate::worker::HmrRunner for HmrRunner {
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs`
async fn start(&mut self) -> Result<(), AnyError> {
async fn start(&mut self) -> Result<(), CoreError> {
self.enable_debugger().await
}
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs`
async fn stop(&mut self) -> Result<(), AnyError> {
async fn stop(&mut self) -> Result<(), CoreError> {
self
.watcher_communicator
.change_restart_mode(WatcherRestartMode::Automatic);
self.disable_debugger().await
}
async fn run(&mut self) -> Result<(), AnyError> {
async fn run(&mut self) -> Result<(), CoreError> {
self
.watcher_communicator
.change_restart_mode(WatcherRestartMode::Manual);
@ -87,13 +87,13 @@ impl crate::worker::HmrRunner for HmrRunner {
select! {
biased;
Some(notification) = session_rx.next() => {
let notification = serde_json::from_value::<cdp::Notification>(notification)?;
let notification = serde_json::from_value::<cdp::Notification>(notification).map_err(JsErrorBox::from_err)?;
if notification.method == "Runtime.exceptionThrown" {
let exception_thrown = serde_json::from_value::<cdp::ExceptionThrown>(notification.params)?;
let exception_thrown = serde_json::from_value::<cdp::ExceptionThrown>(notification.params).map_err(JsErrorBox::from_err)?;
let (message, description) = exception_thrown.exception_details.get_message_and_description();
break Err(generic_error(format!("{} {}", message, description)));
break Err(JsErrorBox::generic(format!("{} {}", message, description)).into());
} else if notification.method == "Debugger.scriptParsed" {
let params = serde_json::from_value::<cdp::ScriptParsed>(notification.params)?;
let params = serde_json::from_value::<cdp::ScriptParsed>(notification.params).map_err(JsErrorBox::from_err)?;
if params.url.starts_with("file://") {
let file_url = Url::parse(&params.url).unwrap();
let file_path = file_url.to_file_path().unwrap();
@ -105,7 +105,7 @@ impl crate::worker::HmrRunner for HmrRunner {
}
}
changed_paths = self.watcher_communicator.watch_for_changed_paths() => {
let changed_paths = changed_paths?;
let changed_paths = changed_paths.map_err(JsErrorBox::from_err)?;
let Some(changed_paths) = changed_paths else {
let _ = self.watcher_communicator.force_restart();
@ -187,7 +187,7 @@ impl HmrRunner {
}
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs`
async fn enable_debugger(&mut self) -> Result<(), AnyError> {
async fn enable_debugger(&mut self) -> Result<(), CoreError> {
self
.session
.post_message::<()>("Debugger.enable", None)
@ -200,7 +200,7 @@ impl HmrRunner {
}
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs`
async fn disable_debugger(&mut self) -> Result<(), AnyError> {
async fn disable_debugger(&mut self) -> Result<(), CoreError> {
self
.session
.post_message::<()>("Debugger.disable", None)
@ -216,7 +216,7 @@ impl HmrRunner {
&mut self,
script_id: &str,
source: &str,
) -> Result<cdp::SetScriptSourceResponse, AnyError> {
) -> Result<cdp::SetScriptSourceResponse, CoreError> {
let result = self
.session
.post_message(
@ -229,15 +229,16 @@ impl HmrRunner {
)
.await?;
Ok(serde_json::from_value::<cdp::SetScriptSourceResponse>(
result,
)?)
Ok(
serde_json::from_value::<cdp::SetScriptSourceResponse>(result)
.map_err(JsErrorBox::from_err)?,
)
}
async fn dispatch_hmr_event(
&mut self,
script_id: &str,
) -> Result<(), AnyError> {
) -> Result<(), CoreError> {
let expr = format!(
"dispatchEvent(new CustomEvent(\"hmr\", {{ detail: {{ path: \"{}\" }} }}));",
script_id

View file

@ -73,7 +73,7 @@ async fn do_serve(
)
.await?;
let worker_count = match worker_count {
None | Some(1) => return worker.run().await,
None | Some(1) => return worker.run().await.map_err(Into::into),
Some(c) => c,
};
@ -133,7 +133,7 @@ async fn run_worker(
worker.run_for_watcher().await?;
Ok(0)
} else {
worker.run().await
worker.run().await.map_err(Into::into)
}
}

View file

@ -37,7 +37,8 @@ const HALF_SYNC_MARKER: &[u8; 4] = &[226, 128, 139, 0];
const BUFFER_SIZE: usize = 4096;
/// The test channel has been closed and cannot be used to send further messages.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, deno_error::JsError)]
#[class(generic)]
pub struct ChannelClosedError;
impl std::error::Error for ChannelClosedError {}

View file

@ -25,10 +25,9 @@ use deno_cache_dir::file_fetcher::File;
use deno_config::glob::FilePatterns;
use deno_config::glob::WalkEntry;
use deno_core::anyhow;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context as _;
use deno_core::error::generic_error;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::error::JsError;
use deno_core::futures::future;
use deno_core::futures::stream;
@ -49,6 +48,7 @@ use deno_core::v8;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_core::PollEventLoopOptions;
use deno_error::JsErrorBox;
use deno_runtime::deno_io::Stdio;
use deno_runtime::deno_io::StdioPipe;
use deno_runtime::deno_permissions::Permissions;
@ -106,6 +106,8 @@ use reporters::PrettyTestReporter;
use reporters::TapTestReporter;
use reporters::TestReporter;
use crate::tools::test::channel::ChannelClosedError;
/// How many times we're allowed to spin the event loop before considering something a leak.
const MAX_SANITIZER_LOOP_SPINS: usize = 16;
@ -612,7 +614,7 @@ async fn configure_main_worker(
permissions_container: PermissionsContainer,
worker_sender: TestEventWorkerSender,
options: &TestSpecifierOptions,
) -> Result<(Option<Box<dyn CoverageCollector>>, MainWorker), anyhow::Error> {
) -> Result<(Option<Box<dyn CoverageCollector>>, MainWorker), CoreError> {
let mut worker = worker_factory
.create_custom_worker(
WorkerExecutionMode::Test,
@ -640,21 +642,15 @@ async fn configure_main_worker(
let mut worker = worker.into_main_worker();
match res {
Ok(()) => Ok(()),
Err(error) => {
// TODO(mmastrac): It would be nice to avoid having this error pattern repeated
if error.is::<JsError>() {
send_test_event(
&worker.js_runtime.op_state(),
TestEvent::UncaughtError(
specifier.to_string(),
Box::new(error.downcast::<JsError>().unwrap()),
),
)?;
Ok(())
} else {
Err(error)
}
Err(CoreError::Js(err)) => {
send_test_event(
&worker.js_runtime.op_state(),
TestEvent::UncaughtError(specifier.to_string(), Box::new(err)),
)
.map_err(JsErrorBox::from_err)?;
Ok(())
}
Err(err) => Err(err),
}?;
Ok((coverage_collector, worker))
}
@ -691,21 +687,14 @@ pub async fn test_specifier(
.await
{
Ok(()) => Ok(()),
Err(error) => {
// TODO(mmastrac): It would be nice to avoid having this error pattern repeated
if error.is::<JsError>() {
send_test_event(
&worker.js_runtime.op_state(),
TestEvent::UncaughtError(
specifier.to_string(),
Box::new(error.downcast::<JsError>().unwrap()),
),
)?;
Ok(())
} else {
Err(error)
}
Err(CoreError::Js(err)) => {
send_test_event(
&worker.js_runtime.op_state(),
TestEvent::UncaughtError(specifier.to_string(), Box::new(err)),
)?;
Ok(())
}
Err(e) => Err(e.into()),
}
}
@ -718,7 +707,7 @@ async fn test_specifier_inner(
specifier: ModuleSpecifier,
fail_fast_tracker: FailFastTracker,
options: TestSpecifierOptions,
) -> Result<(), AnyError> {
) -> Result<(), CoreError> {
// Ensure that there are no pending exceptions before we start running tests
worker.run_up_to_duration(Duration::from_millis(0)).await?;
@ -765,7 +754,7 @@ pub fn worker_has_tests(worker: &mut MainWorker) -> bool {
/// Yields to tokio to allow async work to process, and then polls
/// the event loop once.
#[must_use = "The event loop result should be checked"]
pub async fn poll_event_loop(worker: &mut MainWorker) -> Result<(), AnyError> {
pub async fn poll_event_loop(worker: &mut MainWorker) -> Result<(), CoreError> {
// Allow any ops that to do work in the tokio event loop to do so
tokio::task::yield_now().await;
// Spin the event loop once
@ -784,13 +773,11 @@ pub async fn poll_event_loop(worker: &mut MainWorker) -> Result<(), AnyError> {
pub fn send_test_event(
op_state: &RefCell<OpState>,
event: TestEvent,
) -> Result<(), AnyError> {
Ok(
op_state
.borrow_mut()
.borrow_mut::<TestEventSender>()
.send(event)?,
)
) -> Result<(), ChannelClosedError> {
op_state
.borrow_mut()
.borrow_mut::<TestEventSender>()
.send(event)
}
pub async fn run_tests_for_worker(
@ -986,13 +973,10 @@ async fn run_tests_for_worker_inner(
let result = match result {
Ok(r) => r,
Err(error) => {
if error.is::<JsError>() {
if let CoreError::Js(js_error) = error {
send_test_event(
&state_rc,
TestEvent::UncaughtError(
specifier.to_string(),
Box::new(error.downcast::<JsError>().unwrap()),
),
TestEvent::UncaughtError(specifier.to_string(), Box::new(js_error)),
)?;
fail_fast_tracker.add_failure();
send_test_event(
@ -1002,7 +986,7 @@ async fn run_tests_for_worker_inner(
had_uncaught_error = true;
continue;
} else {
return Err(error);
return Err(error.into());
}
}
};
@ -1374,25 +1358,20 @@ pub async fn report_tests(
reporter.report_summary(&elapsed, &tests, &test_steps);
if let Err(err) = reporter.flush_report(&elapsed, &tests, &test_steps) {
return (
Err(generic_error(format!(
"Test reporter failed to flush: {}",
err
))),
Err(anyhow!("Test reporter failed to flush: {}", err)),
receiver,
);
}
if used_only {
return (
Err(generic_error(
"Test failed because the \"only\" option was used",
)),
Err(anyhow!("Test failed because the \"only\" option was used",)),
receiver,
);
}
if failed {
return (Err(generic_error("Test failed")), receiver);
return (Err(anyhow!("Test failed")), receiver);
}
(Ok(()), receiver)
@ -1575,7 +1554,7 @@ pub async fn run_tests(
if !workspace_test_options.permit_no_files && specifiers_with_mode.is_empty()
{
return Err(generic_error("No test modules found"));
return Err(anyhow!("No test modules found"));
}
let doc_tests = get_doc_tests(&specifiers_with_mode, file_fetcher).await?;
@ -1611,10 +1590,10 @@ pub async fn run_tests(
TestSpecifiersOptions {
cwd: Url::from_directory_path(cli_options.initial_cwd()).map_err(
|_| {
generic_error(format!(
anyhow!(
"Unable to construct URL from the path of cwd: {}",
cli_options.initial_cwd().to_string_lossy(),
))
)
},
)?,
concurrent_jobs: workspace_test_options.concurrent_jobs,
@ -1793,10 +1772,10 @@ pub async fn run_tests_with_watch(
TestSpecifiersOptions {
cwd: Url::from_directory_path(cli_options.initial_cwd()).map_err(
|_| {
generic_error(format!(
anyhow!(
"Unable to construct URL from the path of cwd: {}",
cli_options.initial_cwd().to_string_lossy(),
))
)
},
)?,
concurrent_jobs: workspace_test_options.concurrent_jobs,

View file

@ -129,7 +129,7 @@ impl TestReporter for CompoundTestReporter {
if errors.is_empty() {
Ok(())
} else {
bail!(
anyhow::bail!(
"error in one or more wrapped reporters:\n{}",
errors
.iter()

View file

@ -3,6 +3,8 @@
use std::collections::VecDeque;
use std::path::PathBuf;
use deno_core::anyhow::Context;
use super::fmt::to_relative_path_or_remote_url;
use super::*;

View file

@ -320,7 +320,8 @@ impl fmt::Display for Diagnostic {
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[derive(Clone, Debug, Default, Eq, PartialEq, deno_error::JsError)]
#[class(generic)]
pub struct Diagnostics(Vec<Diagnostic>);
impl Diagnostics {

View file

@ -3,12 +3,10 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use deno_ast::MediaType;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::ascii_str;
use deno_core::error::AnyError;
@ -454,13 +452,6 @@ impl State {
}
}
fn normalize_specifier(
specifier: &str,
current_dir: &Path,
) -> Result<ModuleSpecifier, AnyError> {
resolve_url_or_path(specifier, current_dir).map_err(|err| err.into())
}
#[op2]
#[string]
fn op_create_hash(s: &mut OpState, #[string] text: &str) -> String {
@ -531,6 +522,21 @@ pub fn as_ts_script_kind(media_type: MediaType) -> i32 {
pub const MISSING_DEPENDENCY_SPECIFIER: &str =
"internal:///missing_dependency.d.ts";
#[derive(Debug, Error, deno_error::JsError)]
pub enum LoadError {
#[class(generic)]
#[error("Unable to load {path}: {error}")]
LoadFromNodeModule { path: String, error: std::io::Error },
#[class(inherit)]
#[error(
"Error converting a string module specifier for \"op_resolve\": {0}"
)]
ModuleResolution(#[from] deno_core::ModuleResolutionError),
#[class(inherit)]
#[error("{0}")]
ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError),
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct LoadResponse {
@ -545,24 +551,28 @@ struct LoadResponse {
fn op_load(
state: &mut OpState,
#[string] load_specifier: &str,
) -> Result<Option<LoadResponse>, AnyError> {
) -> Result<Option<LoadResponse>, LoadError> {
op_load_inner(state, load_specifier)
}
fn op_load_inner(
state: &mut OpState,
load_specifier: &str,
) -> Result<Option<LoadResponse>, AnyError> {
) -> Result<Option<LoadResponse>, LoadError> {
fn load_from_node_modules(
specifier: &ModuleSpecifier,
npm_state: Option<&RequestNpmState>,
media_type: &mut MediaType,
is_cjs: &mut bool,
) -> Result<String, AnyError> {
) -> Result<String, LoadError> {
*media_type = MediaType::from_specifier(specifier);
let file_path = specifier.to_file_path().unwrap();
let code = std::fs::read_to_string(&file_path)
.with_context(|| format!("Unable to load {}", file_path.display()))?;
let code = std::fs::read_to_string(&file_path).map_err(|err| {
LoadError::LoadFromNodeModule {
path: file_path.display().to_string(),
error: err,
}
})?;
let code: Arc<str> = code.into();
*is_cjs = npm_state
.map(|npm_state| {
@ -575,8 +585,7 @@ fn op_load_inner(
let state = state.borrow_mut::<State>();
let specifier = normalize_specifier(load_specifier, &state.current_dir)
.context("Error converting a string module specifier for \"op_load\".")?;
let specifier = resolve_url_or_path(load_specifier, &state.current_dir)?;
let mut hash: Option<String> = None;
let mut media_type = MediaType::Unknown;
@ -688,6 +697,26 @@ fn op_load_inner(
}))
}
#[derive(Debug, Error, deno_error::JsError)]
pub enum ResolveError {
#[class(inherit)]
#[error(
"Error converting a string module specifier for \"op_resolve\": {0}"
)]
ModuleResolution(#[from] deno_core::ModuleResolutionError),
#[class(inherit)]
#[error("{0}")]
PackageSubpathResolve(PackageSubpathResolveError),
#[class(inherit)]
#[error("{0}")]
ResolvePkgFolderFromDenoModule(
#[from] crate::npm::ResolvePkgFolderFromDenoModuleError,
),
#[class(inherit)]
#[error("{0}")]
ResolveNonGraphSpecifierTypes(#[from] ResolveNonGraphSpecifierTypesError),
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ResolveArgs {
@ -717,7 +746,7 @@ fn op_resolve(
state: &mut OpState,
#[string] base: String,
#[serde] specifiers: Vec<(bool, String)>,
) -> Result<Vec<(String, &'static str)>, AnyError> {
) -> Result<Vec<(String, &'static str)>, ResolveError> {
op_resolve_inner(state, ResolveArgs { base, specifiers })
}
@ -725,7 +754,7 @@ fn op_resolve(
fn op_resolve_inner(
state: &mut OpState,
args: ResolveArgs,
) -> Result<Vec<(String, &'static str)>, AnyError> {
) -> Result<Vec<(String, &'static str)>, ResolveError> {
let state = state.borrow_mut::<State>();
let mut resolved: Vec<(String, &'static str)> =
Vec::with_capacity(args.specifiers.len());
@ -734,9 +763,7 @@ fn op_resolve_inner(
{
remapped_specifier.clone()
} else {
normalize_specifier(&args.base, &state.current_dir).context(
"Error converting a string module specifier for \"op_resolve\".",
)?
resolve_url_or_path(&args.base, &state.current_dir)?
};
let referrer_module = state.graph.get(&referrer);
for (is_cjs, specifier) in args.specifiers {
@ -852,7 +879,7 @@ fn resolve_graph_specifier_types(
referrer: &ModuleSpecifier,
resolution_mode: ResolutionMode,
state: &State,
) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> {
) -> Result<Option<(ModuleSpecifier, MediaType)>, ResolveError> {
let graph = &state.graph;
let maybe_module = match graph.try_get(specifier) {
Ok(Some(module)) => Some(module),
@ -914,7 +941,7 @@ fn resolve_graph_specifier_types(
Err(err) => match err.code() {
NodeJsErrorCode::ERR_TYPES_NOT_FOUND
| NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None,
_ => return Err(err.into()),
_ => return Err(ResolveError::PackageSubpathResolve(err)),
},
};
Ok(Some(into_specifier_and_media_type(maybe_url)))
@ -936,10 +963,12 @@ fn resolve_graph_specifier_types(
}
}
#[derive(Debug, Error)]
enum ResolveNonGraphSpecifierTypesError {
#[derive(Debug, Error, deno_error::JsError)]
pub enum ResolveNonGraphSpecifierTypesError {
#[class(inherit)]
#[error(transparent)]
ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError),
#[class(inherit)]
#[error(transparent)]
PackageSubpathResolve(#[from] PackageSubpathResolveError),
}
@ -1036,10 +1065,20 @@ fn op_respond_inner(state: &mut OpState, args: RespondArgs) {
state.maybe_response = Some(args);
}
#[derive(Debug, Error, deno_error::JsError)]
pub enum ExecError {
#[class(generic)]
#[error("The response for the exec request was not set.")]
ResponseNotSet,
#[class(inherit)]
#[error(transparent)]
Core(deno_core::error::CoreError),
}
/// Execute a request on the supplied snapshot, returning a response which
/// contains information, like any emitted files, diagnostics, statistics and
/// optionally an updated TypeScript build info.
pub fn exec(request: Request) -> Result<Response, AnyError> {
pub fn exec(request: Request) -> Result<Response, ExecError> {
// tsc cannot handle root specifiers that don't have one of the "acceptable"
// extensions. Therefore, we have to check the root modules against their
// extensions and remap any that are unacceptable to tsc and add them to the
@ -1115,7 +1154,9 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
..Default::default()
});
runtime.execute_script(located_script_name!(), exec_source)?;
runtime
.execute_script(located_script_name!(), exec_source)
.map_err(ExecError::Core)?;
let op_state = runtime.op_state();
let mut op_state = op_state.borrow_mut();
@ -1132,7 +1173,7 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
stats,
})
} else {
Err(anyhow!("The response for the exec request was not set."))
Err(ExecError::ResponseNotSet)
}
}
@ -1141,6 +1182,7 @@ mod tests {
use deno_core::futures::future;
use deno_core::serde_json;
use deno_core::OpState;
use deno_error::JsErrorBox;
use deno_graph::GraphKind;
use deno_graph::ModuleGraph;
use test_util::PathRef;
@ -1167,13 +1209,20 @@ mod tests {
.replace("://", "_")
.replace('/', "-");
let source_path = self.fixtures.join(specifier_text);
let response = source_path.read_to_bytes_if_exists().map(|c| {
Some(deno_graph::source::LoadResponse::Module {
specifier: specifier.clone(),
maybe_headers: None,
content: c.into(),
let response = source_path
.read_to_bytes_if_exists()
.map(|c| {
Some(deno_graph::source::LoadResponse::Module {
specifier: specifier.clone(),
maybe_headers: None,
content: c.into(),
})
})
});
.map_err(|e| {
deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::generic(
e.to_string(),
)))
});
Box::pin(future::ready(response))
}
}
@ -1210,7 +1259,7 @@ mod tests {
async fn test_exec(
specifier: &ModuleSpecifier,
) -> Result<Response, AnyError> {
) -> Result<Response, ExecError> {
let hash_data = 123; // something random
let fixtures = test_util::testdata_path().join("tsc2");
let loader = MockLoader { fixtures };

View file

@ -10,7 +10,7 @@ use std::time::Duration;
use deno_config::glob::PathOrPatternSet;
use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::error::CoreError;
use deno_core::futures::Future;
use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex;
@ -23,6 +23,7 @@ use notify::RecommendedWatcher;
use notify::RecursiveMode;
use notify::Watcher;
use tokio::select;
use tokio::sync::broadcast::error::RecvError;
use tokio::sync::mpsc;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::time::sleep;
@ -80,10 +81,13 @@ where
{
let result = watch_future.await;
if let Err(err) = result {
let error_string = match err.downcast_ref::<JsError>() {
Some(e) => format_js_error(e),
None => format!("{err:?}"),
};
let error_string =
match crate::util::result::any_and_jserrorbox_downcast_ref::<CoreError>(
&err,
) {
Some(CoreError::Js(e)) => format_js_error(e),
_ => format!("{err:?}"),
};
log::error!(
"{}: {}",
colors::red_bold("error"),
@ -171,9 +175,9 @@ impl WatcherCommunicator {
pub async fn watch_for_changed_paths(
&self,
) -> Result<Option<Vec<PathBuf>>, AnyError> {
) -> Result<Option<Vec<PathBuf>>, RecvError> {
let mut rx = self.changed_paths_rx.resubscribe();
rx.recv().await.map_err(AnyError::from)
rx.recv().await
}
pub fn change_restart_mode(&self, restart_mode: WatcherRestartMode) {

View file

@ -13,7 +13,6 @@ use deno_config::glob::PathOrPattern;
use deno_config::glob::PathOrPatternSet;
use deno_config::glob::WalkEntry;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::unsync::spawn_blocking;
use deno_core::ModuleSpecifier;
@ -129,7 +128,7 @@ pub fn collect_specifiers(
.ignore_git_folder()
.ignore_node_modules()
.set_vendor_folder(vendor_folder)
.collect_file_patterns(&CliSys::default(), files)?;
.collect_file_patterns(&CliSys::default(), files);
let mut collected_files_as_urls = collected_files
.iter()
.map(|f| specifier_from_file_path(f).unwrap())
@ -169,7 +168,7 @@ pub fn clone_dir_recursive<
sys: &TSys,
from: &Path,
to: &Path,
) -> Result<(), AnyError> {
) -> Result<(), CopyDirRecursiveError> {
if cfg!(target_vendor = "apple") {
if let Some(parent) = to.parent() {
sys.fs_create_dir_all(parent)?;
@ -200,6 +199,47 @@ pub fn clone_dir_recursive<
Ok(())
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CopyDirRecursiveError {
#[class(inherit)]
#[error("Creating {path}")]
Creating {
path: PathBuf,
#[source]
#[inherit]
source: Error,
},
#[class(inherit)]
#[error("Creating {path}")]
Reading {
path: PathBuf,
#[source]
#[inherit]
source: Error,
},
#[class(inherit)]
#[error("Dir {from} to {to}")]
Dir {
from: PathBuf,
to: PathBuf,
#[source]
#[inherit]
source: Box<Self>,
},
#[class(inherit)]
#[error("Copying {from} to {to}")]
Copying {
from: PathBuf,
to: PathBuf,
#[source]
#[inherit]
source: Error,
},
#[class(inherit)]
#[error(transparent)]
Other(#[from] Error),
}
/// Copies a directory to another directory.
///
/// Note: Does not handle symlinks.
@ -213,13 +253,20 @@ pub fn copy_dir_recursive<
sys: &TSys,
from: &Path,
to: &Path,
) -> Result<(), AnyError> {
sys
.fs_create_dir_all(to)
.with_context(|| format!("Creating {}", to.display()))?;
let read_dir = sys
.fs_read_dir(from)
.with_context(|| format!("Reading {}", from.display()))?;
) -> Result<(), CopyDirRecursiveError> {
sys.fs_create_dir_all(to).map_err(|source| {
CopyDirRecursiveError::Creating {
path: to.to_path_buf(),
source,
}
})?;
let read_dir =
sys
.fs_read_dir(from)
.map_err(|source| CopyDirRecursiveError::Reading {
path: from.to_path_buf(),
source,
})?;
for entry in read_dir {
let entry = entry?;
@ -228,12 +275,20 @@ pub fn copy_dir_recursive<
let new_to = to.join(entry.file_name());
if file_type.is_dir() {
copy_dir_recursive(sys, &new_from, &new_to).with_context(|| {
format!("Dir {} to {}", new_from.display(), new_to.display())
copy_dir_recursive(sys, &new_from, &new_to).map_err(|source| {
CopyDirRecursiveError::Dir {
from: new_from.to_path_buf(),
to: new_to.to_path_buf(),
source: Box::new(source),
}
})?;
} else if file_type.is_file() {
sys.fs_copy(&new_from, &new_to).with_context(|| {
format!("Copying {} to {}", new_from.display(), new_to.display())
sys.fs_copy(&new_from, &new_to).map_err(|source| {
CopyDirRecursiveError::Copying {
from: new_from.to_path_buf(),
to: new_to.to_path_buf(),
source,
}
})?;
}
}

View file

@ -1,6 +1,13 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::convert::Infallible;
use std::fmt::Debug;
use std::fmt::Display;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
pub trait InfallibleResultExt<T> {
fn unwrap_infallible(self) -> T;
@ -14,3 +21,23 @@ impl<T> InfallibleResultExt<T> for Result<T, Infallible> {
}
}
}
pub fn any_and_jserrorbox_downcast_ref<
E: Display + Debug + Send + Sync + 'static,
>(
err: &AnyError,
) -> Option<&E> {
err
.downcast_ref::<E>()
.or_else(|| {
err
.downcast_ref::<JsErrorBox>()
.and_then(|e| e.as_any().downcast_ref::<E>())
})
.or_else(|| {
err.downcast_ref::<CoreError>().and_then(|e| match e {
CoreError::JsNative(e) => e.as_any().downcast_ref::<E>(),
_ => None,
})
})
}

View file

@ -8,6 +8,7 @@ use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::FutureExt;
use deno_core::url::Url;
use deno_core::v8;
@ -17,6 +18,7 @@ use deno_core::FeatureChecker;
use deno_core::ModuleLoader;
use deno_core::PollEventLoopOptions;
use deno_core::SharedArrayBufferStore;
use deno_error::JsErrorBox;
use deno_runtime::code_cache;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_fs;
@ -50,7 +52,6 @@ use crate::args::CliLockfile;
use crate::args::DenoSubcommand;
use crate::args::NpmCachingStrategy;
use crate::args::StorageKeyResolver;
use crate::errors;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::CliNpmResolver;
@ -80,9 +81,9 @@ pub trait ModuleLoaderFactory: Send + Sync {
#[async_trait::async_trait(?Send)]
pub trait HmrRunner: Send + Sync {
async fn start(&mut self) -> Result<(), AnyError>;
async fn stop(&mut self) -> Result<(), AnyError>;
async fn run(&mut self) -> Result<(), AnyError>;
async fn start(&mut self) -> Result<(), CoreError>;
async fn stop(&mut self) -> Result<(), CoreError>;
async fn run(&mut self) -> Result<(), CoreError>;
}
pub trait CliCodeCache: code_cache::CodeCache {
@ -195,7 +196,7 @@ impl CliMainWorker {
Ok(())
}
pub async fn run(&mut self) -> Result<i32, AnyError> {
pub async fn run(&mut self) -> Result<i32, CoreError> {
let mut maybe_coverage_collector =
self.maybe_setup_coverage_collector().await?;
let mut maybe_hmr_runner = self.maybe_setup_hmr_runner().await?;
@ -216,7 +217,7 @@ impl CliMainWorker {
let result;
select! {
hmr_result = hmr_future => {
result = hmr_result;
result = hmr_result.map_err(Into::into);
},
event_loop_result = event_loop_future => {
result = event_loop_result;
@ -331,12 +332,12 @@ impl CliMainWorker {
executor.execute().await
}
pub async fn execute_main_module(&mut self) -> Result<(), AnyError> {
pub async fn execute_main_module(&mut self) -> Result<(), CoreError> {
let id = self.worker.preload_main_module(&self.main_module).await?;
self.worker.evaluate_module(id).await
}
pub async fn execute_side_module(&mut self) -> Result<(), AnyError> {
pub async fn execute_side_module(&mut self) -> Result<(), CoreError> {
let id = self.worker.preload_side_module(&self.main_module).await?;
self.worker.evaluate_module(id).await
}
@ -393,7 +394,7 @@ impl CliMainWorker {
&mut self,
name: &'static str,
source_code: &'static str,
) -> Result<v8::Global<v8::Value>, AnyError> {
) -> Result<v8::Global<v8::Value>, CoreError> {
self.worker.js_runtime.execute_script(name, source_code)
}
}
@ -465,7 +466,7 @@ impl CliMainWorkerFactory {
&self,
mode: WorkerExecutionMode,
main_module: ModuleSpecifier,
) -> Result<CliMainWorker, AnyError> {
) -> Result<CliMainWorker, CoreError> {
self
.create_custom_worker(
mode,
@ -484,7 +485,7 @@ impl CliMainWorkerFactory {
permissions: PermissionsContainer,
custom_extensions: Vec<Extension>,
stdio: deno_runtime::deno_io::Stdio,
) -> Result<CliMainWorker, AnyError> {
) -> Result<CliMainWorker, CoreError> {
let shared = &self.shared;
let CreateModuleLoaderResult {
module_loader,
@ -513,16 +514,15 @@ impl CliMainWorkerFactory {
}
// use a fake referrer that can be used to discover the package.json if necessary
let referrer =
ModuleSpecifier::from_directory_path(self.shared.fs.cwd()?)
.unwrap()
.join("package.json")?;
let referrer = ModuleSpecifier::from_directory_path(
self.shared.fs.cwd().map_err(JsErrorBox::from_err)?,
)
.unwrap()
.join("package.json")?;
let package_folder = shared
.npm_resolver
.resolve_pkg_folder_from_deno_module_req(
package_ref.req(),
&referrer,
)?;
.resolve_pkg_folder_from_deno_module_req(package_ref.req(), &referrer)
.map_err(JsErrorBox::from_err)?;
let main_module = self
.resolve_binary_entrypoint(&package_folder, package_ref.sub_path())?;
@ -633,7 +633,6 @@ impl CliMainWorkerFactory {
should_break_on_first_statement: shared.options.inspect_brk,
should_wait_for_inspector_session: shared.options.inspect_wait,
strace_ops: shared.options.strace_ops.clone(),
get_error_class_fn: Some(&errors::get_error_class_name),
cache_storage_dir,
origin_storage_dir,
stdio,
@ -834,7 +833,6 @@ fn create_web_worker_callback(
create_web_worker_cb,
format_js_error_fn: Some(Arc::new(format_js_error)),
worker_type: args.worker_type,
get_error_class_fn: Some(&errors::get_error_class_name),
stdio: stdio.clone(),
cache_storage_dir,
strace_ops: shared.options.strace_ops.clone(),

View file

@ -16,6 +16,7 @@ path = "lib.rs"
[dependencies]
async-trait.workspace = true
deno_core.workspace = true
deno_error.workspace = true
thiserror.workspace = true
tokio.workspace = true
uuid.workspace = true

View file

@ -12,6 +12,7 @@ use deno_core::JsBuffer;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_error::JsErrorBox;
pub use in_memory_broadcast_channel::InMemoryBroadcastChannel;
pub use in_memory_broadcast_channel::InMemoryBroadcastChannelResource;
use tokio::sync::broadcast::error::SendError as BroadcastSendError;
@ -19,18 +20,26 @@ use tokio::sync::mpsc::error::SendError as MpscSendError;
pub const UNSTABLE_FEATURE_NAME: &str = "broadcast-channel";
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum BroadcastChannelError {
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(
#[from]
#[inherit]
deno_core::error::ResourceError,
),
#[class(generic)]
#[error(transparent)]
MPSCSendError(MpscSendError<Box<dyn std::fmt::Debug + Send + Sync>>),
#[class(generic)]
#[error(transparent)]
BroadcastSendError(
BroadcastSendError<Box<dyn std::fmt::Debug + Send + Sync>>,
),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(#[inherit] JsErrorBox),
}
impl<T: std::fmt::Debug + Send + Sync + 'static> From<MpscSendError<T>>
@ -100,10 +109,7 @@ pub fn op_broadcast_unsubscribe<BC>(
where
BC: BroadcastChannel + 'static,
{
let resource = state
.resource_table
.get::<BC::Resource>(rid)
.map_err(BroadcastChannelError::Resource)?;
let resource = state.resource_table.get::<BC::Resource>(rid)?;
let bc = state.borrow::<BC>();
bc.unsubscribe(&resource)
}
@ -118,11 +124,7 @@ pub async fn op_broadcast_send<BC>(
where
BC: BroadcastChannel + 'static,
{
let resource = state
.borrow()
.resource_table
.get::<BC::Resource>(rid)
.map_err(BroadcastChannelError::Resource)?;
let resource = state.borrow().resource_table.get::<BC::Resource>(rid)?;
let bc = state.borrow().borrow::<BC>().clone();
bc.send(&resource, name, buf.to_vec()).await
}
@ -136,11 +138,7 @@ pub async fn op_broadcast_recv<BC>(
where
BC: BroadcastChannel + 'static,
{
let resource = state
.borrow()
.resource_table
.get::<BC::Resource>(rid)
.map_err(BroadcastChannelError::Resource)?;
let resource = state.borrow().resource_table.get::<BC::Resource>(rid)?;
let bc = state.borrow().borrow::<BC>().clone();
bc.recv(&resource).await
}

View file

@ -16,6 +16,7 @@ path = "lib.rs"
[dependencies]
async-trait.workspace = true
deno_core.workspace = true
deno_error.workspace = true
rusqlite.workspace = true
serde.workspace = true
sha2.workspace = true

27
ext/cache/lib.rs vendored
View file

@ -6,7 +6,6 @@ use std::rc::Rc;
use std::sync::Arc;
use async_trait::async_trait;
use deno_core::error::type_error;
use deno_core::op2;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
@ -14,22 +13,38 @@ use deno_core::ByteString;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_error::JsErrorBox;
mod sqlite;
pub use sqlite::SqliteBackedCache;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CacheError {
#[class(type)]
#[error("CacheStorage is not available in this context")]
ContextUnsupported,
#[class(generic)]
#[error(transparent)]
Sqlite(#[from] rusqlite::Error),
#[class(generic)]
#[error(transparent)]
JoinError(#[from] tokio::task::JoinError),
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(JsErrorBox),
#[class(inherit)]
#[error("{0}")]
Io(#[from] std::io::Error),
#[class(generic)]
#[error("Failed to create cache storage directory {}", .dir.display())]
CacheStorageDirectory {
dir: PathBuf,
#[source]
source: std::io::Error,
},
}
#[derive(Clone)]
@ -237,9 +252,7 @@ where
state.put(cache);
Ok(state.borrow::<CA>().clone())
} else {
Err(CacheError::Other(type_error(
"CacheStorage is not available in this context",
)))
Err(CacheError::ContextUnsupported)
}
}

21
ext/cache/sqlite.rs vendored
View file

@ -8,8 +8,6 @@ use std::time::SystemTime;
use std::time::UNIX_EPOCH;
use async_trait::async_trait;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::futures::future::poll_fn;
use deno_core::parking_lot::Mutex;
use deno_core::unsync::spawn_blocking;
@ -45,14 +43,12 @@ pub struct SqliteBackedCache {
impl SqliteBackedCache {
pub fn new(cache_storage_dir: PathBuf) -> Result<Self, CacheError> {
{
std::fs::create_dir_all(&cache_storage_dir)
.with_context(|| {
format!(
"Failed to create cache storage directory {}",
cache_storage_dir.display()
)
})
.map_err(CacheError::Other)?;
std::fs::create_dir_all(&cache_storage_dir).map_err(|source| {
CacheError::CacheStorageDirectory {
dir: cache_storage_dir.clone(),
source,
}
})?;
let path = cache_storage_dir.join("cache_metadata.db");
let connection = rusqlite::Connection::open(&path).unwrap_or_else(|_| {
panic!("failed to open cache db at {}", path.display())
@ -385,7 +381,10 @@ impl CacheResponseResource {
}
}
async fn read(self: Rc<Self>, data: &mut [u8]) -> Result<usize, AnyError> {
async fn read(
self: Rc<Self>,
data: &mut [u8],
) -> Result<usize, std::io::Error> {
let resource = deno_core::RcRef::map(&self, |r| &r.file);
let mut file = resource.borrow_mut().await;
let nread = file.read(data).await?;

View file

@ -15,6 +15,7 @@ path = "lib.rs"
[dependencies]
deno_core.workspace = true
deno_error.workspace = true
deno_webgpu.workspace = true
image = { version = "0.24.7", default-features = false, features = ["png"] }
serde = { workspace = true, features = ["derive"] }

View file

@ -12,10 +12,12 @@ use image::RgbaImage;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CanvasError {
#[class(type)]
#[error("Color type '{0:?}' not supported")]
UnsupportedColorType(ColorType),
#[class(generic)]
#[error(transparent)]
Image(#[from] image::ImageError),
}

View file

@ -18,6 +18,7 @@ anyhow.workspace = true
async-trait.workspace = true
chrono = { workspace = true, features = ["now"] }
deno_core.workspace = true
deno_error.workspace = true
saffron.workspace = true
thiserror.workspace = true
tokio.workspace = true

View file

@ -7,11 +7,12 @@ use std::borrow::Cow;
use std::cell::RefCell;
use std::rc::Rc;
use deno_core::error::get_custom_error_class;
use deno_core::op2;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
pub use crate::interface::*;
@ -47,26 +48,35 @@ impl<EH: CronHandle + 'static> Resource for CronResource<EH> {
}
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CronError {
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(type)]
#[error("Cron name cannot exceed 64 characters: current length {0}")]
NameExceeded(usize),
#[class(type)]
#[error("Invalid cron name: only alphanumeric characters, whitespace, hyphens, and underscores are allowed")]
NameInvalid,
#[class(type)]
#[error("Cron with this name already exists")]
AlreadyExists,
#[class(type)]
#[error("Too many crons")]
TooManyCrons,
#[class(type)]
#[error("Invalid cron schedule")]
InvalidCron,
#[class(type)]
#[error("Invalid backoff schedule")]
InvalidBackoff,
#[class(generic)]
#[error(transparent)]
AcquireError(#[from] tokio::sync::AcquireError),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(JsErrorBox),
}
#[op2]
@ -119,7 +129,7 @@ where
let resource = match state.resource_table.get::<CronResource<C::EH>>(rid) {
Ok(resource) => resource,
Err(err) => {
if get_custom_error_class(&err) == Some("BadResource") {
if err.get_class() == "BadResource" {
return Ok(false);
} else {
return Err(CronError::Resource(err));

View file

@ -23,6 +23,7 @@ const-oid = "0.9.0"
ctr = "0.9.1"
curve25519-dalek = "4.1.3"
deno_core.workspace = true
deno_error.workspace = true
deno_web.workspace = true
ed448-goldilocks = { version = "0.8.3", features = ["zeroize"] }
elliptic-curve = { version = "0.13.1", features = ["std", "pem"] }

View file

@ -70,26 +70,40 @@ pub enum DecryptAlgorithm {
},
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum DecryptError {
#[class(inherit)]
#[error(transparent)]
General(#[from] SharedError),
General(
#[from]
#[inherit]
SharedError,
),
#[class(generic)]
#[error(transparent)]
Pkcs1(#[from] rsa::pkcs1::Error),
#[class("DOMExceptionOperationError")]
#[error("Decryption failed")]
Failed,
#[class(type)]
#[error("invalid length")]
InvalidLength,
#[class(type)]
#[error("invalid counter length. Currently supported 32/64/128 bits")]
InvalidCounterLength,
#[class(type)]
#[error("tag length not equal to 128")]
InvalidTagLength,
#[class("DOMExceptionOperationError")]
#[error("invalid key or iv")]
InvalidKeyOrIv,
#[class("DOMExceptionOperationError")]
#[error("tried to decrypt too much data")]
TooMuchData,
#[class(type)]
#[error("iv length not equal to 12 or 16")]
InvalidIvLength,
#[class("DOMExceptionOperationError")]
#[error("{0}")]
Rsa(rsa::Error),
}

View file

@ -13,12 +13,15 @@ use spki::der::asn1::BitString;
use spki::der::Decode;
use spki::der::Encode;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum Ed25519Error {
#[class("DOMExceptionOperationError")]
#[error("Failed to export key")]
FailedExport,
#[class(generic)]
#[error(transparent)]
Der(#[from] rsa::pkcs1::der::Error),
#[class(generic)]
#[error(transparent)]
KeyRejected(#[from] ring::error::KeyRejected),
}

View file

@ -71,20 +71,31 @@ pub enum EncryptAlgorithm {
},
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum EncryptError {
#[class(inherit)]
#[error(transparent)]
General(#[from] SharedError),
General(
#[from]
#[inherit]
SharedError,
),
#[class(type)]
#[error("invalid length")]
InvalidLength,
#[class("DOMExceptionOperationError")]
#[error("invalid key or iv")]
InvalidKeyOrIv,
#[class(type)]
#[error("iv length not equal to 12 or 16")]
InvalidIvLength,
#[class(type)]
#[error("invalid counter length. Currently supported 32/64/128 bits")]
InvalidCounterLength,
#[class("DOMExceptionOperationError")]
#[error("tried to encrypt too much data")]
TooMuchData,
#[class("DOMExceptionOperationError")]
#[error("Encryption failed")]
Failed,
}

View file

@ -20,12 +20,19 @@ use spki::AlgorithmIdentifierOwned;
use crate::shared::*;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ExportKeyError {
#[class(inherit)]
#[error(transparent)]
General(#[from] SharedError),
General(
#[from]
#[inherit]
SharedError,
),
#[class(generic)]
#[error(transparent)]
Der(#[from] spki::der::Error),
#[class("DOMExceptionNotSupportedError")]
#[error("Unsupported named curve")]
UnsupportedNamedCurve,
}

View file

@ -15,10 +15,16 @@ use serde::Deserialize;
use crate::shared::*;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class("DOMExceptionOperationError")]
pub enum GenerateKeyError {
#[class(inherit)]
#[error(transparent)]
General(#[from] SharedError),
General(
#[from]
#[inherit]
SharedError,
),
#[error("Bad public exponent")]
BadPublicExponent,
#[error("Invalid HMAC key length")]

View file

@ -14,10 +14,16 @@ use spki::der::Decode;
use crate::shared::*;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class("DOMExceptionDataError")]
pub enum ImportKeyError {
#[class(inherit)]
#[error(transparent)]
General(#[from] SharedError),
General(
#[from]
#[inherit]
SharedError,
),
#[error("invalid modulus")]
InvalidModulus,
#[error("invalid public exponent")]

View file

@ -8,12 +8,12 @@ use aes_kw::KekAes192;
use aes_kw::KekAes256;
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
use base64::Engine;
use deno_core::error::not_supported;
use deno_core::op2;
use deno_core::unsync::spawn_blocking;
use deno_core::JsBuffer;
use deno_core::OpState;
use deno_core::ToJsBuffer;
use deno_error::JsErrorBox;
use p256::elliptic_curve::sec1::FromEncodedPoint;
use p256::pkcs8::DecodePrivateKey;
pub use rand;
@ -129,63 +129,99 @@ deno_core::extension!(deno_crypto,
},
);
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CryptoError {
#[class(inherit)]
#[error(transparent)]
General(#[from] SharedError),
General(
#[from]
#[inherit]
SharedError,
),
#[class(inherit)]
#[error(transparent)]
JoinError(#[from] tokio::task::JoinError),
JoinError(
#[from]
#[inherit]
tokio::task::JoinError,
),
#[class(generic)]
#[error(transparent)]
Der(#[from] rsa::pkcs1::der::Error),
#[class(type)]
#[error("Missing argument hash")]
MissingArgumentHash,
#[class(type)]
#[error("Missing argument saltLength")]
MissingArgumentSaltLength,
#[class(type)]
#[error("unsupported algorithm")]
UnsupportedAlgorithm,
#[class(generic)]
#[error(transparent)]
KeyRejected(#[from] ring::error::KeyRejected),
#[class(generic)]
#[error(transparent)]
RSA(#[from] rsa::Error),
#[class(generic)]
#[error(transparent)]
Pkcs1(#[from] rsa::pkcs1::Error),
#[class(generic)]
#[error(transparent)]
Unspecified(#[from] ring::error::Unspecified),
#[class(type)]
#[error("Invalid key format")]
InvalidKeyFormat,
#[class(generic)]
#[error(transparent)]
P256Ecdsa(#[from] p256::ecdsa::Error),
#[class(type)]
#[error("Unexpected error decoding private key")]
DecodePrivateKey,
#[class(type)]
#[error("Missing argument publicKey")]
MissingArgumentPublicKey,
#[class(type)]
#[error("Missing argument namedCurve")]
MissingArgumentNamedCurve,
#[class(type)]
#[error("Missing argument info")]
MissingArgumentInfo,
#[class("DOMExceptionOperationError")]
#[error("The length provided for HKDF is too large")]
HKDFLengthTooLarge,
#[class(generic)]
#[error(transparent)]
Base64Decode(#[from] base64::DecodeError),
#[class(type)]
#[error("Data must be multiple of 8 bytes")]
DataInvalidSize,
#[class(type)]
#[error("Invalid key length")]
InvalidKeyLength,
#[class("DOMExceptionOperationError")]
#[error("encryption error")]
EncryptionError,
#[class("DOMExceptionOperationError")]
#[error("decryption error - integrity check failed")]
DecryptionError,
#[class("DOMExceptionQuotaExceededError")]
#[error("The ArrayBufferView's byte length ({0}) exceeds the number of bytes of entropy available via this API (65536)")]
ArrayBufferViewLengthExceeded(usize),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(
#[from]
#[inherit]
JsErrorBox,
),
}
#[op2]
#[serde]
pub fn op_crypto_base64url_decode(
#[string] data: String,
) -> Result<ToJsBuffer, Error> {
) -> Result<ToJsBuffer, CryptoError> {
let data: Vec<u8> = BASE64_URL_SAFE_NO_PAD.decode(data)?;
Ok(data.into())
}
@ -201,9 +237,9 @@ pub fn op_crypto_base64url_encode(#[buffer] data: JsBuffer) -> String {
pub fn op_crypto_get_random_values(
state: &mut OpState,
#[buffer] out: &mut [u8],
) -> Result<(), Error> {
) -> Result<(), CryptoError> {
if out.len() > 65536 {
return Err(Error::ArrayBufferViewLengthExceeded(out.len()));
return Err(CryptoError::ArrayBufferViewLengthExceeded(out.len()));
}
let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
@ -255,7 +291,7 @@ pub struct SignArg {
pub async fn op_crypto_sign_key(
#[serde] args: SignArg,
#[buffer] zero_copy: JsBuffer,
) -> Result<ToJsBuffer, Error> {
) -> Result<ToJsBuffer, CryptoError> {
deno_core::unsync::spawn_blocking(move || {
let data = &*zero_copy;
let algorithm = args.algorithm;
@ -264,7 +300,7 @@ pub async fn op_crypto_sign_key(
Algorithm::RsassaPkcs1v15 => {
use rsa::pkcs1v15::SigningKey;
let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?;
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let signing_key = SigningKey::<Sha1>::new(private_key);
signing_key.sign(data)
@ -289,11 +325,11 @@ pub async fn op_crypto_sign_key(
let salt_len = args
.salt_length
.ok_or_else(|| Error::MissingArgumentSaltLength)?
.ok_or_else(|| CryptoError::MissingArgumentSaltLength)?
as usize;
let mut rng = OsRng;
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let signing_key = Pss::new_with_salt::<Sha1>(salt_len);
let hashed = Sha1::digest(data);
@ -320,7 +356,7 @@ pub async fn op_crypto_sign_key(
Algorithm::Ecdsa => {
let curve: &EcdsaSigningAlgorithm = args
.named_curve
.ok_or_else(|| Error::Other(not_supported()))?
.ok_or_else(JsErrorBox::not_supported)?
.into();
let rng = RingRand::SystemRandom::new();
@ -330,7 +366,7 @@ pub async fn op_crypto_sign_key(
if let Some(hash) = args.hash {
match hash {
CryptoHash::Sha256 | CryptoHash::Sha384 => (),
_ => return Err(Error::UnsupportedAlgorithm),
_ => return Err(CryptoError::UnsupportedAlgorithm),
}
};
@ -340,17 +376,15 @@ pub async fn op_crypto_sign_key(
signature.as_ref().to_vec()
}
Algorithm::Hmac => {
let hash: HmacAlgorithm = args
.hash
.ok_or_else(|| Error::Other(not_supported()))?
.into();
let hash: HmacAlgorithm =
args.hash.ok_or_else(JsErrorBox::not_supported)?.into();
let key = HmacKey::new(hash, &args.key.data);
let signature = ring::hmac::sign(&key, data);
signature.as_ref().to_vec()
}
_ => return Err(Error::UnsupportedAlgorithm),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
Ok(signature.into())
@ -373,7 +407,7 @@ pub struct VerifyArg {
pub async fn op_crypto_verify_key(
#[serde] args: VerifyArg,
#[buffer] zero_copy: JsBuffer,
) -> Result<bool, Error> {
) -> Result<bool, CryptoError> {
deno_core::unsync::spawn_blocking(move || {
let data = &*zero_copy;
let algorithm = args.algorithm;
@ -384,7 +418,7 @@ pub async fn op_crypto_verify_key(
use rsa::pkcs1v15::VerifyingKey;
let public_key = read_rsa_public_key(args.key)?;
let signature: Signature = args.signature.as_ref().try_into()?;
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let verifying_key = VerifyingKey::<Sha1>::new(public_key);
verifying_key.verify(data, &signature).is_ok()
@ -409,10 +443,10 @@ pub async fn op_crypto_verify_key(
let salt_len = args
.salt_length
.ok_or_else(|| Error::MissingArgumentSaltLength)?
.ok_or_else(|| CryptoError::MissingArgumentSaltLength)?
as usize;
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let pss = Pss::new_with_salt::<Sha1>(salt_len);
let hashed = Sha1::digest(data);
@ -436,21 +470,19 @@ pub async fn op_crypto_verify_key(
}
}
Algorithm::Hmac => {
let hash: HmacAlgorithm = args
.hash
.ok_or_else(|| Error::Other(not_supported()))?
.into();
let hash: HmacAlgorithm =
args.hash.ok_or_else(JsErrorBox::not_supported)?.into();
let key = HmacKey::new(hash, &args.key.data);
ring::hmac::verify(&key, data, &args.signature).is_ok()
}
Algorithm::Ecdsa => {
let signing_alg: &EcdsaSigningAlgorithm = args
.named_curve
.ok_or_else(|| Error::Other(not_supported()))?
.ok_or_else(JsErrorBox::not_supported)?
.into();
let verify_alg: &EcdsaVerificationAlgorithm = args
.named_curve
.ok_or_else(|| Error::Other(not_supported()))?
.ok_or_else(JsErrorBox::not_supported)?
.into();
let private_key;
@ -464,7 +496,7 @@ pub async fn op_crypto_verify_key(
private_key.public_key().as_ref()
}
KeyType::Public => &*args.key.data,
_ => return Err(Error::InvalidKeyFormat),
_ => return Err(CryptoError::InvalidKeyFormat),
};
let public_key =
@ -472,7 +504,7 @@ pub async fn op_crypto_verify_key(
public_key.verify(data, &args.signature).is_ok()
}
_ => return Err(Error::UnsupportedAlgorithm),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
Ok(verification)
@ -500,31 +532,27 @@ pub struct DeriveKeyArg {
pub async fn op_crypto_derive_bits(
#[serde] args: DeriveKeyArg,
#[buffer] zero_copy: Option<JsBuffer>,
) -> Result<ToJsBuffer, Error> {
) -> Result<ToJsBuffer, CryptoError> {
deno_core::unsync::spawn_blocking(move || {
let algorithm = args.algorithm;
match algorithm {
Algorithm::Pbkdf2 => {
let zero_copy =
zero_copy.ok_or_else(|| Error::Other(not_supported()))?;
let zero_copy = zero_copy.ok_or_else(JsErrorBox::not_supported)?;
let salt = &*zero_copy;
// The caller must validate these cases.
assert!(args.length > 0);
assert!(args.length % 8 == 0);
let algorithm =
match args.hash.ok_or_else(|| Error::Other(not_supported()))? {
CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
};
let algorithm = match args.hash.ok_or_else(JsErrorBox::not_supported)? {
CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
};
// This will never panic. We have already checked length earlier.
let iterations = NonZeroU32::new(
args
.iterations
.ok_or_else(|| Error::Other(not_supported()))?,
args.iterations.ok_or_else(JsErrorBox::not_supported)?,
)
.unwrap();
let secret = args.key.data;
@ -535,33 +563,33 @@ pub async fn op_crypto_derive_bits(
Algorithm::Ecdh => {
let named_curve = args
.named_curve
.ok_or_else(|| Error::MissingArgumentNamedCurve)?;
.ok_or_else(|| CryptoError::MissingArgumentNamedCurve)?;
let public_key = args
.public_key
.ok_or_else(|| Error::MissingArgumentPublicKey)?;
.ok_or_else(|| CryptoError::MissingArgumentPublicKey)?;
match named_curve {
CryptoNamedCurve::P256 => {
let secret_key = p256::SecretKey::from_pkcs8_der(&args.key.data)
.map_err(|_| Error::DecodePrivateKey)?;
.map_err(|_| CryptoError::DecodePrivateKey)?;
let public_key = match public_key.r#type {
KeyType::Private => {
p256::SecretKey::from_pkcs8_der(&public_key.data)
.map_err(|_| Error::DecodePrivateKey)?
.map_err(|_| CryptoError::DecodePrivateKey)?
.public_key()
}
KeyType::Public => {
let point = p256::EncodedPoint::from_bytes(public_key.data)
.map_err(|_| Error::DecodePrivateKey)?;
.map_err(|_| CryptoError::DecodePrivateKey)?;
let pk = p256::PublicKey::from_encoded_point(&point);
// pk is a constant time Option.
if pk.is_some().into() {
pk.unwrap()
} else {
return Err(Error::DecodePrivateKey);
return Err(CryptoError::DecodePrivateKey);
}
}
_ => unreachable!(),
@ -577,24 +605,24 @@ pub async fn op_crypto_derive_bits(
}
CryptoNamedCurve::P384 => {
let secret_key = p384::SecretKey::from_pkcs8_der(&args.key.data)
.map_err(|_| Error::DecodePrivateKey)?;
.map_err(|_| CryptoError::DecodePrivateKey)?;
let public_key = match public_key.r#type {
KeyType::Private => {
p384::SecretKey::from_pkcs8_der(&public_key.data)
.map_err(|_| Error::DecodePrivateKey)?
.map_err(|_| CryptoError::DecodePrivateKey)?
.public_key()
}
KeyType::Public => {
let point = p384::EncodedPoint::from_bytes(public_key.data)
.map_err(|_| Error::DecodePrivateKey)?;
.map_err(|_| CryptoError::DecodePrivateKey)?;
let pk = p384::PublicKey::from_encoded_point(&point);
// pk is a constant time Option.
if pk.is_some().into() {
pk.unwrap()
} else {
return Err(Error::DecodePrivateKey);
return Err(CryptoError::DecodePrivateKey);
}
}
_ => unreachable!(),
@ -611,18 +639,16 @@ pub async fn op_crypto_derive_bits(
}
}
Algorithm::Hkdf => {
let zero_copy =
zero_copy.ok_or_else(|| Error::Other(not_supported()))?;
let zero_copy = zero_copy.ok_or_else(JsErrorBox::not_supported)?;
let salt = &*zero_copy;
let algorithm =
match args.hash.ok_or_else(|| Error::Other(not_supported()))? {
CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
CryptoHash::Sha256 => hkdf::HKDF_SHA256,
CryptoHash::Sha384 => hkdf::HKDF_SHA384,
CryptoHash::Sha512 => hkdf::HKDF_SHA512,
};
let algorithm = match args.hash.ok_or_else(JsErrorBox::not_supported)? {
CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
CryptoHash::Sha256 => hkdf::HKDF_SHA256,
CryptoHash::Sha384 => hkdf::HKDF_SHA384,
CryptoHash::Sha512 => hkdf::HKDF_SHA512,
};
let info = args.info.ok_or_else(|| Error::MissingArgumentInfo)?;
let info = args.info.ok_or(CryptoError::MissingArgumentInfo)?;
// IKM
let secret = args.key.data;
// L
@ -633,18 +659,18 @@ pub async fn op_crypto_derive_bits(
let info = &[&*info];
let okm = prk
.expand(info, HkdfOutput(length))
.map_err(|_e| Error::HKDFLengthTooLarge)?;
.map_err(|_e| CryptoError::HKDFLengthTooLarge)?;
let mut r = vec![0u8; length];
okm.fill(&mut r)?;
Ok(r.into())
}
_ => Err(Error::UnsupportedAlgorithm),
_ => Err(CryptoError::UnsupportedAlgorithm),
}
})
.await?
}
fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, Error> {
fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, CryptoError> {
let public_key = match key_data.r#type {
KeyType::Private => {
RsaPrivateKey::from_pkcs1_der(&key_data.data)?.to_public_key()
@ -657,7 +683,9 @@ fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, Error> {
#[op2]
#[string]
pub fn op_crypto_random_uuid(state: &mut OpState) -> Result<String, Error> {
pub fn op_crypto_random_uuid(
state: &mut OpState,
) -> Result<String, CryptoError> {
let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
let uuid = if let Some(seeded_rng) = maybe_seeded_rng {
let mut bytes = [0u8; 16];
@ -678,7 +706,7 @@ pub fn op_crypto_random_uuid(state: &mut OpState) -> Result<String, Error> {
pub async fn op_crypto_subtle_digest(
#[serde] algorithm: CryptoHash,
#[buffer] data: JsBuffer,
) -> Result<ToJsBuffer, Error> {
) -> Result<ToJsBuffer, CryptoError> {
let output = spawn_blocking(move || {
digest::digest(algorithm.into(), &data)
.as_ref()
@ -702,7 +730,7 @@ pub struct WrapUnwrapKeyArg {
pub fn op_crypto_wrap_key(
#[serde] args: WrapUnwrapKeyArg,
#[buffer] data: JsBuffer,
) -> Result<ToJsBuffer, Error> {
) -> Result<ToJsBuffer, CryptoError> {
let algorithm = args.algorithm;
match algorithm {
@ -710,20 +738,20 @@ pub fn op_crypto_wrap_key(
let key = args.key.as_secret_key()?;
if data.len() % 8 != 0 {
return Err(Error::DataInvalidSize);
return Err(CryptoError::DataInvalidSize);
}
let wrapped_key = match key.len() {
16 => KekAes128::new(key.into()).wrap_vec(&data),
24 => KekAes192::new(key.into()).wrap_vec(&data),
32 => KekAes256::new(key.into()).wrap_vec(&data),
_ => return Err(Error::InvalidKeyLength),
_ => return Err(CryptoError::InvalidKeyLength),
}
.map_err(|_| Error::EncryptionError)?;
.map_err(|_| CryptoError::EncryptionError)?;
Ok(wrapped_key.into())
}
_ => Err(Error::UnsupportedAlgorithm),
_ => Err(CryptoError::UnsupportedAlgorithm),
}
}
@ -732,27 +760,27 @@ pub fn op_crypto_wrap_key(
pub fn op_crypto_unwrap_key(
#[serde] args: WrapUnwrapKeyArg,
#[buffer] data: JsBuffer,
) -> Result<ToJsBuffer, Error> {
) -> Result<ToJsBuffer, CryptoError> {
let algorithm = args.algorithm;
match algorithm {
Algorithm::AesKw => {
let key = args.key.as_secret_key()?;
if data.len() % 8 != 0 {
return Err(Error::DataInvalidSize);
return Err(CryptoError::DataInvalidSize);
}
let unwrapped_key = match key.len() {
16 => KekAes128::new(key.into()).unwrap_vec(&data),
24 => KekAes192::new(key.into()).unwrap_vec(&data),
32 => KekAes256::new(key.into()).unwrap_vec(&data),
_ => return Err(Error::InvalidKeyLength),
_ => return Err(CryptoError::InvalidKeyLength),
}
.map_err(|_| Error::DecryptionError)?;
.map_err(|_| CryptoError::DecryptionError)?;
Ok(unwrapped_key.into())
}
_ => Err(Error::UnsupportedAlgorithm),
_ => Err(CryptoError::UnsupportedAlgorithm),
}
}

View file

@ -60,26 +60,36 @@ pub enum RustRawKeyData {
Public(ToJsBuffer),
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum SharedError {
#[class(type)]
#[error("expected valid private key")]
ExpectedValidPrivateKey,
#[class(type)]
#[error("expected valid public key")]
ExpectedValidPublicKey,
#[class(type)]
#[error("expected valid private EC key")]
ExpectedValidPrivateECKey,
#[class(type)]
#[error("expected valid public EC key")]
ExpectedValidPublicECKey,
#[class(type)]
#[error("expected private key")]
ExpectedPrivateKey,
#[class(type)]
#[error("expected public key")]
ExpectedPublicKey,
#[class(type)]
#[error("expected secret key")]
ExpectedSecretKey,
#[class("DOMExceptionOperationError")]
#[error("failed to decode private key")]
FailedDecodePrivateKey,
#[class("DOMExceptionOperationError")]
#[error("failed to decode public key")]
FailedDecodePublicKey,
#[class("DOMExceptionNotSupportedError")]
#[error("unsupported format")]
UnsupportedFormat,
}

View file

@ -11,10 +11,12 @@ use spki::der::asn1::BitString;
use spki::der::Decode;
use spki::der::Encode;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum X25519Error {
#[class("DOMExceptionOperationError")]
#[error("Failed to export key")]
FailedExport,
#[class(generic)]
#[error(transparent)]
Der(#[from] spki::der::Error),
}

View file

@ -12,10 +12,12 @@ use spki::der::asn1::BitString;
use spki::der::Decode;
use spki::der::Encode;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum X448Error {
#[class("DOMExceptionOperationError")]
#[error("Failed to export key")]
FailedExport,
#[class(generic)]
#[error(transparent)]
Der(#[from] spki::der::Error),
}

View file

@ -18,6 +18,7 @@ base64.workspace = true
bytes.workspace = true
data-url.workspace = true
deno_core.workspace = true
deno_error.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_tls.workspace = true

View file

@ -8,6 +8,7 @@ use deno_core::futures::TryStreamExt;
use deno_core::url::Url;
use deno_core::CancelFuture;
use deno_core::OpState;
use deno_error::JsErrorBox;
use http::StatusCode;
use http_body_util::BodyExt;
use tokio_util::io::ReaderStream;
@ -34,7 +35,7 @@ impl FetchHandler for FsFetchHandler {
let file = tokio::fs::File::open(path).map_err(|_| ()).await?;
let stream = ReaderStream::new(file)
.map_ok(hyper::body::Frame::data)
.map_err(Into::into);
.map_err(JsErrorBox::from_err);
let body = http_body_util::StreamBody::new(stream).boxed();
let response = http::Response::builder()
.status(StatusCode::OK)

View file

@ -46,6 +46,7 @@ use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_error::JsErrorBox;
use deno_path_util::url_from_file_path;
use deno_path_util::PathToUrlError;
use deno_permissions::PermissionCheckError;
@ -100,9 +101,8 @@ pub struct Options {
/// For more info on what can be configured, see [`hyper_util::client::legacy::Builder`].
pub client_builder_hook: Option<fn(HyperClientBuilder) -> HyperClientBuilder>,
#[allow(clippy::type_complexity)]
pub request_builder_hook: Option<
fn(&mut http::Request<ReqBody>) -> Result<(), deno_core::error::AnyError>,
>,
pub request_builder_hook:
Option<fn(&mut http::Request<ReqBody>) -> Result<(), JsErrorBox>>,
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub client_cert_chain_and_key: TlsKeys,
pub file_fetch_handler: Rc<dyn FetchHandler>,
@ -110,9 +110,7 @@ pub struct Options {
}
impl Options {
pub fn root_cert_store(
&self,
) -> Result<Option<RootCertStore>, deno_core::error::AnyError> {
pub fn root_cert_store(&self) -> Result<Option<RootCertStore>, JsErrorBox> {
Ok(match &self.root_cert_store_provider {
Some(provider) => Some(provider.get_or_try_init()?.clone()),
None => None,
@ -164,48 +162,71 @@ deno_core::extension!(deno_fetch,
},
);
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum FetchError {
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)]
Permission(#[from] PermissionCheckError),
#[class(type)]
#[error("NetworkError when attempting to fetch resource")]
NetworkError,
#[class(type)]
#[error("Fetching files only supports the GET method: received {0}")]
FsNotGet(Method),
#[class(inherit)]
#[error(transparent)]
PathToUrl(#[from] PathToUrlError),
#[class(type)]
#[error("Invalid URL {0}")]
InvalidUrl(Url),
#[class(type)]
#[error(transparent)]
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
#[class(type)]
#[error(transparent)]
InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
#[class(type)]
#[error("{0:?}")]
DataUrl(data_url::DataUrlError),
#[class(type)]
#[error("{0:?}")]
Base64(data_url::forgiving_base64::InvalidBase64),
#[class(type)]
#[error("Blob for the given URL not found.")]
BlobNotFound,
#[class(type)]
#[error("Url scheme '{0}' not supported")]
SchemeNotSupported(String),
#[class(type)]
#[error("Request was cancelled")]
RequestCanceled,
#[class(generic)]
#[error(transparent)]
Http(#[from] http::Error),
#[class(inherit)]
#[error(transparent)]
ClientCreate(#[from] HttpClientCreateError),
#[class(inherit)]
#[error(transparent)]
Url(#[from] url::ParseError),
#[class(type)]
#[error(transparent)]
Method(#[from] http::method::InvalidMethod),
#[class(inherit)]
#[error(transparent)]
ClientSend(#[from] ClientSendError),
#[class(inherit)]
#[error(transparent)]
RequestBuilderHook(deno_core::error::AnyError),
RequestBuilderHook(JsErrorBox),
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
#[class(generic)]
#[error(transparent)]
Dns(hickory_resolver::ResolveError),
}
pub type CancelableResponseFuture =
@ -294,9 +315,7 @@ pub fn create_client_from_options(
#[allow(clippy::type_complexity)]
pub struct ResourceToBodyAdapter(
Rc<dyn Resource>,
Option<
Pin<Box<dyn Future<Output = Result<BufView, deno_core::error::AnyError>>>>,
>,
Option<Pin<Box<dyn Future<Output = Result<BufView, JsErrorBox>>>>>,
);
impl ResourceToBodyAdapter {
@ -312,7 +331,7 @@ unsafe impl Send for ResourceToBodyAdapter {}
unsafe impl Sync for ResourceToBodyAdapter {}
impl Stream for ResourceToBodyAdapter {
type Item = Result<Bytes, deno_core::error::AnyError>;
type Item = Result<Bytes, JsErrorBox>;
fn poll_next(
self: Pin<&mut Self>,
@ -342,7 +361,7 @@ impl Stream for ResourceToBodyAdapter {
impl hyper::body::Body for ResourceToBodyAdapter {
type Data = Bytes;
type Error = deno_core::error::AnyError;
type Error = JsErrorBox;
fn poll_frame(
self: Pin<&mut Self>,
@ -417,10 +436,7 @@ where
FP: FetchPermissions + 'static,
{
let (client, allow_host) = if let Some(rid) = client_rid {
let r = state
.resource_table
.get::<HttpClientResource>(rid)
.map_err(FetchError::Resource)?;
let r = state.resource_table.get::<HttpClientResource>(rid)?;
(r.client.clone(), r.allow_host)
} else {
(get_or_create_client_from_state(state)?, false)
@ -479,10 +495,7 @@ where
ReqBody::full(data.to_vec().into())
}
(_, Some(resource)) => {
let resource = state
.resource_table
.take_any(resource)
.map_err(FetchError::Resource)?;
let resource = state.resource_table.take_any(resource)?;
match resource.size_hint() {
(body_size, Some(n)) if body_size == n && body_size > 0 => {
con_len = Some(body_size);
@ -624,8 +637,7 @@ pub async fn op_fetch_send(
let request = state
.borrow_mut()
.resource_table
.take::<FetchRequestResource>(rid)
.map_err(FetchError::Resource)?;
.take::<FetchRequestResource>(rid)?;
let request = Rc::try_unwrap(request)
.ok()
@ -804,9 +816,7 @@ impl Resource for FetchResponseResource {
// safely call `await` on it without creating a race condition.
Some(_) => match reader.as_mut().next().await.unwrap() {
Ok(chunk) => assert!(chunk.is_empty()),
Err(err) => {
break Err(deno_core::error::type_error(err.to_string()))
}
Err(err) => break Err(JsErrorBox::type_error(err.to_string())),
},
None => break Ok(BufView::empty()),
}
@ -814,7 +824,10 @@ impl Resource for FetchResponseResource {
};
let cancel_handle = RcRef::map(self, |r| &r.cancel);
fut.try_or_cancel(cancel_handle).await
fut
.try_or_cancel(cancel_handle)
.await
.map_err(JsErrorBox::from_err)
})
}
@ -897,9 +910,7 @@ where
ca_certs,
proxy: args.proxy,
dns_resolver: if args.use_hickory_resolver {
dns::Resolver::hickory()
.map_err(deno_core::error::AnyError::new)
.map_err(FetchError::Resource)?
dns::Resolver::hickory().map_err(FetchError::Dns)?
} else {
dns::Resolver::default()
},
@ -963,7 +974,8 @@ impl Default for CreateHttpClientOptions {
}
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(type)]
pub enum HttpClientCreateError {
#[error(transparent)]
Tls(deno_tls::TlsError),
@ -973,8 +985,9 @@ pub enum HttpClientCreateError {
InvalidProxyUrl,
#[error("Cannot create Http Client: either `http1` or `http2` needs to be set to true")]
HttpVersionSelectionInvalid,
#[class(inherit)]
#[error(transparent)]
RootCertStore(deno_core::error::AnyError),
RootCertStore(JsErrorBox),
}
/// Create new instance of async Client. This client supports
@ -1097,7 +1110,8 @@ type Connector = proxy::ProxyConnector<HttpConnector<dns::Resolver>>;
#[allow(clippy::declare_interior_mutable_const)]
const STAR_STAR: HeaderValue = HeaderValue::from_static("*/*");
#[derive(Debug)]
#[derive(Debug, deno_error::JsError)]
#[class(type)]
pub struct ClientSendError {
uri: Uri,
pub source: hyper_util::client::legacy::Error,
@ -1172,7 +1186,7 @@ impl Client {
.oneshot(req)
.await
.map_err(|e| ClientSendError { uri, source: e })?;
Ok(resp.map(|b| b.map_err(|e| deno_core::anyhow::anyhow!(e)).boxed()))
Ok(resp.map(|b| b.map_err(|e| JsErrorBox::generic(e.to_string())).boxed()))
}
}
@ -1180,10 +1194,10 @@ impl Client {
pub enum ReqBody {
Full(http_body_util::Full<Bytes>),
Empty(http_body_util::Empty<Bytes>),
Streaming(BoxBody<Bytes, deno_core::error::AnyError>),
Streaming(BoxBody<Bytes, JsErrorBox>),
}
pub type ResBody = BoxBody<Bytes, deno_core::error::AnyError>;
pub type ResBody = BoxBody<Bytes, JsErrorBox>;
impl ReqBody {
pub fn full(bytes: Bytes) -> Self {
@ -1196,7 +1210,7 @@ impl ReqBody {
pub fn streaming<B>(body: B) -> Self
where
B: hyper::body::Body<Data = Bytes, Error = deno_core::error::AnyError>
B: hyper::body::Body<Data = Bytes, Error = JsErrorBox>
+ Send
+ Sync
+ 'static,
@ -1207,7 +1221,7 @@ impl ReqBody {
impl hyper::body::Body for ReqBody {
type Data = Bytes;
type Error = deno_core::error::AnyError;
type Error = JsErrorBox;
fn poll_frame(
mut self: Pin<&mut Self>,

View file

@ -15,6 +15,7 @@ path = "lib.rs"
[dependencies]
deno_core.workspace = true
deno_error.workspace = true
deno_permissions.workspace = true
dlopen2.workspace = true
dynasmrt = "1.2.3"

View file

@ -25,18 +25,24 @@ use crate::symbol::Symbol;
use crate::FfiPermissions;
use crate::ForeignFunction;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CallError {
#[class(type)]
#[error(transparent)]
IR(#[from] IRError),
#[class(generic)]
#[error("Nonblocking FFI call failed: {0}")]
NonblockingCallFailure(#[source] tokio::task::JoinError),
#[class(type)]
#[error("Invalid FFI symbol name: '{0}'")]
InvalidSymbol(String),
#[class(inherit)]
#[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError),
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)]
Callback(#[from] super::CallbackError),
}
@ -346,10 +352,7 @@ pub fn op_ffi_call_nonblocking(
) -> Result<impl Future<Output = Result<FfiValue, CallError>>, CallError> {
let symbol = {
let state = state.borrow();
let resource = state
.resource_table
.get::<DynamicLibraryResource>(rid)
.map_err(CallError::Resource)?;
let resource = state.resource_table.get::<DynamicLibraryResource>(rid)?;
let symbols = &resource.symbols;
*symbols
.get(&symbol)

View file

@ -35,14 +35,17 @@ thread_local! {
static LOCAL_THREAD_ID: RefCell<u32> = const { RefCell::new(0) };
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CallbackError {
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(#[from] deno_error::JsErrorBox),
}
#[derive(Clone)]
@ -63,13 +66,8 @@ impl PtrSymbol {
.clone()
.into_iter()
.map(libffi::middle::Type::try_from)
.collect::<Result<Vec<_>, _>>()
.map_err(CallbackError::Other)?,
def
.result
.clone()
.try_into()
.map_err(CallbackError::Other)?,
.collect::<Result<Vec<_>, _>>()?,
def.result.clone().try_into()?,
);
Ok(Self { cif, ptr })
@ -540,10 +538,8 @@ pub fn op_ffi_unsafe_callback_ref(
#[smi] rid: ResourceId,
) -> Result<impl Future<Output = ()>, CallbackError> {
let state = state.borrow();
let callback_resource = state
.resource_table
.get::<UnsafeCallbackResource>(rid)
.map_err(CallbackError::Resource)?;
let callback_resource =
state.resource_table.get::<UnsafeCallbackResource>(rid)?;
Ok(async move {
let info: &mut CallbackInfo =
@ -610,10 +606,8 @@ where
.parameters
.into_iter()
.map(libffi::middle::Type::try_from)
.collect::<Result<Vec<_>, _>>()
.map_err(CallbackError::Other)?,
libffi::middle::Type::try_from(args.result)
.map_err(CallbackError::Other)?,
.collect::<Result<Vec<_>, _>>()?,
libffi::middle::Type::try_from(args.result)?,
);
// SAFETY: CallbackInfo is leaked, is not null and stays valid as long as the callback exists.
@ -649,10 +643,8 @@ pub fn op_ffi_unsafe_callback_close(
// It is up to the user to know that it is safe to call the `close()` on the
// UnsafeCallback instance.
unsafe {
let callback_resource = state
.resource_table
.take::<UnsafeCallbackResource>(rid)
.map_err(CallbackError::Resource)?;
let callback_resource =
state.resource_table.take::<UnsafeCallbackResource>(rid)?;
let info = Box::from_raw(callback_resource.info);
let _ = v8::Global::from_raw(scope, info.callback);
let _ = v8::Global::from_raw(scope, info.context);

View file

@ -11,6 +11,8 @@ use deno_core::v8;
use deno_core::GarbageCollected;
use deno_core::OpState;
use deno_core::Resource;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
use dlopen2::raw::Library;
use serde::Deserialize;
use serde_value::ValueDeserializer;
@ -22,20 +24,34 @@ use crate::turbocall;
use crate::turbocall::Turbocall;
use crate::FfiPermissions;
#[derive(Debug, thiserror::Error)]
deno_error::js_error_wrapper!(dlopen2::Error, JsDlopen2Error, |err| {
match err {
dlopen2::Error::NullCharacter(_) => "InvalidData".into(),
dlopen2::Error::OpeningLibraryError(e) => e.get_class(),
dlopen2::Error::SymbolGettingError(e) => e.get_class(),
dlopen2::Error::AddrNotMatchingDll(e) => e.get_class(),
dlopen2::Error::NullSymbol => "NotFound".into(),
}
});
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum DlfcnError {
#[class(generic)]
#[error("Failed to register symbol {symbol}: {error}")]
RegisterSymbol {
symbol: String,
#[source]
error: dlopen2::Error,
},
#[class(generic)]
#[error(transparent)]
Dlopen(#[from] dlopen2::Error),
#[class(inherit)]
#[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(#[from] JsErrorBox),
}
pub struct DynamicLibraryResource {
@ -190,13 +206,8 @@ where
.clone()
.into_iter()
.map(libffi::middle::Type::try_from)
.collect::<Result<Vec<_>, _>>()
.map_err(DlfcnError::Other)?,
foreign_fn
.result
.clone()
.try_into()
.map_err(DlfcnError::Other)?,
.collect::<Result<Vec<_>, _>>()?,
foreign_fn.result.clone().try_into()?,
);
let func_key = v8::String::new(scope, &symbol_key).unwrap();
@ -304,9 +315,7 @@ fn sync_fn_impl<'s>(
unsafe { result.to_v8(scope, data.symbol.result_type.clone()) };
rv.set(result);
}
Err(err) => {
deno_core::_ops::throw_type_error(scope, err.to_string());
}
Err(err) => deno_core::error::throw_js_error_class(scope, &err),
};
}

View file

@ -8,7 +8,8 @@ use libffi::middle::Arg;
use crate::symbol::NativeType;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(type)]
pub enum IRError {
#[error("Invalid FFI u8 type, expected boolean")]
InvalidU8ExpectedBoolean,

View file

@ -11,7 +11,8 @@ use deno_core::OpState;
use crate::FfiPermissions;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(type)]
pub enum ReprError {
#[error("Invalid pointer to offset, pointer is null")]
InvalidOffset,
@ -47,6 +48,7 @@ pub enum ReprError {
InvalidF64,
#[error("Invalid pointer pointer, pointer is null")]
InvalidPointer,
#[class(inherit)]
#[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError),
}

View file

@ -10,16 +10,20 @@ use deno_core::ResourceId;
use crate::dlfcn::DynamicLibraryResource;
use crate::symbol::NativeType;
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum StaticError {
#[class(inherit)]
#[error(transparent)]
Dlfcn(super::DlfcnError),
#[class(type)]
#[error("Invalid FFI static type 'void'")]
InvalidTypeVoid,
#[class(type)]
#[error("Invalid FFI static type 'struct'")]
InvalidTypeStruct,
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
}
#[op2]
@ -31,10 +35,7 @@ pub fn op_ffi_get_static<'scope>(
#[serde] static_type: NativeType,
optional: bool,
) -> Result<v8::Local<'scope, v8::Value>, StaticError> {
let resource = state
.resource_table
.get::<DynamicLibraryResource>(rid)
.map_err(StaticError::Resource)?;
let resource = state.resource_table.get::<DynamicLibraryResource>(rid)?;
let data_ptr = match resource.get_static(name) {
Ok(data_ptr) => data_ptr,

View file

@ -1,7 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_error::JsErrorBox;
/// Defines the accepted types that can be used as
/// parameters and return values in FFI.
@ -29,7 +28,7 @@ pub enum NativeType {
}
impl TryFrom<NativeType> for libffi::middle::Type {
type Error = AnyError;
type Error = JsErrorBox;
fn try_from(native_type: NativeType) -> Result<Self, Self::Error> {
Ok(match native_type {
@ -56,7 +55,9 @@ impl TryFrom<NativeType> for libffi::middle::Type {
.map(|field| field.clone().try_into())
.collect::<Result<Vec<_>, _>>()?,
false => {
return Err(type_error("Struct must have at least one field"))
return Err(JsErrorBox::type_error(
"Struct must have at least one field",
))
}
})
}

View file

@ -21,6 +21,7 @@ async-trait.workspace = true
base32.workspace = true
boxed_error.workspace = true
deno_core.workspace = true
deno_error.workspace = true
deno_io.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true

View file

@ -12,6 +12,7 @@ use std::path::StripPrefixError;
use std::rc::Rc;
use boxed_error::Boxed;
use deno_core::error::ResourceError;
use deno_core::op2;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
@ -20,6 +21,7 @@ use deno_core::JsBuffer;
use deno_core::OpState;
use deno_core::ResourceId;
use deno_core::ToJsBuffer;
use deno_error::JsErrorBox;
use deno_io::fs::FileResource;
use deno_io::fs::FsError;
use deno_io::fs::FsStat;
@ -36,34 +38,46 @@ use crate::interface::FsFileType;
use crate::FsPermissions;
use crate::OpenOptions;
#[derive(Debug, Boxed)]
#[derive(Debug, Boxed, deno_error::JsError)]
pub struct FsOpsError(pub Box<FsOpsErrorKind>);
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum FsOpsErrorKind {
#[class(inherit)]
#[error("{0}")]
Io(#[source] std::io::Error),
#[class(inherit)]
#[error("{0}")]
OperationError(#[source] OperationError),
#[class(inherit)]
#[error(transparent)]
Permission(#[from] PermissionCheckError),
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] ResourceError),
#[class("InvalidData")]
#[error("File name or path {0:?} is not valid UTF-8")]
InvalidUtf8(std::ffi::OsString),
#[class(generic)]
#[error("{0}")]
StripPrefix(#[from] StripPrefixError),
#[class(inherit)]
#[error("{0}")]
Canceled(#[from] deno_core::Canceled),
#[class(type)]
#[error("Invalid seek mode: {0}")]
InvalidSeekMode(i32),
#[class(generic)]
#[error("Invalid control character in prefix or suffix: {0:?}")]
InvalidControlCharacter(String),
#[class(generic)]
#[error("Invalid character in prefix or suffix: {0:?}")]
InvalidCharacter(String),
#[cfg(windows)]
#[class(generic)]
#[error("Invalid trailing character in suffix")]
InvalidTrailingCharacter,
#[class("NotCapable")]
#[error("Requires {err} access to {path}, {}", print_not_capable_info(*.standalone, .err))]
NotCapableAccess {
// NotCapable
@ -71,21 +85,21 @@ pub enum FsOpsErrorKind {
err: &'static str,
path: String,
},
#[class("NotCapable")]
#[error("permission denied: {0}")]
NotCapable(&'static str), // NotCapable
NotCapable(&'static str),
#[class(inherit)]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(JsErrorBox),
}
impl From<FsError> for FsOpsError {
fn from(err: FsError) -> Self {
match err {
FsError::Io(err) => FsOpsErrorKind::Io(err),
FsError::FileBusy => {
FsOpsErrorKind::Other(deno_core::error::resource_unavailable())
}
FsError::FileBusy => FsOpsErrorKind::Resource(ResourceError::Unavailable),
FsError::NotSupported => {
FsOpsErrorKind::Other(deno_core::error::not_supported())
FsOpsErrorKind::Other(JsErrorBox::not_supported())
}
FsError::NotCapable(err) => FsOpsErrorKind::NotCapable(err),
}
@ -1666,10 +1680,12 @@ pub async fn op_fs_futime_async(
Ok(())
}
#[derive(Debug)]
#[derive(Debug, deno_error::JsError)]
#[class(inherit)]
pub struct OperationError {
operation: &'static str,
kind: OperationErrorKind,
#[inherit]
pub err: FsError,
}

View file

@ -28,6 +28,7 @@ brotli.workspace = true
bytes.workspace = true
cache_control.workspace = true
deno_core.workspace = true
deno_error.workspace = true
deno_net.workspace = true
deno_websocket.workspace = true
flate2.workspace = true

View file

@ -146,24 +146,44 @@ macro_rules! clone_external {
}};
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum HttpNextError {
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error("{0}")]
Io(#[from] io::Error),
#[class(inherit)]
#[error(transparent)]
WebSocketUpgrade(crate::websocket_upgrade::WebSocketUpgradeError),
#[class("Http")]
#[error("{0}")]
Hyper(#[from] hyper::Error),
#[class(inherit)]
#[error(transparent)]
JoinError(#[from] tokio::task::JoinError),
JoinError(
#[from]
#[inherit]
tokio::task::JoinError,
),
#[class(inherit)]
#[error(transparent)]
Canceled(#[from] deno_core::Canceled),
#[error(transparent)]
HttpPropertyExtractor(deno_core::error::AnyError),
Canceled(
#[from]
#[inherit]
deno_core::Canceled,
),
#[class(generic)]
#[error(transparent)]
UpgradeUnavailable(#[from] crate::service::UpgradeUnavailableError),
#[class(inherit)]
#[error("{0}")]
Other(
#[from]
#[inherit]
deno_error::JsErrorBox,
),
}
#[op2(fast)]
@ -747,15 +767,9 @@ pub async fn op_http_set_response_body_resource(
let resource = {
let mut state = state.borrow_mut();
if auto_close {
state
.resource_table
.take_any(stream_rid)
.map_err(HttpNextError::Resource)?
state.resource_table.take_any(stream_rid)?
} else {
state
.resource_table
.get_any(stream_rid)
.map_err(HttpNextError::Resource)?
state.resource_table.get_any(stream_rid)?
}
};
@ -1063,8 +1077,7 @@ where
HTTP: HttpPropertyExtractor,
{
let listener =
HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid)
.map_err(HttpNextError::Resource)?;
HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid)?;
let listen_properties = HTTP::listen_properties_from_listener(&listener)?;
@ -1084,8 +1097,7 @@ where
loop {
let conn = HTTP::accept_connection_from_listener(&listener)
.try_or_cancel(listen_cancel_clone.clone())
.await
.map_err(HttpNextError::HttpPropertyExtractor)?;
.await?;
serve_http_on::<HTTP>(
conn,
&listen_properties_clone,
@ -1120,8 +1132,7 @@ where
HTTP: HttpPropertyExtractor,
{
let connection =
HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid)
.map_err(HttpNextError::Resource)?;
HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid)?;
let listen_properties = HTTP::listen_properties_from_connection(&connection)?;
@ -1190,8 +1201,7 @@ pub async fn op_http_wait(
let join_handle = state
.borrow_mut()
.resource_table
.get::<HttpJoinHandle>(rid)
.map_err(HttpNextError::Resource)?;
.get::<HttpJoinHandle>(rid)?;
let cancel = join_handle.listen_cancel_handle();
let next = async {
@ -1236,7 +1246,7 @@ pub fn op_http_cancel(
state: &mut OpState,
#[smi] rid: ResourceId,
graceful: bool,
) -> Result<(), deno_core::error::AnyError> {
) -> Result<(), deno_core::error::ResourceError> {
let join_handle = state.resource_table.get::<HttpJoinHandle>(rid)?;
if graceful {
@ -1260,8 +1270,7 @@ pub async fn op_http_close(
let join_handle = state
.borrow_mut()
.resource_table
.take::<HttpJoinHandle>(rid)
.map_err(HttpNextError::Resource)?;
.take::<HttpJoinHandle>(rid)?;
if graceful {
http_general_trace!("graceful shutdown");
@ -1390,11 +1399,8 @@ pub async fn op_raw_write_vectored(
#[buffer] buf1: JsBuffer,
#[buffer] buf2: JsBuffer,
) -> Result<usize, HttpNextError> {
let resource: Rc<UpgradeStream> = state
.borrow()
.resource_table
.get::<UpgradeStream>(rid)
.map_err(HttpNextError::Resource)?;
let resource: Rc<UpgradeStream> =
state.borrow().resource_table.get::<UpgradeStream>(rid)?;
let nwritten = resource.write_vectored(&buf1, &buf2).await?;
Ok(nwritten)
}

View file

@ -51,6 +51,7 @@ use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::StringOrBuffer;
use deno_error::JsErrorBox;
use deno_net::raw::NetworkStream;
use deno_websocket::ws_create_server_stream;
use flate2::write::GzEncoder;
@ -165,36 +166,50 @@ deno_core::extension!(
}
);
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum HttpError {
#[class(inherit)]
#[error(transparent)]
Resource(deno_core::error::AnyError),
Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)]
Canceled(#[from] deno_core::Canceled),
#[class("Http")]
#[error("{0}")]
HyperV014(#[source] Arc<hyper_v014::Error>),
#[class(generic)]
#[error("{0}")]
InvalidHeaderName(#[from] hyper_v014::header::InvalidHeaderName),
#[class(generic)]
#[error("{0}")]
InvalidHeaderValue(#[from] hyper_v014::header::InvalidHeaderValue),
#[class(generic)]
#[error("{0}")]
Http(#[from] hyper_v014::http::Error),
#[class("Http")]
#[error("response headers already sent")]
ResponseHeadersAlreadySent,
#[class("Http")]
#[error("connection closed while sending response")]
ConnectionClosedWhileSendingResponse,
#[class("Http")]
#[error("already in use")]
AlreadyInUse,
#[class(inherit)]
#[error("{0}")]
Io(#[from] std::io::Error),
#[class("Http")]
#[error("no response headers")]
NoResponseHeaders,
#[class("Http")]
#[error("response already completed")]
ResponseAlreadyCompleted,
#[class("Http")]
#[error("cannot upgrade because request body was used")]
UpgradeBodyUsed,
#[class("Http")]
#[error(transparent)]
Other(deno_core::error::AnyError),
Other(#[from] JsErrorBox),
}
pub enum HttpSocketAddr {
@ -486,7 +501,9 @@ impl Resource for HttpStreamReadResource {
Some(_) => match body.as_mut().next().await.unwrap() {
Ok(chunk) => assert!(chunk.is_empty()),
Err(err) => {
break Err(HttpError::HyperV014(Arc::new(err)).into())
break Err(JsErrorBox::from_err(HttpError::HyperV014(
Arc::new(err),
)))
}
},
None => break Ok(BufView::empty()),
@ -610,11 +627,7 @@ async fn op_http_accept(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
) -> Result<Option<NextRequestResponse>, HttpError> {
let conn = state
.borrow()
.resource_table
.get::<HttpConnResource>(rid)
.map_err(HttpError::Resource)?;
let conn = state.borrow().resource_table.get::<HttpConnResource>(rid)?;
match conn.accept().await {
Ok(Some((read_stream, write_stream, method, url))) => {
@ -729,8 +742,7 @@ async fn op_http_write_headers(
let stream = state
.borrow_mut()
.resource_table
.get::<HttpStreamWriteResource>(rid)
.map_err(HttpError::Resource)?;
.get::<HttpStreamWriteResource>(rid)?;
// Track supported encoding
let encoding = stream.accept_encoding;
@ -795,10 +807,7 @@ fn op_http_headers(
state: &mut OpState,
#[smi] rid: u32,
) -> Result<Vec<(ByteString, ByteString)>, HttpError> {
let stream = state
.resource_table
.get::<HttpStreamReadResource>(rid)
.map_err(HttpError::Resource)?;
let stream = state.resource_table.get::<HttpStreamReadResource>(rid)?;
let rd = RcRef::map(&stream, |r| &r.rd)
.try_borrow()
.ok_or(HttpError::AlreadyInUse)?;
@ -954,14 +963,9 @@ async fn op_http_write_resource(
let http_stream = state
.borrow()
.resource_table
.get::<HttpStreamWriteResource>(rid)
.map_err(HttpError::Resource)?;
.get::<HttpStreamWriteResource>(rid)?;
let mut wr = RcRef::map(&http_stream, |r| &r.wr).borrow_mut().await;
let resource = state
.borrow()
.resource_table
.get_any(stream)
.map_err(HttpError::Resource)?;
let resource = state.borrow().resource_table.get_any(stream)?;
loop {
match *wr {
HttpResponseWriter::Headers(_) => {
@ -973,11 +977,7 @@ async fn op_http_write_resource(
_ => {}
};
let view = resource
.clone()
.read(64 * 1024)
.await
.map_err(HttpError::Other)?; // 64KB
let view = resource.clone().read(64 * 1024).await?; // 64KB
if view.is_empty() {
break;
}
@ -1022,8 +1022,7 @@ async fn op_http_write(
let stream = state
.borrow()
.resource_table
.get::<HttpStreamWriteResource>(rid)
.map_err(HttpError::Resource)?;
.get::<HttpStreamWriteResource>(rid)?;
let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
match &mut *wr {
@ -1075,8 +1074,7 @@ async fn op_http_shutdown(
let stream = state
.borrow()
.resource_table
.get::<HttpStreamWriteResource>(rid)
.map_err(HttpError::Resource)?;
.get::<HttpStreamWriteResource>(rid)?;
let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
let wr = take(&mut *wr);
match wr {
@ -1122,8 +1120,7 @@ async fn op_http_upgrade_websocket(
let stream = state
.borrow_mut()
.resource_table
.get::<HttpStreamReadResource>(rid)
.map_err(HttpError::Resource)?;
.get::<HttpStreamReadResource>(rid)?;
let mut rd = RcRef::map(&stream, |r| &r.rd).borrow_mut().await;
let request = match &mut *rd {

Some files were not shown because too many files have changed in this diff Show more