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

View file

@ -48,10 +48,10 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies] [workspace.dependencies]
deno_ast = { version = "=0.44.0", features = ["transpiling"] } 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_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_lockfile = "=0.24.0"
deno_media_type = { version = "0.2.3", features = ["module_specifier"] } deno_media_type = { version = "0.2.3", features = ["module_specifier"] }
deno_npm = "=0.27.0" deno_npm = "=0.27.0"
@ -63,10 +63,10 @@ deno_terminal = "0.2.0"
napi_sym = { version = "0.114.0", path = "./ext/napi/sym" } napi_sym = { version = "0.114.0", path = "./ext/napi/sym" }
test_util = { package = "test_server", path = "./tests/util/server" } test_util = { package = "test_server", path = "./tests/util/server" }
denokv_proto = "0.8.4" denokv_proto = "0.9.0"
denokv_remote = "0.8.4" denokv_remote = "0.9.0"
# denokv_sqlite brings in bundled sqlite if we don't disable the default features # 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 # exts
deno_broadcast_channel = { version = "0.178.0", path = "./ext/broadcast_channel" } 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-encoding = "2.3.3"
data-url = "=0.3.1" data-url = "=0.3.1"
deno_cache_dir = "=0.16.0" 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_package_json = { version = "0.4.0", default-features = false }
deno_unsync = "0.4.2" deno_unsync = "0.4.2"
dlopen2 = "0.6.1" dlopen2 = "0.6.1"

View file

@ -62,6 +62,7 @@ serde_json.workspace = true
zstd.workspace = true zstd.workspace = true
glibc_version = "0.1.2" glibc_version = "0.1.2"
flate2 = { workspace = true, features = ["default"] } flate2 = { workspace = true, features = ["default"] }
deno_error.workspace = true
[target.'cfg(windows)'.build-dependencies] [target.'cfg(windows)'.build-dependencies]
winapi.workspace = true winapi.workspace = true
@ -72,9 +73,9 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposa
deno_cache_dir.workspace = true deno_cache_dir.workspace = true
deno_config.workspace = true deno_config.workspace = true
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } 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_error.workspace = true
deno_graph = { version = "=0.86.9" } deno_graph = { version = "=0.87.0" }
deno_lint = { version = "=0.68.2", features = ["docs"] } deno_lint = { version = "=0.68.2", features = ["docs"] }
deno_lockfile.workspace = true deno_lockfile.workspace = true
deno_npm.workspace = true deno_npm.workspace = true
@ -124,7 +125,7 @@ http.workspace = true
http-body.workspace = true http-body.workspace = true
http-body-util.workspace = true http-body-util.workspace = true
hyper-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 indexmap.workspace = true
jsonc-parser = { workspace = true, features = ["cst", "serde"] } jsonc-parser = { workspace = true, features = ["cst", "serde"] }
jupyter_runtime = { package = "runtimelib", version = "=0.19.0", features = ["tokio-runtime"] } 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::Mutex;
use deno_core::parking_lot::MutexGuard; use deno_core::parking_lot::MutexGuard;
use deno_core::serde_json; use deno_core::serde_json;
use deno_error::JsErrorBox;
use deno_lockfile::Lockfile; use deno_lockfile::Lockfile;
use deno_lockfile::WorkspaceMemberConfig; use deno_lockfile::WorkspaceMemberConfig;
use deno_package_json::PackageJsonDepValue; 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 { impl CliLockfile {
/// Get the inner deno_lockfile::Lockfile. /// Get the inner deno_lockfile::Lockfile.
pub fn lock(&self) -> Guard<Lockfile> { pub fn lock(&self) -> Guard<Lockfile> {
@ -78,7 +87,7 @@ impl CliLockfile {
self.lockfile.lock().overwrite self.lockfile.lock().overwrite
} }
pub fn write_if_changed(&self) -> Result<(), AnyError> { pub fn write_if_changed(&self) -> Result<(), JsErrorBox> {
if self.skip_write { if self.skip_write {
return Ok(()); return Ok(());
} }
@ -96,7 +105,9 @@ impl CliLockfile {
&bytes, &bytes,
cache::CACHE_PERM, cache::CACHE_PERM,
) )
.context("Failed writing lockfile.")?; .map_err(|source| {
JsErrorBox::from_err(AtomicWriteFileWithRetriesError { source })
})?;
lockfile.has_content_changed = false; lockfile.has_content_changed = false;
Ok(()) 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 { if !self.frozen {
return Ok(()); return Ok(());
} }
@ -267,9 +278,7 @@ impl CliLockfile {
let diff = crate::util::diff::diff(&contents, &new_contents); let diff = crate::util::diff::diff(&contents, &new_contents);
// has an extra newline at the end // has an extra newline at the end
let diff = diff.trim_end(); let diff = diff.trim_end();
Err(deno_core::anyhow::anyhow!( 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}")))
"The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.\nchanges:\n{diff}"
))
} else { } else {
Ok(()) Ok(())
} }

View file

@ -26,6 +26,7 @@ use deno_ast::SourceMapOption;
use deno_cache_dir::file_fetcher::CacheSetting; use deno_cache_dir::file_fetcher::CacheSetting;
pub use deno_config::deno_json::BenchConfig; pub use deno_config::deno_json::BenchConfig;
pub use deno_config::deno_json::ConfigFile; pub use deno_config::deno_json::ConfigFile;
use deno_config::deno_json::ConfigFileError;
use deno_config::deno_json::FmtConfig; use deno_config::deno_json::FmtConfig;
pub use deno_config::deno_json::FmtOptionsConfig; pub use deno_config::deno_json::FmtOptionsConfig;
use deno_config::deno_json::LintConfig; 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::resolve_url_or_path;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::url::Url; use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_graph::GraphKind; use deno_graph::GraphKind;
pub use deno_json::check_warn_tsconfig; pub use deno_json::check_warn_tsconfig;
use deno_lint::linter::LintConfig as DenoLintConfig; 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 { pub enum RootCertStoreLoadError {
#[error( #[error(
"Unknown certificate store \"{0}\" specified (allowed: \"system,mozilla\")" "Unknown certificate store \"{0}\" specified (allowed: \"system,mozilla\")"
@ -1104,7 +1107,7 @@ impl CliOptions {
pkg_json_dep_resolution, pkg_json_dep_resolution,
specified_import_map: cli_arg_specified_import_map, 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( pub fn node_modules_dir(
&self, &self,
) -> Result<Option<NodeModulesDirMode>, AnyError> { ) -> Result<
Option<NodeModulesDirMode>,
deno_config::deno_json::NodeModulesDirParseError,
> {
if let Some(flag) = self.flags.node_modules_dir { if let Some(flag) = self.flags.node_modules_dir {
return Ok(Some(flag)); 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> { pub fn vendor_dir_path(&self) -> Option<&PathBuf> {
@ -1260,7 +1266,7 @@ impl CliOptions {
pub fn resolve_ts_config_for_emit( pub fn resolve_ts_config_for_emit(
&self, &self,
config_type: TsConfigType, config_type: TsConfigType,
) -> Result<TsConfigForEmit, AnyError> { ) -> Result<TsConfigForEmit, ConfigFileError> {
self.workspace().resolve_ts_config_for_emit(config_type) self.workspace().resolve_ts_config_for_emit(config_type)
} }
@ -1289,7 +1295,7 @@ impl CliOptions {
pub fn to_compiler_option_types( pub fn to_compiler_option_types(
&self, &self,
) -> Result<Vec<deno_graph::ReferrerImports>, AnyError> { ) -> Result<Vec<deno_graph::ReferrerImports>, serde_json::Error> {
self self
.workspace() .workspace()
.to_compiler_option_types() .to_compiler_option_types()

View file

@ -13,10 +13,9 @@ mod ts {
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use deno_core::OpState; use deno_core::OpState;
use deno_error::JsErrorBox;
use serde::Serialize; use serde::Serialize;
use super::*; use super::*;
@ -53,7 +52,7 @@ mod ts {
fn op_script_version( fn op_script_version(
_state: &mut OpState, _state: &mut OpState,
#[string] _arg: &str, #[string] _arg: &str,
) -> Result<Option<String>, AnyError> { ) -> Result<Option<String>, JsErrorBox> {
Ok(Some("1".to_string())) Ok(Some("1".to_string()))
} }
@ -72,7 +71,7 @@ mod ts {
fn op_load( fn op_load(
state: &mut OpState, state: &mut OpState,
#[string] load_specifier: &str, #[string] load_specifier: &str,
) -> Result<LoadResponse, AnyError> { ) -> Result<LoadResponse, JsErrorBox> {
let op_crate_libs = state.borrow::<HashMap<&str, PathBuf>>(); let op_crate_libs = state.borrow::<HashMap<&str, PathBuf>>();
let path_dts = state.borrow::<PathBuf>(); let path_dts = state.borrow::<PathBuf>();
let re_asset = lazy_regex::regex!(r"asset:/{3}lib\.(\S+)\.d\.ts"); 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 // if it comes from an op crate, we were supplied with the path to the
// file. // file.
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) { 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 // otherwise we will generate the path ourself
} else { } else {
path_dts.join(format!("lib.{lib}.d.ts")) 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 { Ok(LoadResponse {
data, data,
version: "1".to_string(), version: "1".to_string(),
@ -106,13 +108,13 @@ mod ts {
script_kind: 3, script_kind: 3,
}) })
} else { } else {
Err(custom_error( Err(JsErrorBox::new(
"InvalidSpecifier", "InvalidSpecifier",
format!("An invalid specifier was requested: {}", load_specifier), format!("An invalid specifier was requested: {}", load_specifier),
)) ))
} }
} else { } else {
Err(custom_error( Err(JsErrorBox::new(
"InvalidSpecifier", "InvalidSpecifier",
format!("An invalid specifier was requested: {}", load_specifier), 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::CacheSetting;
use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind; use deno_cache_dir::file_fetcher::FetchNoFollowErrorKind;
use deno_cache_dir::file_fetcher::FileOrRedirect; use deno_cache_dir::file_fetcher::FileOrRedirect;
use deno_core::error::AnyError;
use deno_core::futures; use deno_core::futures;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::ModuleSpecifier; 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 LocalHttpCache = deno_cache_dir::LocalHttpCache<CliSys>;
pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache<CliSys>; pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache<CliSys>;
pub use deno_cache_dir::HttpCache; pub use deno_cache_dir::HttpCache;
use deno_error::JsErrorBox;
pub struct FetchCacherOptions { pub struct FetchCacherOptions {
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>, pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
@ -194,9 +194,9 @@ impl Loader for FetchCacher {
LoaderCacheSetting::Use => None, LoaderCacheSetting::Use => None,
LoaderCacheSetting::Reload => { LoaderCacheSetting::Reload => {
if matches!(file_fetcher.cache_setting(), CacheSetting::Only) { 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" "Could not resolve version constraint using only cached data. Try running again without --cached-only"
)); ))));
} }
Some(CacheSetting::ReloadAll) Some(CacheSetting::ReloadAll)
} }
@ -262,28 +262,27 @@ impl Loader for FetchCacher {
FetchNoFollowErrorKind::CacheSave { .. } | FetchNoFollowErrorKind::CacheSave { .. } |
FetchNoFollowErrorKind::UnsupportedScheme { .. } | FetchNoFollowErrorKind::UnsupportedScheme { .. } |
FetchNoFollowErrorKind::RedirectHeaderParse { .. } | FetchNoFollowErrorKind::RedirectHeaderParse { .. } |
FetchNoFollowErrorKind::InvalidHeader { .. } => Err(AnyError::from(err)), FetchNoFollowErrorKind::InvalidHeader { .. } => Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err)))),
FetchNoFollowErrorKind::NotCached { .. } => { FetchNoFollowErrorKind::NotCached { .. } => {
if options.cache_setting == LoaderCacheSetting::Only { if options.cache_setting == LoaderCacheSetting::Only {
Ok(None) Ok(None)
} else { } else {
Err(AnyError::from(err)) Err(deno_graph::source::LoadError::Other(Arc::new(JsErrorBox::from_err(err))))
} }
}, },
FetchNoFollowErrorKind::ChecksumIntegrity(err) => { FetchNoFollowErrorKind::ChecksumIntegrity(err) => {
// convert to the equivalent deno_graph error so that it // convert to the equivalent deno_graph error so that it
// enhances it if this is passed to deno_graph // enhances it if this is passed to deno_graph
Err( Err(
deno_graph::source::ChecksumIntegrityError { deno_graph::source::LoadError::ChecksumIntegrity(deno_graph::source::ChecksumIntegrityError {
actual: err.actual, actual: err.actual,
expected: err.expected, 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::TranspileModuleOptions;
use deno_ast::TranspileResult; use deno_ast::TranspileResult;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::stream::FuturesUnordered; use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::MediaType; use deno_graph::MediaType;
use deno_graph::Module; use deno_graph::Module;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
@ -124,7 +126,7 @@ impl Emitter {
let transpiled_source = deno_core::unsync::spawn_blocking({ let transpiled_source = deno_core::unsync::spawn_blocking({
let specifier = specifier.clone(); let specifier = specifier.clone();
let source = source.clone(); let source = source.clone();
move || -> Result<_, AnyError> { move || {
EmitParsedSourceHelper::transpile( EmitParsedSourceHelper::transpile(
&parsed_source_cache, &parsed_source_cache,
&specifier, &specifier,
@ -155,7 +157,7 @@ impl Emitter {
media_type: MediaType, media_type: MediaType,
module_kind: deno_ast::ModuleKind, module_kind: deno_ast::ModuleKind,
source: &Arc<str>, source: &Arc<str>,
) -> Result<String, AnyError> { ) -> Result<String, EmitParsedSourceHelperError> {
// Note: keep this in sync with the async version above // Note: keep this in sync with the async version above
let helper = EmitParsedSourceHelper(self); let helper = EmitParsedSourceHelper(self);
match helper.pre_emit_parsed_source(specifier, module_kind, source) { match helper.pre_emit_parsed_source(specifier, module_kind, source) {
@ -210,7 +212,7 @@ impl Emitter {
pub async fn load_and_emit_for_hmr( pub async fn load_and_emit_for_hmr(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
) -> Result<String, AnyError> { ) -> Result<String, CoreError> {
let media_type = MediaType::from_specifier(specifier); let media_type = MediaType::from_specifier(specifier);
let source_code = tokio::fs::read_to_string( let source_code = tokio::fs::read_to_string(
ModuleSpecifier::to_file_path(specifier).unwrap(), ModuleSpecifier::to_file_path(specifier).unwrap(),
@ -225,17 +227,21 @@ impl Emitter {
let source_arc: Arc<str> = source_code.into(); let source_arc: Arc<str> = source_code.into();
let parsed_source = self let parsed_source = self
.parsed_source_cache .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 // 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 // the option to not use them (though you should test this out because
// this statement is probably wrong) // this statement is probably wrong)
let mut options = self.transpile_and_emit_options.1.clone(); let mut options = self.transpile_and_emit_options.1.clone();
options.source_map = SourceMapOption::None; options.source_map = SourceMapOption::None;
let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script( let is_cjs = self
specifier, .cjs_tracker
media_type, .is_cjs_with_known_is_script(
parsed_source.compute_is_script(), specifier,
)?; media_type,
parsed_source.compute_is_script(),
)
.map_err(JsErrorBox::from_err)?;
let transpiled_source = parsed_source let transpiled_source = parsed_source
.transpile( .transpile(
&self.transpile_and_emit_options.0, &self.transpile_and_emit_options.0,
@ -243,7 +249,8 @@ impl Emitter {
module_kind: Some(ModuleKind::from_is_cjs(is_cjs)), module_kind: Some(ModuleKind::from_is_cjs(is_cjs)),
}, },
&options, &options,
)? )
.map_err(JsErrorBox::from_err)?
.into_source(); .into_source();
Ok(transpiled_source.text) Ok(transpiled_source.text)
} }
@ -282,6 +289,19 @@ enum PreEmitResult {
NotCached { source_hash: u64 }, 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. /// Helper to share code between async and sync emit_parsed_source methods.
struct EmitParsedSourceHelper<'a>(&'a Emitter); struct EmitParsedSourceHelper<'a>(&'a Emitter);
@ -311,7 +331,7 @@ impl<'a> EmitParsedSourceHelper<'a> {
source: Arc<str>, source: Arc<str>,
transpile_options: &deno_ast::TranspileOptions, transpile_options: &deno_ast::TranspileOptions,
emit_options: &deno_ast::EmitOptions, emit_options: &deno_ast::EmitOptions,
) -> Result<EmittedSourceText, AnyError> { ) -> Result<EmittedSourceText, EmitParsedSourceHelperError> {
// nothing else needs the parsed source at this point, so remove from // nothing else needs the parsed source at this point, so remove from
// the cache in order to not transpile owned // the cache in order to not transpile owned
let parsed_source = parsed_source_cache 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 // todo(dsherret): this is a temporary measure until we have swc erroring for this
fn ensure_no_import_assertion( fn ensure_no_import_assertion(
parsed_source: &deno_ast::ParsedSource, parsed_source: &deno_ast::ParsedSource,
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
fn has_import_assertion(text: &str) -> bool { fn has_import_assertion(text: &str) -> bool {
// good enough // good enough
text.contains(" assert ") && !text.contains(" with ") text.contains(" assert ") && !text.contains(" with ")
@ -360,7 +380,7 @@ fn ensure_no_import_assertion(
fn create_err( fn create_err(
parsed_source: &deno_ast::ParsedSource, parsed_source: &deno_ast::ParsedSource,
range: SourceRange, range: SourceRange,
) -> AnyError { ) -> JsErrorBox {
let text_info = parsed_source.text_info_lazy(); let text_info = parsed_source.text_info_lazy();
let loc = text_info.line_and_column_display(range.start); 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(); 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.line_number,
loc.column_number, loc.column_number,
)); ));
deno_core::anyhow::anyhow!("{}", msg) JsErrorBox::generic(msg)
} }
let deno_ast::ProgramRef::Module(module) = parsed_source.program_ref() else { 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::error::AnyError;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::FeatureChecker; use deno_core::FeatureChecker;
use deno_error::JsErrorBox;
use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions; use deno_resolver::DenoResolverOptions;
@ -118,7 +119,7 @@ impl CliRootCertStoreProvider {
} }
impl RootCertStoreProvider for CliRootCertStoreProvider { impl RootCertStoreProvider for CliRootCertStoreProvider {
fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError> { fn get_or_try_init(&self) -> Result<&RootCertStore, JsErrorBox> {
self self
.cell .cell
.get_or_try_init(|| { .get_or_try_init(|| {
@ -128,7 +129,7 @@ impl RootCertStoreProvider for CliRootCertStoreProvider {
self.maybe_ca_data.clone(), 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::collections::HashSet;
use std::error::Error; use std::error::Error;
use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use deno_config::deno_json;
use deno_config::deno_json::JsxImportSourceConfig; use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::JsrPackageConfig; use deno_config::workspace::JsrPackageConfig;
use deno_core::anyhow::bail;
use deno_core::error::custom_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
use deno_graph::source::Loader; use deno_graph::source::Loader;
use deno_graph::source::LoaderChecksum; use deno_graph::source::LoaderChecksum;
use deno_graph::source::ResolutionKind; use deno_graph::source::ResolutionKind;
@ -49,8 +50,6 @@ use crate::cache::GlobalHttpCache;
use crate::cache::ModuleInfoCache; use crate::cache::ModuleInfoCache;
use crate::cache::ParsedSourceCache; use crate::cache::ParsedSourceCache;
use crate::colors; 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::file_fetcher::CliFileFetcher;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
@ -59,6 +58,7 @@ use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use crate::sys::CliSys; use crate::sys::CliSys;
use crate::tools::check; use crate::tools::check;
use crate::tools::check::CheckError;
use crate::tools::check::TypeChecker; use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path; use crate::util::fs::canonicalize_path;
@ -85,7 +85,7 @@ pub fn graph_valid(
sys: &CliSys, sys: &CliSys,
roots: &[ModuleSpecifier], roots: &[ModuleSpecifier],
options: GraphValidOptions, options: GraphValidOptions,
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
if options.exit_integrity_errors { if options.exit_integrity_errors {
graph_exit_integrity_errors(graph); graph_exit_integrity_errors(graph);
} }
@ -104,9 +104,9 @@ pub fn graph_valid(
} else { } else {
// finally surface the npm resolution result // finally surface the npm resolution result
if let Err(err) = &graph.npm_dep_graph_result { if let Err(err) = &graph.npm_dep_graph_result {
return Err(custom_error( return Err(JsErrorBox::new(
get_error_class_name(err), err.get_class(),
format_deno_graph_error(err.as_ref().deref()), format_deno_graph_error(err),
)); ));
} }
Ok(()) Ok(())
@ -145,7 +145,7 @@ pub fn graph_walk_errors<'a>(
sys: &'a CliSys, sys: &'a CliSys,
roots: &'a [ModuleSpecifier], roots: &'a [ModuleSpecifier],
options: GraphWalkErrorsOptions, options: GraphWalkErrorsOptions,
) -> impl Iterator<Item = AnyError> + 'a { ) -> impl Iterator<Item = JsErrorBox> + 'a {
graph graph
.walk( .walk(
roots.iter(), roots.iter(),
@ -197,7 +197,7 @@ pub fn graph_walk_errors<'a>(
return None; 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) self.module_graph_builder.graph_valid(graph)
} }
async fn type_check_graph( async fn type_check_graph(
&self, &self,
graph: ModuleGraph, graph: ModuleGraph,
) -> Result<Arc<ModuleGraph>, AnyError> { ) -> Result<Arc<ModuleGraph>, CheckError> {
self self
.type_checker .type_checker
.check( .check(
@ -467,6 +467,27 @@ pub struct BuildFastCheckGraphOptions<'a> {
pub workspace_fast_check: deno_graph::WorkspaceFastCheckOption<'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 { pub struct ModuleGraphBuilder {
caches: Arc<cache::Caches>, caches: Arc<cache::Caches>,
cjs_tracker: Arc<CjsTracker>, cjs_tracker: Arc<CjsTracker>,
@ -524,7 +545,7 @@ impl ModuleGraphBuilder {
&self, &self,
graph: &mut ModuleGraph, graph: &mut ModuleGraph,
options: CreateGraphOptions<'a>, options: CreateGraphOptions<'a>,
) -> Result<(), AnyError> { ) -> Result<(), BuildGraphWithNpmResolutionError> {
enum MutLoaderRef<'a> { enum MutLoaderRef<'a> {
Borrowed(&'a mut dyn Loader), Borrowed(&'a mut dyn Loader),
Owned(cache::FetchCacher), Owned(cache::FetchCacher),
@ -652,7 +673,7 @@ impl ModuleGraphBuilder {
loader: &'a mut dyn deno_graph::source::Loader, loader: &'a mut dyn deno_graph::source::Loader,
options: deno_graph::BuildOptions<'a>, options: deno_graph::BuildOptions<'a>,
npm_caching: NpmCachingStrategy, npm_caching: NpmCachingStrategy,
) -> Result<(), AnyError> { ) -> Result<(), BuildGraphWithNpmResolutionError> {
// ensure an "npm install" is done if the user has explicitly // ensure an "npm install" is done if the user has explicitly
// opted into using a node_modules directory // opted into using a node_modules directory
if self if self
@ -689,7 +710,7 @@ impl ModuleGraphBuilder {
if roots.iter().any(|r| r.scheme() == "npm") if roots.iter().any(|r| r.scheme() == "npm")
&& self.npm_resolver.as_byonm().is_some() && 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; graph.build(roots, loader, options).await;
@ -740,7 +761,7 @@ impl ModuleGraphBuilder {
&self, &self,
graph: &mut ModuleGraph, graph: &mut ModuleGraph,
options: BuildFastCheckGraphOptions, options: BuildFastCheckGraphOptions,
) -> Result<(), AnyError> { ) -> Result<(), deno_json::ToMaybeJsxImportSourceConfigError> {
if !graph.graph_kind().include_types() { if !graph.graph_kind().include_types() {
return Ok(()); return Ok(());
} }
@ -804,7 +825,7 @@ impl ModuleGraphBuilder {
/// Check if `roots` and their deps are available. Returns `Ok(())` if /// Check if `roots` and their deps are available. Returns `Ok(())` if
/// so. Returns `Err(_)` if there is a known module graph or resolution /// so. Returns `Err(_)` if there is a known module graph or resolution
/// error statically reachable from `roots` and not a dynamic import. /// 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( self.graph_roots_valid(
graph, graph,
&graph.roots.iter().cloned().collect::<Vec<_>>(), &graph.roots.iter().cloned().collect::<Vec<_>>(),
@ -815,7 +836,7 @@ impl ModuleGraphBuilder {
&self, &self,
graph: &ModuleGraph, graph: &ModuleGraph,
roots: &[ModuleSpecifier], roots: &[ModuleSpecifier],
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
graph_valid( graph_valid(
graph, graph,
&self.sys, &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 let jsx_import_source_config = self
.cli_options .cli_options
.workspace() .workspace()
@ -1001,8 +1025,13 @@ fn get_resolution_error_bare_specifier(
Some(specifier.as_str()) Some(specifier.as_str())
} else if let ResolutionError::ResolverError { error, .. } = error { } else if let ResolutionError::ResolverError { error, .. } = error {
if let ResolveError::Other(error) = (*error).as_ref() { if let ResolveError::Other(error) = (*error).as_ref() {
if let Some(ImportMapError::UnmappedBareSpecifier(specifier, _)) = if let Some(import_map::ImportMapErrorKind::UnmappedBareSpecifier(
error.downcast_ref::<ImportMapError>() specifier,
_,
)) = error
.as_any()
.downcast_ref::<ImportMapError>()
.map(|e| &**e)
{ {
Some(specifier.as_str()) Some(specifier.as_str())
} else { } else {
@ -1039,11 +1068,12 @@ fn get_import_prefix_missing_error(error: &ResolutionError) -> Option<&str> {
ResolveError::Other(other_error) => { ResolveError::Other(other_error) => {
if let Some(SpecifierError::ImportPrefixMissing { if let Some(SpecifierError::ImportPrefixMissing {
specifier, .. specifier, ..
}) = other_error.downcast_ref::<SpecifierError>() }) = other_error.as_any().downcast_ref::<SpecifierError>()
{ {
maybe_specifier = Some(specifier); maybe_specifier = Some(specifier);
} }
} }
ResolveError::ImportMap(_) => {}
} }
} }
} }
@ -1294,7 +1324,7 @@ mod test {
let specifier = ModuleSpecifier::parse("file:///file.ts").unwrap(); let specifier = ModuleSpecifier::parse("file:///file.ts").unwrap();
let err = import_map.resolve(input, &specifier).err().unwrap(); let err = import_map.resolve(input, &specifier).err().unwrap();
let err = ResolutionError::ResolverError { let err = ResolutionError::ResolverError {
error: Arc::new(ResolveError::Other(err.into())), error: Arc::new(ResolveError::Other(JsErrorBox::from_err(err))),
specifier: input.to_string(), specifier: input.to_string(),
range: Range { range: Range {
specifier, specifier,

View file

@ -6,13 +6,14 @@ use std::thread::ThreadId;
use boxed_error::Boxed; use boxed_error::Boxed;
use deno_cache_dir::file_fetcher::RedirectHeaderParseError; use deno_cache_dir::file_fetcher::RedirectHeaderParseError;
use deno_core::error::custom_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::serde; use deno_core::serde;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::url::Url; use deno_core::url::Url;
use deno_error::JsError;
use deno_error::JsErrorBox;
use deno_runtime::deno_fetch; use deno_runtime::deno_fetch;
use deno_runtime::deno_fetch::create_http_client; use deno_runtime::deno_fetch::create_http_client;
use deno_runtime::deno_fetch::CreateHttpClientOptions; 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))] #[error("Bad response: {:?}{}", .status_code, .response_text.as_ref().map(|s| format!("\n\n{}", s)).unwrap_or_else(String::new))]
pub struct BadResponseError { pub struct BadResponseError {
pub status_code: StatusCode, pub status_code: StatusCode,
pub response_text: Option<String>, pub response_text: Option<String>,
} }
#[derive(Debug, Boxed)] #[derive(Debug, Boxed, JsError)]
pub struct DownloadError(pub Box<DownloadErrorKind>); pub struct DownloadError(pub Box<DownloadErrorKind>);
#[derive(Debug, Error)] #[derive(Debug, Error, JsError)]
pub enum DownloadErrorKind { pub enum DownloadErrorKind {
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Fetch(AnyError), Fetch(deno_fetch::ClientSendError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
UrlParse(#[from] deno_core::url::ParseError), UrlParse(#[from] deno_core::url::ParseError),
#[class(generic)]
#[error(transparent)] #[error(transparent)]
HttpParse(#[from] http::Error), HttpParse(#[from] http::Error),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Json(#[from] serde_json::Error), Json(#[from] serde_json::Error),
#[class(generic)]
#[error(transparent)] #[error(transparent)]
ToStr(#[from] http::header::ToStrError), ToStr(#[from] http::header::ToStrError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
RedirectHeaderParse(RedirectHeaderParseError), RedirectHeaderParse(RedirectHeaderParseError),
#[class(type)]
#[error("Too many redirects.")] #[error("Too many redirects.")]
TooManyRedirects, TooManyRedirects,
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
BadResponse(#[from] BadResponseError), BadResponse(#[from] BadResponseError),
#[class("Http")]
#[error("Not Found.")]
NotFound,
#[class(inherit)]
#[error(transparent)]
Other(JsErrorBox),
} }
#[derive(Debug)] #[derive(Debug)]
@ -208,11 +224,11 @@ impl HttpClient {
Ok(String::from_utf8(bytes)?) 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?; let maybe_bytes = self.download_inner(url, None, None).await?;
match maybe_bytes { match maybe_bytes {
Some(bytes) => Ok(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) get_response_body_with_progress(response, progress_guard)
.await .await
.map(|(_, body)| Some(body)) .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( async fn get_redirected_response(
@ -293,7 +309,7 @@ impl HttpClient {
.clone() .clone()
.send(req) .send(req)
.await .await
.map_err(|e| DownloadErrorKind::Fetch(e.into()).into_box())?; .map_err(|e| DownloadErrorKind::Fetch(e).into_box())?;
let status = response.status(); let status = response.status();
if status.is_redirection() { if status.is_redirection() {
for _ in 0..5 { for _ in 0..5 {
@ -313,7 +329,7 @@ impl HttpClient {
.clone() .clone()
.send(req) .send(req)
.await .await
.map_err(|e| DownloadErrorKind::Fetch(e.into()).into_box())?; .map_err(|e| DownloadErrorKind::Fetch(e).into_box())?;
let status = new_response.status(); let status = new_response.status();
if status.is_redirection() { if status.is_redirection() {
response = new_response; response = new_response;
@ -332,7 +348,7 @@ impl HttpClient {
pub async fn get_response_body_with_progress( pub async fn get_response_body_with_progress(
response: http::Response<deno_fetch::ResBody>, response: http::Response<deno_fetch::ResBody>,
progress_guard: Option<&UpdateGuard>, progress_guard: Option<&UpdateGuard>,
) -> Result<(HeaderMap, Vec<u8>), AnyError> { ) -> Result<(HeaderMap, Vec<u8>), JsErrorBox> {
use http_body::Body as _; use http_body::Body as _;
if let Some(progress_guard) = progress_guard { if let Some(progress_guard) = progress_guard {
let mut total_size = response.body().size_hint().exact(); 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::SourceRangedForSpanned;
use deno_ast::SourceTextInfo; use deno_ast::SourceTextInfo;
use deno_config::workspace::MappedResolution; use deno_config::workspace::MappedResolution;
use deno_core::error::custom_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
use deno_core::serde::Serialize; use deno_core::serde::Serialize;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_lint::diagnostic::LintDiagnosticRange; use deno_lint::diagnostic::LintDiagnosticRange;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_runtime::deno_node::PathClean; 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 // 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, // actually easier to return errors if we ever encounter one of these,
// which we really wouldn't expect from the Deno lsp. // which we really wouldn't expect from the Deno lsp.
return Err(custom_error( return Err(
"UnsupportedFix", JsErrorBox::new(
"The action returned from TypeScript is unsupported.", "UnsupportedFix",
)); "The action returned from TypeScript is unsupported.",
)
.into(),
);
} }
let Some(action) = let Some(action) =
fix_ts_import_action(specifier, resolution_mode, action, language_server) 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::serde_json::Value;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_lint::linter::LintConfig as DenoLintConfig; use deno_lint::linter::LintConfig as DenoLintConfig;
use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::npm_rc::ResolvedNpmRc;
use deno_package_json::PackageJsonCache; use deno_package_json::PackageJsonCache;
@ -1575,7 +1576,7 @@ impl ConfigData {
pkg_json_dep_resolution, pkg_json_dep_resolution,
specified_import_map, 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| { .inspect_err(|err| {
lsp_warn!( lsp_warn!(

View file

@ -34,7 +34,7 @@ use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference; use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq; use deno_semver::package::PackageReq;
use import_map::ImportMap; use import_map::ImportMap;
use import_map::ImportMapError; use import_map::ImportMapErrorKind;
use log::error; use log::error;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@ -1297,8 +1297,8 @@ impl DenoDiagnostic {
let mut message; let mut message;
message = enhanced_resolution_error_message(err); message = enhanced_resolution_error_message(err);
if let deno_graph::ResolutionError::ResolverError {error, ..} = err{ if let deno_graph::ResolutionError::ResolverError {error, ..} = err{
if let ResolveError::Other(resolve_error, ..) = (*error).as_ref() { if let ResolveError::ImportMap(importmap) = (*error).as_ref() {
if let Some(ImportMapError::UnmappedBareSpecifier(specifier, _)) = resolve_error.downcast_ref::<ImportMapError>() { if let ImportMapErrorKind::UnmappedBareSpecifier(specifier, _) = &**importmap {
if specifier.chars().next().unwrap_or('\0') == '@'{ if specifier.chars().next().unwrap_or('\0') == '@'{
let hint = format!("\nHint: Use [deno add {}] to add the dependency.", specifier); let hint = format!("\nHint: Use [deno add {}] to add the dependency.", specifier);
message.push_str(hint.as_str()); 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::MediaType;
use deno_ast::ParsedSource; use deno_ast::ParsedSource;
use deno_ast::SourceTextInfo; use deno_ast::SourceTextInfo;
use deno_core::error::custom_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures::future; use deno_core::futures::future;
use deno_core::futures::future::Shared; use deno_core::futures::future::Shared;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_graph::Resolution; use deno_graph::Resolution;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_runtime::deno_node; use deno_runtime::deno_node;
@ -1081,7 +1081,7 @@ impl Documents {
.or_else(|| self.file_system_docs.remove_document(specifier)) .or_else(|| self.file_system_docs.remove_document(specifier))
.map(Ok) .map(Ok)
.unwrap_or_else(|| { .unwrap_or_else(|| {
Err(custom_error( Err(JsErrorBox::new(
"NotFound", "NotFound",
format!("The specifier \"{specifier}\" was not found."), format!("The specifier \"{specifier}\" was not found."),
)) ))

View file

@ -122,7 +122,7 @@ use crate::util::sync::AsyncFlag;
struct LspRootCertStoreProvider(RootCertStore); struct LspRootCertStoreProvider(RootCertStore);
impl RootCertStoreProvider for LspRootCertStoreProvider { 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) Ok(&self.0)
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -11,6 +11,7 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::url::Url; use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo; use deno_npm::registry::NpmPackageInfo;
use deno_npm::registry::NpmRegistryApi; 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 { impl ManagedCliNpmResolver {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
@ -356,7 +379,7 @@ impl ManagedCliNpmResolver {
pub fn resolve_pkg_folder_from_pkg_id( pub fn resolve_pkg_folder_from_pkg_id(
&self, &self,
pkg_id: &NpmPackageId, pkg_id: &NpmPackageId,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, ResolvePkgFolderFromPkgIdError> {
let path = self.fs_resolver.package_folder(pkg_id)?; let path = self.fs_resolver.package_folder(pkg_id)?;
let path = canonicalize_path_maybe_not_exists(&self.sys, &path)?; let path = canonicalize_path_maybe_not_exists(&self.sys, &path)?;
log::debug!( log::debug!(
@ -423,7 +446,7 @@ impl ManagedCliNpmResolver {
pub async fn add_and_cache_package_reqs( pub async fn add_and_cache_package_reqs(
&self, &self,
packages: &[PackageReq], packages: &[PackageReq],
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
self self
.add_package_reqs_raw( .add_package_reqs_raw(
packages, packages,
@ -436,7 +459,7 @@ impl ManagedCliNpmResolver {
pub async fn add_package_reqs_no_cache( pub async fn add_package_reqs_no_cache(
&self, &self,
packages: &[PackageReq], packages: &[PackageReq],
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
self self
.add_package_reqs_raw(packages, None) .add_package_reqs_raw(packages, None)
.await .await
@ -447,7 +470,7 @@ impl ManagedCliNpmResolver {
&self, &self,
packages: &[PackageReq], packages: &[PackageReq],
caching: PackageCaching<'_>, caching: PackageCaching<'_>,
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
self self
.add_package_reqs_raw(packages, Some(caching)) .add_package_reqs_raw(packages, Some(caching))
.await .await
@ -517,7 +540,7 @@ impl ManagedCliNpmResolver {
pub async fn inject_synthetic_types_node_package( pub async fn inject_synthetic_types_node_package(
&self, &self,
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
let reqs = &[PackageReq::from_str("@types/node").unwrap()]; let reqs = &[PackageReq::from_str("@types/node").unwrap()];
// add and ensure this isn't added to the lockfile // add and ensure this isn't added to the lockfile
self self
@ -530,16 +553,16 @@ impl ManagedCliNpmResolver {
pub async fn cache_packages( pub async fn cache_packages(
&self, &self,
caching: PackageCaching<'_>, caching: PackageCaching<'_>,
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
self.fs_resolver.cache_packages(caching).await self.fs_resolver.cache_packages(caching).await
} }
pub fn resolve_pkg_folder_from_deno_module( pub fn resolve_pkg_folder_from_deno_module(
&self, &self,
nv: &PackageNv, nv: &PackageNv,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, ResolvePkgFolderFromDenoModuleError> {
let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(nv)?; 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( 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. /// return value of `false` means that new packages were added to the NPM resolution.
pub async fn ensure_top_level_package_json_install( pub async fn ensure_top_level_package_json_install(
&self, &self,
) -> Result<bool, AnyError> { ) -> Result<bool, JsErrorBox> {
if !self.top_level_install_flag.raise() { if !self.top_level_install_flag.raise() {
return Ok(true); // already did this return Ok(true); // already did this
} }
@ -687,12 +710,12 @@ impl CliNpmReqResolver for ManagedCliNpmResolver {
req: &PackageReq, req: &PackageReq,
_referrer: &ModuleSpecifier, _referrer: &ModuleSpecifier,
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> { ) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
let pkg_id = self let pkg_id = self.resolve_pkg_id_from_pkg_req(req).map_err(|err| {
.resolve_pkg_id_from_pkg_req(req) ResolvePkgFolderFromDenoReqError::Managed(Box::new(err))
.map_err(|err| ResolvePkgFolderFromDenoReqError::Managed(err.into()))?; })?;
self self
.resolve_pkg_folder_from_pkg_id(&pkg_id) .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 capacity_builder::StringBuilder;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use deno_lockfile::NpmPackageDependencyLockfileInfo; use deno_lockfile::NpmPackageDependencyLockfileInfo;
use deno_lockfile::NpmPackageLockfileInfo; use deno_lockfile::NpmPackageLockfileInfo;
use deno_npm::registry::NpmRegistryApi; use deno_npm::registry::NpmRegistryApi;
@ -39,7 +40,7 @@ pub struct AddPkgReqsResult {
/// package requirements. /// package requirements.
pub results: Vec<Result<PackageNv, NpmResolutionError>>, pub results: Vec<Result<PackageNv, NpmResolutionError>>,
/// The final result of resolving and caching all the package requirements. /// 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 /// Handles updating and storing npm resolution in memory where the underlying
@ -106,7 +107,7 @@ impl NpmResolution {
*snapshot_lock.write() = snapshot; *snapshot_lock.write() = snapshot;
Ok(()) 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 async_trait::async_trait;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError; use deno_error::JsErrorBox;
use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId; use deno_npm::NpmPackageId;
use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageFolderResolveError;
use super::super::PackageCaching; 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. /// Part of the resolution that interacts with the file system.
#[async_trait(?Send)] #[async_trait(?Send)]
pub trait NpmPackageFsResolver: Send + Sync { pub trait NpmPackageFsResolver: Send + Sync {
@ -26,12 +31,9 @@ pub trait NpmPackageFsResolver: Send + Sync {
fn package_folder( fn package_folder(
&self, &self,
package_id: &NpmPackageId, package_id: &NpmPackageId,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, NpmPackageFsResolverPackageFolderError> {
self.maybe_package_folder(package_id).ok_or_else(|| { self.maybe_package_folder(package_id).ok_or_else(|| {
deno_core::anyhow::anyhow!( NpmPackageFsResolverPackageFolderError(package_id.as_serialized())
"Package folder not found for '{}'",
package_id.as_serialized()
)
}) })
} }
@ -44,10 +46,10 @@ pub trait NpmPackageFsResolver: Send + Sync {
fn resolve_package_cache_folder_id_from_specifier( fn resolve_package_cache_folder_id_from_specifier(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageCacheFolderId>, AnyError>; ) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error>;
async fn cache_packages<'a>( async fn cache_packages<'a>(
&self, &self,
caching: PackageCaching<'a>, caching: PackageCaching<'a>,
) -> Result<(), AnyError>; ) -> Result<(), JsErrorBox>;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,9 +6,8 @@ use std::io::ErrorKind;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_error::JsErrorBox;
use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodePermissions;
use sys_traits::FsCanonicalize; use sys_traits::FsCanonicalize;
@ -28,6 +27,16 @@ pub struct NpmRegistryReadPermissionChecker {
mode: NpmRegistryReadPermissionCheckerMode, 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 { impl NpmRegistryReadPermissionChecker {
pub fn new(sys: CliSys, mode: NpmRegistryReadPermissionCheckerMode) -> Self { pub fn new(sys: CliSys, mode: NpmRegistryReadPermissionCheckerMode) -> Self {
Self { Self {
@ -42,7 +51,7 @@ impl NpmRegistryReadPermissionChecker {
&self, &self,
permissions: &mut dyn NodePermissions, permissions: &mut dyn NodePermissions,
path: &'a Path, path: &'a Path,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, JsErrorBox> {
if permissions.query_read_all() { if permissions.query_read_all() {
return Ok(Cow::Borrowed(path)); // skip permissions checks below 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") { if path.components().any(|c| c.as_os_str() == "node_modules") {
Ok(Cow::Borrowed(path)) Ok(Cow::Borrowed(path))
} else { } else {
permissions.check_read_path(path).map_err(Into::into) permissions
.check_read_path(path)
.map_err(JsErrorBox::from_err)
} }
} }
NpmRegistryReadPermissionCheckerMode::Global(registry_path) NpmRegistryReadPermissionCheckerMode::Global(registry_path)
@ -66,7 +77,7 @@ impl NpmRegistryReadPermissionChecker {
if is_path_in_node_modules { if is_path_in_node_modules {
let mut cache = self.cache.lock(); let mut cache = self.cache.lock();
let mut canonicalize = let mut canonicalize =
|path: &Path| -> Result<Option<PathBuf>, AnyError> { |path: &Path| -> Result<Option<PathBuf>, JsErrorBox> {
match cache.get(path) { match cache.get(path) {
Some(canon) => Ok(Some(canon.clone())), Some(canon) => Ok(Some(canon.clone())),
None => match self.sys.fs_canonicalize(path) { None => match self.sys.fs_canonicalize(path) {
@ -78,9 +89,12 @@ impl NpmRegistryReadPermissionChecker {
if e.kind() == ErrorKind::NotFound { if e.kind() == ErrorKind::NotFound {
return Ok(None); return Ok(None);
} }
Err(AnyError::from(e)).with_context(|| { Err(JsErrorBox::from_err(
format!("failed canonicalizing '{}'", path.display()) 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::AtomicUsize;
use std::sync::atomic::Ordering; 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::op2;
use deno_core::v8; use deno_core::v8;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::OpState; use deno_core::OpState;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::ChildPermissionsArg; use deno_runtime::deno_permissions::ChildPermissionsArg;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::deno_web::StartTime; use deno_runtime::deno_web::StartTime;
@ -78,7 +76,7 @@ pub fn op_pledge_test_permissions(
pub fn op_restore_test_permissions( pub fn op_restore_test_permissions(
state: &mut OpState, state: &mut OpState,
#[serde] token: Uuid, #[serde] token: Uuid,
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() { if let Some(permissions_holder) = state.try_take::<PermissionsHolder>() {
if token != permissions_holder.0 { if token != permissions_holder.0 {
panic!("restore test permissions token does not match the stored token"); 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); state.put::<PermissionsContainer>(permissions);
Ok(()) Ok(())
} else { } 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, only: bool,
warmup: bool, warmup: bool,
#[buffer] ret_buf: &mut [u8], #[buffer] ret_buf: &mut [u8],
) -> Result<(), AnyError> { ) -> Result<(), JsErrorBox> {
if ret_buf.len() != 4 { if ret_buf.len() != 4 {
return Err(type_error(format!( return Err(JsErrorBox::type_error(format!(
"Invalid ret_buf length: {}", "Invalid ret_buf length: {}",
ret_buf.len() ret_buf.len()
))); )));

View file

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

View file

@ -2,25 +2,36 @@
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::error::generic_error; use deno_ast::ParseDiagnostic;
use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use crate::tools::lint; use crate::tools::lint;
deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],); 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] #[op2]
#[buffer] #[buffer]
fn op_lint_create_serialized_ast( fn op_lint_create_serialized_ast(
#[string] file_name: &str, #[string] file_name: &str,
#[string] source: String, #[string] source: String,
) -> Result<Vec<u8>, AnyError> { ) -> Result<Vec<u8>, LintError> {
let file_text = deno_ast::strip_bom(source); let file_text = deno_ast::strip_bom(source);
let path = std::env::current_dir()?.join(file_name); let path = std::env::current_dir()?.join(file_name);
let specifier = ModuleSpecifier::from_file_path(&path).map_err(|_| { let specifier = ModuleSpecifier::from_file_path(&path)
generic_error(format!("Failed to parse path as URL: {}", path.display())) .map_err(|_| LintError::PathParse(path))?;
})?;
let media_type = MediaType::from_specifier(&specifier); let media_type = MediaType::from_specifier(&specifier);
let parsed_source = deno_ast::parse_program(deno_ast::ParseParams { let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
specifier, specifier,

View file

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

View file

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

View file

@ -21,9 +21,8 @@ use deno_config::workspace::MappedResolutionError;
use deno_config::workspace::ResolverWorkspaceJsrPackage; use deno_config::workspace::ResolverWorkspaceJsrPackage;
use deno_config::workspace::WorkspaceResolver; use deno_config::workspace::WorkspaceResolver;
use deno_core::anyhow::Context; 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::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::future::LocalBoxFuture; use deno_core::futures::future::LocalBoxFuture;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::v8_set_flags; use deno_core::v8_set_flags;
@ -36,6 +35,7 @@ use deno_core::ModuleType;
use deno_core::RequestedModuleType; use deno_core::RequestedModuleType;
use deno_core::ResolutionKind; use deno_core::ResolutionKind;
use deno_core::SourceCodeCacheInfo; use deno_core::SourceCodeCacheInfo;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::npm_rc::ResolvedNpmRc;
use deno_package_json::PackageJsonDepValue; use deno_package_json::PackageJsonDepValue;
use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::cjs::IsCjsResolutionMode;
@ -182,25 +182,32 @@ impl ModuleLoader for EmbeddedModuleLoader {
raw_specifier: &str, raw_specifier: &str,
referrer: &str, referrer: &str,
kind: ResolutionKind, kind: ResolutionKind,
) -> Result<ModuleSpecifier, AnyError> { ) -> Result<ModuleSpecifier, ModuleLoaderError> {
let referrer = if referrer == "." { let referrer = if referrer == "." {
if kind != ResolutionKind::MainModule { if kind != ResolutionKind::MainModule {
return Err(generic_error(format!( return Err(
"Expected to resolve main module, got {:?} instead.", JsErrorBox::generic(format!(
kind "Expected to resolve main module, got {:?} instead.",
))); kind
))
.into(),
);
} }
let current_dir = std::env::current_dir().unwrap(); let current_dir = std::env::current_dir().unwrap();
deno_core::resolve_path(".", &current_dir)? deno_core::resolve_path(".", &current_dir)?
} else { } else {
ModuleSpecifier::parse(referrer).map_err(|err| { 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 let referrer_kind = if self
.shared .shared
.cjs_tracker .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 ResolutionMode::Require
} else { } else {
@ -217,7 +224,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
&referrer, &referrer,
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)? )
.map_err(JsErrorBox::from_err)?
.into_url(), .into_url(),
); );
} }
@ -245,14 +253,18 @@ impl ModuleLoader for EmbeddedModuleLoader {
Some(&referrer), Some(&referrer),
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)?, )
.map_err(JsErrorBox::from_err)?,
), ),
Ok(MappedResolution::PackageJson { Ok(MappedResolution::PackageJson {
dep_result, dep_result,
sub_path, sub_path,
alias, 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 PackageJsonDepValue::Req(req) => self
.shared .shared
.npm_req_resolver .npm_req_resolver
@ -263,7 +275,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
) )
.map_err(AnyError::from), .map_err(|e| JsErrorBox::from_err(e).into()),
PackageJsonDepValue::Workspace(version_req) => { PackageJsonDepValue::Workspace(version_req) => {
let pkg_folder = self let pkg_folder = self
.shared .shared
@ -271,7 +283,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
.resolve_workspace_pkg_json_folder_for_pkg_json_dep( .resolve_workspace_pkg_json_folder_for_pkg_json_dep(
alias, alias,
version_req, version_req,
)?; )
.map_err(JsErrorBox::from_err)?;
Ok( Ok(
self self
.shared .shared
@ -282,7 +295,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
Some(&referrer), Some(&referrer),
referrer_kind, referrer_kind,
NodeResolutionKind::Execution, NodeResolutionKind::Execution,
)?, )
.map_err(JsErrorBox::from_err)?,
) )
} }
}, },
@ -291,12 +305,18 @@ impl ModuleLoader for EmbeddedModuleLoader {
if let Ok(reference) = if let Ok(reference) =
NpmPackageReqReference::from_specifier(&specifier) NpmPackageReqReference::from_specifier(&specifier)
{ {
return Ok(self.shared.npm_req_resolver.resolve_req_reference( return Ok(
&reference, self
&referrer, .shared
referrer_kind, .npm_req_resolver
NodeResolutionKind::Execution, .resolve_req_reference(
)?); &reference,
&referrer,
referrer_kind,
NodeResolutionKind::Execution,
)
.map_err(JsErrorBox::from_err)?,
);
} }
if specifier.scheme() == "jsr" { if specifier.scheme() == "jsr" {
@ -318,18 +338,22 @@ impl ModuleLoader for EmbeddedModuleLoader {
Err(err) Err(err)
if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" => if err.is_unmapped_bare_specifier() && referrer.scheme() == "file" =>
{ {
let maybe_res = self.shared.npm_req_resolver.resolve_if_for_npm_pkg( let maybe_res = self
raw_specifier, .shared
&referrer, .npm_req_resolver
referrer_kind, .resolve_if_for_npm_pkg(
NodeResolutionKind::Execution, raw_specifier,
)?; &referrer,
referrer_kind,
NodeResolutionKind::Execution,
)
.map_err(JsErrorBox::from_err)?;
if let Some(res) = maybe_res { if let Some(res) = maybe_res {
return Ok(res.into_url()); 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, Ok(response) => response,
Err(err) => { Err(err) => {
return deno_core::ModuleLoadResponse::Sync(Err(type_error( return deno_core::ModuleLoadResponse::Sync(Err(
format!("{:#}", err), JsErrorBox::type_error(format!("{:#}", err)).into(),
))); ));
} }
}; };
return deno_core::ModuleLoadResponse::Sync(Ok( return deno_core::ModuleLoadResponse::Sync(Ok(
@ -420,9 +444,9 @@ impl ModuleLoader for EmbeddedModuleLoader {
{ {
Ok(is_maybe_cjs) => is_maybe_cjs, Ok(is_maybe_cjs) => is_maybe_cjs,
Err(err) => { Err(err) => {
return deno_core::ModuleLoadResponse::Sync(Err(type_error( return deno_core::ModuleLoadResponse::Sync(Err(
format!("{:?}", err), JsErrorBox::type_error(format!("{:?}", err)).into(),
))); ));
} }
}; };
if is_maybe_cjs { if is_maybe_cjs {
@ -482,12 +506,16 @@ impl ModuleLoader for EmbeddedModuleLoader {
)) ))
} }
} }
Ok(None) => deno_core::ModuleLoadResponse::Sync(Err(type_error( Ok(None) => deno_core::ModuleLoadResponse::Sync(Err(
format!("{MODULE_NOT_FOUND}: {}", original_specifier), JsErrorBox::type_error(format!(
))), "{MODULE_NOT_FOUND}: {}",
Err(err) => deno_core::ModuleLoadResponse::Sync(Err(type_error( original_specifier
format!("{:?}", err), ))
))), .into(),
)),
Err(err) => deno_core::ModuleLoadResponse::Sync(Err(
JsErrorBox::type_error(format!("{:?}", err)).into(),
)),
} }
} }
@ -553,7 +581,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
&self, &self,
permissions: &mut dyn deno_runtime::deno_node::NodePermissions, permissions: &mut dyn deno_runtime::deno_node::NodePermissions,
path: &'a std::path::Path, 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) { if self.shared.modules.has_file(path) {
// allow reading if the file is in the snapshot // allow reading if the file is in the snapshot
return Ok(Cow::Borrowed(path)); return Ok(Cow::Borrowed(path));
@ -563,17 +591,23 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
.shared .shared
.npm_registry_permission_checker .npm_registry_permission_checker
.ensure_read_permission(permissions, path) .ensure_read_permission(permissions, path)
.map_err(JsErrorBox::from_err)
} }
fn load_text_file_lossy( fn load_text_file_lossy(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
) -> Result<Cow<'static, str>, AnyError> { ) -> Result<Cow<'static, str>, JsErrorBox> {
let file_entry = self.shared.vfs.file_entry(path)?; let file_entry = self
.shared
.vfs
.file_entry(path)
.map_err(JsErrorBox::from_err)?;
let file_bytes = self let file_bytes = self
.shared .shared
.vfs .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)) Ok(from_utf8_lossy_cow(file_bytes))
} }
@ -626,10 +660,10 @@ struct StandaloneRootCertStoreProvider {
} }
impl RootCertStoreProvider for 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(|| { self.cell.get_or_try_init(|| {
get_root_cert_store(None, self.ca_stores.clone(), self.ca_data.clone()) 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 std::time::Duration;
use deno_config::glob::WalkEntry; 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::AnyError;
use deno_core::error::CoreError;
use deno_core::error::JsError; use deno_core::error::JsError;
use deno_core::futures::future; use deno_core::futures::future;
use deno_core::futures::stream; use deno_core::futures::stream;
@ -18,6 +19,7 @@ use deno_core::unsync::spawn_blocking;
use deno_core::v8; use deno_core::v8;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::PollEventLoopOptions; use deno_core::PollEventLoopOptions;
use deno_error::JsErrorBox;
use deno_runtime::deno_permissions::Permissions; use deno_runtime::deno_permissions::Permissions;
use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser; use deno_runtime::permissions::RuntimePermissionDescriptorParser;
@ -162,17 +164,14 @@ async fn bench_specifier(
.await .await
{ {
Ok(()) => Ok(()), Ok(()) => Ok(()),
Err(error) => { Err(CoreError::Js(error)) => {
if error.is::<JsError>() { sender.send(BenchEvent::UncaughtError(
sender.send(BenchEvent::UncaughtError( specifier.to_string(),
specifier.to_string(), Box::new(error),
Box::new(error.downcast::<JsError>().unwrap()), ))?;
))?; Ok(())
Ok(())
} else {
Err(error)
}
} }
Err(e) => Err(e.into()),
} }
} }
@ -183,7 +182,7 @@ async fn bench_specifier_inner(
specifier: ModuleSpecifier, specifier: ModuleSpecifier,
sender: &UnboundedSender<BenchEvent>, sender: &UnboundedSender<BenchEvent>,
filter: TestFilter, filter: TestFilter,
) -> Result<(), AnyError> { ) -> Result<(), CoreError> {
let mut worker = worker_factory let mut worker = worker_factory
.create_custom_worker( .create_custom_worker(
WorkerExecutionMode::Bench, WorkerExecutionMode::Bench,
@ -230,14 +229,18 @@ async fn bench_specifier_inner(
.partial_cmp(&groups.get_index_of(&d2.group).unwrap()) .partial_cmp(&groups.get_index_of(&d2.group).unwrap())
.unwrap() .unwrap()
}); });
sender.send(BenchEvent::Plan(BenchPlan { sender
origin: specifier.to_string(), .send(BenchEvent::Plan(BenchPlan {
total: benchmarks.len(), origin: specifier.to_string(),
used_only, total: benchmarks.len(),
names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(), used_only,
}))?; names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(),
}))
.map_err(JsErrorBox::from_err)?;
for (desc, function) in benchmarks { 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 call = worker.js_runtime.call(&function);
let result = worker let result = worker
.js_runtime .js_runtime
@ -245,8 +248,11 @@ async fn bench_specifier_inner(
.await?; .await?;
let scope = &mut worker.js_runtime.handle_scope(); let scope = &mut worker.js_runtime.handle_scope();
let result = v8::Local::new(scope, result); let result = v8::Local::new(scope, result);
let result = serde_v8::from_v8::<BenchResult>(scope, result)?; let result = serde_v8::from_v8::<BenchResult>(scope, result)
sender.send(BenchEvent::Result(desc.id, 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 // Ignore `defaultPrevented` of the `beforeunload` event. We don't allow the
@ -356,13 +362,13 @@ async fn bench_specifiers(
reporter.report_end(&report); reporter.report_end(&report);
if used_only { if used_only {
return Err(generic_error( return Err(anyhow!(
"Bench failed because the \"only\" option was used", "Bench failed because the \"only\" option was used",
)); ));
} }
if report.failed > 0 { if report.failed > 0 {
return Err(generic_error("Bench failed")); return Err(anyhow!("Bench failed"));
} }
Ok(()) Ok(())
@ -440,7 +446,7 @@ pub async fn run_benchmarks(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if specifiers.is_empty() { 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?; 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::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_config::deno_json;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use deno_graph::Module; use deno_graph::Module;
use deno_graph::ModuleError; use deno_graph::ModuleError;
use deno_graph::ModuleGraph; use deno_graph::ModuleGraph;
@ -112,6 +114,27 @@ pub struct TypeChecker {
sys: CliSys, 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 { impl TypeChecker {
pub fn new( pub fn new(
caches: Arc<Caches>, caches: Arc<Caches>,
@ -141,7 +164,7 @@ impl TypeChecker {
&self, &self,
graph: ModuleGraph, graph: ModuleGraph,
options: CheckOptions, options: CheckOptions,
) -> Result<Arc<ModuleGraph>, AnyError> { ) -> Result<Arc<ModuleGraph>, CheckError> {
let (graph, mut diagnostics) = let (graph, mut diagnostics) =
self.check_diagnostics(graph, options).await?; self.check_diagnostics(graph, options).await?;
diagnostics.emit_warnings(); diagnostics.emit_warnings();
@ -160,7 +183,7 @@ impl TypeChecker {
&self, &self,
mut graph: ModuleGraph, mut graph: ModuleGraph,
options: CheckOptions, options: CheckOptions,
) -> Result<(Arc<ModuleGraph>, Diagnostics), AnyError> { ) -> Result<(Arc<ModuleGraph>, Diagnostics), CheckError> {
if !options.type_check_mode.is_true() || graph.roots.is_empty() { if !options.type_check_mode.is_true() || graph.roots.is_empty() {
return Ok((graph.into(), Default::default())); return Ok((graph.into(), Default::default()));
} }

View file

@ -8,9 +8,9 @@ use std::sync::Arc;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::resolve_url_or_path; use deno_core::resolve_url_or_path;
use deno_graph::GraphKind; use deno_graph::GraphKind;
@ -330,7 +330,7 @@ async fn resolve_compile_executable_output_path(
.map(PathBuf::from) .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.", "An executable name was not provided. One could not be inferred from the URL. Aborting.",
)).map(|output_path| { )).map(|output_path| {
get_os_specific_filepath(output_path, &compile_flags.target) 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_config::glob::PathOrPatternSet;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::sourcemap::SourceMap; use deno_core::sourcemap::SourceMap;
@ -430,7 +429,7 @@ fn collect_coverages(
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules() .ignore_node_modules()
.set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) .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 { let coverage_patterns = FilePatterns {
base: initial_cwd.to_path_buf(), base: initial_cwd.to_path_buf(),
@ -505,7 +504,7 @@ pub fn cover_files(
coverage_flags: CoverageFlags, coverage_flags: CoverageFlags,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
if coverage_flags.files.include.is_empty() { 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); let factory = CliFactory::from_flags(flags);
@ -527,7 +526,7 @@ pub fn cover_files(
cli_options.initial_cwd(), cli_options.initial_cwd(),
)?; )?;
if script_coverages.is_empty() { 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( let script_coverages = filter_coverages(
script_coverages, script_coverages,
@ -536,7 +535,7 @@ pub fn cover_files(
in_npm_pkg_checker.as_ref(), in_npm_pkg_checker.as_ref(),
); );
if script_coverages.is_empty() { 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 let proc_coverages: Vec<_> = script_coverages

View file

@ -62,10 +62,11 @@ async fn generate_doc_nodes_for_builtin_types(
)], )],
Vec::new(), Vec::new(),
); );
let roots = vec![source_file_specifier.clone()];
let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly); let mut graph = deno_graph::ModuleGraph::new(GraphKind::TypesOnly);
graph graph
.build( .build(
vec![source_file_specifier.clone()], roots.clone(),
&loader, &loader,
deno_graph::BuildOptions { deno_graph::BuildOptions {
imports: Vec::new(), imports: Vec::new(),
@ -85,14 +86,13 @@ async fn generate_doc_nodes_for_builtin_types(
let doc_parser = doc::DocParser::new( let doc_parser = doc::DocParser::new(
&graph, &graph,
parser, parser,
&roots,
doc::DocParserOptions { doc::DocParserOptions {
diagnostics: false, diagnostics: false,
private: doc_flags.private, private: doc_flags.private,
}, },
)?; )?;
let nodes = doc_parser.parse_module(&source_file_specifier)?.definitions; Ok(doc_parser.parse()?)
Ok(IndexMap::from([(source_file_specifier, nodes)]))
} }
pub async fn doc( pub async fn doc(
@ -158,19 +158,13 @@ pub async fn doc(
let doc_parser = doc::DocParser::new( let doc_parser = doc::DocParser::new(
&graph, &graph,
&capturing_parser, &capturing_parser,
&module_specifiers,
doc::DocParserOptions { doc::DocParserOptions {
private: doc_flags.private, private: doc_flags.private,
diagnostics: doc_flags.lint, diagnostics: doc_flags.lint,
}, },
)?; )?;
let doc_nodes_by_url = doc_parser.parse()?;
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);
}
if doc_flags.lint { if doc_flags.lint {
let diagnostics = doc_parser.take_diagnostics(); let diagnostics = doc_parser.take_diagnostics();
@ -191,29 +185,9 @@ pub async fn doc(
.await?; .await?;
let (_, deno_ns) = deno_ns.into_iter().next().unwrap(); let (_, deno_ns) = deno_ns.into_iter().next().unwrap();
let short_path = Rc::new(ShortPath::new( Some(deno_ns)
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<_>>(),
)
} else { } else {
Default::default() None
}; };
let mut main_entrypoint = None; let mut main_entrypoint = None;
@ -393,7 +367,7 @@ impl UsageComposer for DocComposer {
fn generate_docs_directory( fn generate_docs_directory(
doc_nodes_by_url: IndexMap<ModuleSpecifier, Vec<doc::DocNode>>, doc_nodes_by_url: IndexMap<ModuleSpecifier, Vec<doc::DocNode>>,
html_options: &DocHtmlFlag, 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>>, rewrite_map: Option<IndexMap<ModuleSpecifier, String>>,
main_entrypoint: Option<ModuleSpecifier>, main_entrypoint: Option<ModuleSpecifier>,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
@ -426,12 +400,12 @@ fn generate_docs_directory(
None None
}; };
let options = deno_doc::html::GenerateOptions { let mut options = deno_doc::html::GenerateOptions {
package_name: html_options.name.clone(), package_name: html_options.name.clone(),
main_entrypoint, main_entrypoint,
rewrite_map, rewrite_map,
href_resolver: Rc::new(DocResolver { href_resolver: Rc::new(DocResolver {
deno_ns, deno_ns: Default::default(),
strip_trailing_html: html_options.strip_trailing_html, strip_trailing_html: html_options.strip_trailing_html,
}), }),
usage_composer: Rc::new(DocComposer), 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")?; .context("Failed to generate HTML documentation")?;
files.insert("prism.js".to_string(), PRISM_JS.to_string()); 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::anyhow;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures; use deno_core::futures;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
@ -167,7 +166,7 @@ fn resolve_paths_with_options_batches(
Vec::with_capacity(members_fmt_options.len()); Vec::with_capacity(members_fmt_options.len());
for (_ctx, member_fmt_options) in members_fmt_options { for (_ctx, member_fmt_options) in members_fmt_options {
let files = 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() { if !files.is_empty() {
paths_with_options_batches.push(PathsWithOptions { paths_with_options_batches.push(PathsWithOptions {
base: member_fmt_options.files.base.clone(), base: member_fmt_options.files.base.clone(),
@ -177,7 +176,7 @@ fn resolve_paths_with_options_batches(
} }
} }
if paths_with_options_batches.is_empty() { 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) Ok(paths_with_options_batches)
} }
@ -224,7 +223,7 @@ async fn format_files(
fn collect_fmt_files( fn collect_fmt_files(
cli_options: &CliOptions, cli_options: &CliOptions,
files: FilePatterns, files: FilePatterns,
) -> Result<Vec<PathBuf>, AnyError> { ) -> Vec<PathBuf> {
FileCollector::new(|e| { FileCollector::new(|e| {
is_supported_ext_fmt(e.path) is_supported_ext_fmt(e.path)
|| (e.path.extension().is_none() && cli_options.ext_flag().is_some()) || (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) { if let Some(error_msg) = inner(&error, file_path) {
AnyError::from(generic_error(error_msg)) AnyError::msg(error_msg)
} else { } else {
AnyError::from(error) AnyError::from(error)
} }
@ -732,9 +731,9 @@ impl Formatter for CheckFormatter {
Ok(()) Ok(())
} else { } else {
let not_formatted_files_str = files_str(not_formatted_files_count); 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}", "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::resolve_url_or_path;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::url; use deno_core::url;
use deno_error::JsErrorClass;
use deno_graph::Dependency; use deno_graph::Dependency;
use deno_graph::GraphKind; use deno_graph::GraphKind;
use deno_graph::Module; use deno_graph::Module;
@ -664,9 +665,10 @@ impl<'a> GraphDisplayContext<'a> {
HttpsChecksumIntegrity(_) => "(checksum integrity error)", HttpsChecksumIntegrity(_) => "(checksum integrity error)",
Decode(_) => "(loading decode error)", Decode(_) => "(loading decode error)",
Loader(err) => { Loader(err) => {
match deno_runtime::errors::get_error_class_name(err) { if err.get_class() == "NotCapable" {
Some("NotCapable") => "(not capable, requires --allow-import)", "(not capable, requires --allow-import)"
_ => "(loading error)", } else {
"(loading error)"
} }
} }
Jsr(_) => "(loading error)", Jsr(_) => "(loading error)",

View file

@ -12,9 +12,9 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use deno_cache_dir::file_fetcher::CacheSetting; use deno_cache_dir::file_fetcher::CacheSetting;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::resolve_url_or_path; use deno_core::resolve_url_or_path;
use deno_core::url::Url; 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) { if EXEC_NAME_RE.is_match(exec_name) {
Ok(()) Ok(())
} else { } else {
Err(generic_error(format!( Err(anyhow!("Invalid executable name: {exec_name}"))
"Invalid executable name: {exec_name}"
)))
} }
} }
@ -223,7 +221,7 @@ pub async fn uninstall(
// ensure directory exists // ensure directory exists
if let Ok(metadata) = fs::metadata(&installation_dir) { if let Ok(metadata) = fs::metadata(&installation_dir) {
if !metadata.is_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 { if !removed {
return Err(generic_error(format!( return Err(anyhow!(
"No installation found for {}", "No installation found for {}",
uninstall_flags.name uninstall_flags.name
))); ));
} }
// There might be some extra files to delete // There might be some extra files to delete
@ -423,14 +421,14 @@ async fn create_install_shim(
// ensure directory exists // ensure directory exists
if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) { if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) {
if !metadata.is_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 { } else {
fs::create_dir_all(&shim_data.installation_dir)?; fs::create_dir_all(&shim_data.installation_dir)?;
}; };
if shim_data.file_path.exists() && !install_flags_global.force { 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).", "Existing installation found. Aborting (Use -f to overwrite).",
)); ));
}; };
@ -492,7 +490,7 @@ async fn resolve_shim_data(
let name = match name { let name = match name {
Some(name) => 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.", "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 { let log_level = match log_level {
Level::Debug => "debug", Level::Debug => "debug",
Level::Info => "info", Level::Info => "info",
_ => { _ => return Err(anyhow!(format!("invalid log level {log_level}"))),
return Err(generic_error(format!("invalid log level {log_level}")))
}
}; };
executable_args.push(log_level.to_string()); executable_args.push(log_level.to_string());
} }

View file

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

View file

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

View file

@ -7,7 +7,7 @@ use std::sync::Arc;
use deno_ast::SourceRange; use deno_ast::SourceRange;
use deno_config::workspace::WorkspaceResolver; use deno_config::workspace::WorkspaceResolver;
use deno_core::anyhow::anyhow; use deno_error::JsErrorBox;
use deno_graph::source::ResolutionKind; use deno_graph::source::ResolutionKind;
use deno_graph::source::ResolveError; use deno_graph::source::ResolveError;
use deno_graph::Range; use deno_graph::Range;
@ -187,7 +187,7 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> {
let resolution = self let resolution = self
.workspace_resolver .workspace_resolver
.resolve(specifier_text, &referrer_range.specifier) .resolve(specifier_text, &referrer_range.specifier)
.map_err(|err| ResolveError::Other(err.into()))?; .map_err(|err| ResolveError::Other(JsErrorBox::from_err(err)))?;
match resolution { match resolution {
deno_config::workspace::MappedResolution::Normal { deno_config::workspace::MappedResolution::Normal {
@ -220,7 +220,7 @@ impl<'a> deno_graph::source::Resolver for SloppyImportCaptureResolver<'a> {
} }
| deno_config::workspace::MappedResolution::PackageJson { .. } => { | deno_config::workspace::MappedResolution::PackageJson { .. } => {
// this error is ignored // 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> { ) -> Result<Vec<CollectedPublishPath>, AnyError> {
let diagnostics_collector = opts.diagnostics_collector; let diagnostics_collector = opts.diagnostics_collector;
let publish_paths = 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 publish_paths_set = publish_paths.iter().cloned().collect::<HashSet<_>>();
let capacity = publish_paths.len() + opts.force_include_paths.len(); let capacity = publish_paths.len() + opts.force_include_paths.len();
let mut paths = HashSet::with_capacity(capacity); let mut paths = HashSet::with_capacity(capacity);
@ -321,7 +321,7 @@ fn collect_paths(
cli_options: &CliOptions, cli_options: &CliOptions,
diagnostics_collector: &PublishDiagnosticsCollector, diagnostics_collector: &PublishDiagnosticsCollector,
file_patterns: FilePatterns, file_patterns: FilePatterns,
) -> Result<Vec<PathBuf>, AnyError> { ) -> Vec<PathBuf> {
FileCollector::new(|e| { FileCollector::new(|e| {
if !e.metadata.file_type().is_file() { if !e.metadata.file_type().is_file() {
if let Ok(specifier) = ModuleSpecifier::from_file_path(e.path) { 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::anyhow::anyhow;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::serde_json; use deno_core::serde_json;
use deno_core::serde_json::Value; use deno_core::serde_json::Value;
use deno_error::JsErrorBox;
use tokio::sync::mpsc::channel; use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::Receiver; use tokio::sync::mpsc::Receiver;
@ -47,7 +49,7 @@ pub enum RustylineSyncMessage {
} }
pub enum RustylineSyncResponse { pub enum RustylineSyncResponse {
PostMessage(Result<Value, AnyError>), PostMessage(Result<Value, CoreError>),
LspCompletions(Vec<ReplCompletionItem>), LspCompletions(Vec<ReplCompletionItem>),
} }
@ -61,7 +63,7 @@ impl RustylineSyncMessageSender {
&self, &self,
method: &str, method: &str,
params: Option<T>, params: Option<T>,
) -> Result<Value, AnyError> { ) -> Result<Value, CoreError> {
if let Err(err) = if let Err(err) =
self self
.message_tx .message_tx
@ -69,10 +71,11 @@ impl RustylineSyncMessageSender {
method: method.to_string(), method: method.to_string(),
params: params params: params
.map(|params| serde_json::to_value(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 { } else {
match self.response_rx.borrow_mut().blocking_recv().unwrap() { match self.response_rx.borrow_mut().blocking_recv().unwrap() {
RustylineSyncResponse::PostMessage(result) => result, RustylineSyncResponse::PostMessage(result) => result,

View file

@ -16,8 +16,9 @@ use deno_ast::ParsedSource;
use deno_ast::SourcePos; use deno_ast::SourcePos;
use deno_ast::SourceRangedForSpanned; use deno_ast::SourceRangedForSpanned;
use deno_ast::SourceTextInfo; use deno_ast::SourceTextInfo;
use deno_core::error::generic_error; use deno_core::anyhow::anyhow;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::channel::mpsc::UnboundedReceiver; use deno_core::futures::channel::mpsc::UnboundedReceiver;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
@ -27,6 +28,7 @@ use deno_core::unsync::spawn;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::LocalInspectorSession; use deno_core::LocalInspectorSession;
use deno_core::PollEventLoopOptions; use deno_core::PollEventLoopOptions;
use deno_error::JsErrorBox;
use deno_graph::Position; use deno_graph::Position;
use deno_graph::PositionRange; use deno_graph::PositionRange;
use deno_graph::SpecifierWithRange; use deno_graph::SpecifierWithRange;
@ -250,10 +252,10 @@ impl ReplSession {
let cwd_url = let cwd_url =
Url::from_directory_path(cli_options.initial_cwd()).map_err(|_| { Url::from_directory_path(cli_options.initial_cwd()).map_err(|_| {
generic_error(format!( anyhow!(
"Unable to construct URL from the path of cwd: {}", "Unable to construct URL from the path of cwd: {}",
cli_options.initial_cwd().to_string_lossy(), cli_options.initial_cwd().to_string_lossy(),
)) )
})?; })?;
let ts_config_for_emit = cli_options let ts_config_for_emit = cli_options
.resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?; .resolve_ts_config_for_emit(deno_config::deno_json::TsConfigType::Emit)?;
@ -322,7 +324,7 @@ impl ReplSession {
&mut self, &mut self,
method: &str, method: &str,
params: Option<T>, params: Option<T>,
) -> Result<Value, AnyError> { ) -> Result<Value, CoreError> {
self self
.worker .worker
.js_runtime .js_runtime
@ -339,7 +341,7 @@ impl ReplSession {
.await .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 self.worker.run_event_loop(true).await
} }
@ -400,21 +402,29 @@ impl ReplSession {
} }
Err(err) => { Err(err) => {
// handle a parsing diagnostic // 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) => { Some(diagnostic) => {
Ok(EvaluationOutput::Error(format_diagnostic(diagnostic))) Ok(EvaluationOutput::Error(format_diagnostic(diagnostic)))
} }
None => match err.downcast_ref::<ParseDiagnosticsError>() { None => {
Some(diagnostics) => Ok(EvaluationOutput::Error( match crate::util::result::any_and_jserrorbox_downcast_ref::<
diagnostics ParseDiagnosticsError,
.0 >(&err)
.iter() {
.map(format_diagnostic) Some(diagnostics) => Ok(EvaluationOutput::Error(
.collect::<Vec<_>>() diagnostics
.join("\n\n"), .0
)), .iter()
None => Err(err), .map(format_diagnostic)
}, .collect::<Vec<_>>()
.join("\n\n"),
)),
None => Err(err),
}
}
} }
} }
} }
@ -742,7 +752,7 @@ impl ReplSession {
async fn evaluate_expression( async fn evaluate_expression(
&mut self, &mut self,
expression: &str, expression: &str,
) -> Result<cdp::EvaluateResponse, AnyError> { ) -> Result<cdp::EvaluateResponse, CoreError> {
self self
.post_message_with_event_loop( .post_message_with_event_loop(
"Runtime.evaluate", "Runtime.evaluate",
@ -765,7 +775,9 @@ impl ReplSession {
}), }),
) )
.await .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::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use deno_core::error::generic_error; use deno_core::error::CoreError;
use deno_core::error::AnyError;
use deno_core::futures::StreamExt; use deno_core::futures::StreamExt;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::serde_json::{self}; use deno_core::serde_json::{self};
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::LocalInspectorSession; use deno_core::LocalInspectorSession;
use deno_error::JsErrorBox;
use deno_terminal::colors; use deno_terminal::colors;
use tokio::select; use tokio::select;
@ -66,19 +66,19 @@ pub struct HmrRunner {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl crate::worker::HmrRunner for HmrRunner { impl crate::worker::HmrRunner for HmrRunner {
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` // 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 self.enable_debugger().await
} }
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` // 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 self
.watcher_communicator .watcher_communicator
.change_restart_mode(WatcherRestartMode::Automatic); .change_restart_mode(WatcherRestartMode::Automatic);
self.disable_debugger().await self.disable_debugger().await
} }
async fn run(&mut self) -> Result<(), AnyError> { async fn run(&mut self) -> Result<(), CoreError> {
self self
.watcher_communicator .watcher_communicator
.change_restart_mode(WatcherRestartMode::Manual); .change_restart_mode(WatcherRestartMode::Manual);
@ -87,13 +87,13 @@ impl crate::worker::HmrRunner for HmrRunner {
select! { select! {
biased; biased;
Some(notification) = session_rx.next() => { 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" { 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(); 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" { } 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://") { if params.url.starts_with("file://") {
let file_url = Url::parse(&params.url).unwrap(); let file_url = Url::parse(&params.url).unwrap();
let file_path = file_url.to_file_path().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() => { 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 Some(changed_paths) = changed_paths else {
let _ = self.watcher_communicator.force_restart(); let _ = self.watcher_communicator.force_restart();
@ -187,7 +187,7 @@ impl HmrRunner {
} }
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` // 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 self
.session .session
.post_message::<()>("Debugger.enable", None) .post_message::<()>("Debugger.enable", None)
@ -200,7 +200,7 @@ impl HmrRunner {
} }
// TODO(bartlomieju): this code is duplicated in `cli/tools/coverage/mod.rs` // 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 self
.session .session
.post_message::<()>("Debugger.disable", None) .post_message::<()>("Debugger.disable", None)
@ -216,7 +216,7 @@ impl HmrRunner {
&mut self, &mut self,
script_id: &str, script_id: &str,
source: &str, source: &str,
) -> Result<cdp::SetScriptSourceResponse, AnyError> { ) -> Result<cdp::SetScriptSourceResponse, CoreError> {
let result = self let result = self
.session .session
.post_message( .post_message(
@ -229,15 +229,16 @@ impl HmrRunner {
) )
.await?; .await?;
Ok(serde_json::from_value::<cdp::SetScriptSourceResponse>( Ok(
result, serde_json::from_value::<cdp::SetScriptSourceResponse>(result)
)?) .map_err(JsErrorBox::from_err)?,
)
} }
async fn dispatch_hmr_event( async fn dispatch_hmr_event(
&mut self, &mut self,
script_id: &str, script_id: &str,
) -> Result<(), AnyError> { ) -> Result<(), CoreError> {
let expr = format!( let expr = format!(
"dispatchEvent(new CustomEvent(\"hmr\", {{ detail: {{ path: \"{}\" }} }}));", "dispatchEvent(new CustomEvent(\"hmr\", {{ detail: {{ path: \"{}\" }} }}));",
script_id script_id

View file

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

View file

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

View file

@ -3,6 +3,8 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::path::PathBuf; use std::path::PathBuf;
use deno_core::anyhow::Context;
use super::fmt::to_relative_path_or_remote_url; use super::fmt::to_relative_path_or_remote_url;
use super::*; 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>); pub struct Diagnostics(Vec<Diagnostic>);
impl Diagnostics { impl Diagnostics {

View file

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

View file

@ -10,7 +10,7 @@ use std::time::Duration;
use deno_config::glob::PathOrPatternSet; use deno_config::glob::PathOrPatternSet;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::JsError; use deno_core::error::CoreError;
use deno_core::futures::Future; use deno_core::futures::Future;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
@ -23,6 +23,7 @@ use notify::RecommendedWatcher;
use notify::RecursiveMode; use notify::RecursiveMode;
use notify::Watcher; use notify::Watcher;
use tokio::select; use tokio::select;
use tokio::sync::broadcast::error::RecvError;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedReceiver;
use tokio::time::sleep; use tokio::time::sleep;
@ -80,10 +81,13 @@ where
{ {
let result = watch_future.await; let result = watch_future.await;
if let Err(err) = result { if let Err(err) = result {
let error_string = match err.downcast_ref::<JsError>() { let error_string =
Some(e) => format_js_error(e), match crate::util::result::any_and_jserrorbox_downcast_ref::<CoreError>(
None => format!("{err:?}"), &err,
}; ) {
Some(CoreError::Js(e)) => format_js_error(e),
_ => format!("{err:?}"),
};
log::error!( log::error!(
"{}: {}", "{}: {}",
colors::red_bold("error"), colors::red_bold("error"),
@ -171,9 +175,9 @@ impl WatcherCommunicator {
pub async fn watch_for_changed_paths( pub async fn watch_for_changed_paths(
&self, &self,
) -> Result<Option<Vec<PathBuf>>, AnyError> { ) -> Result<Option<Vec<PathBuf>>, RecvError> {
let mut rx = self.changed_paths_rx.resubscribe(); 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) { 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::PathOrPatternSet;
use deno_config::glob::WalkEntry; use deno_config::glob::WalkEntry;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::unsync::spawn_blocking; use deno_core::unsync::spawn_blocking;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
@ -129,7 +128,7 @@ pub fn collect_specifiers(
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules() .ignore_node_modules()
.set_vendor_folder(vendor_folder) .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 let mut collected_files_as_urls = collected_files
.iter() .iter()
.map(|f| specifier_from_file_path(f).unwrap()) .map(|f| specifier_from_file_path(f).unwrap())
@ -169,7 +168,7 @@ pub fn clone_dir_recursive<
sys: &TSys, sys: &TSys,
from: &Path, from: &Path,
to: &Path, to: &Path,
) -> Result<(), AnyError> { ) -> Result<(), CopyDirRecursiveError> {
if cfg!(target_vendor = "apple") { if cfg!(target_vendor = "apple") {
if let Some(parent) = to.parent() { if let Some(parent) = to.parent() {
sys.fs_create_dir_all(parent)?; sys.fs_create_dir_all(parent)?;
@ -200,6 +199,47 @@ pub fn clone_dir_recursive<
Ok(()) 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. /// Copies a directory to another directory.
/// ///
/// Note: Does not handle symlinks. /// Note: Does not handle symlinks.
@ -213,13 +253,20 @@ pub fn copy_dir_recursive<
sys: &TSys, sys: &TSys,
from: &Path, from: &Path,
to: &Path, to: &Path,
) -> Result<(), AnyError> { ) -> Result<(), CopyDirRecursiveError> {
sys sys.fs_create_dir_all(to).map_err(|source| {
.fs_create_dir_all(to) CopyDirRecursiveError::Creating {
.with_context(|| format!("Creating {}", to.display()))?; path: to.to_path_buf(),
let read_dir = sys source,
.fs_read_dir(from) }
.with_context(|| format!("Reading {}", from.display()))?; })?;
let read_dir =
sys
.fs_read_dir(from)
.map_err(|source| CopyDirRecursiveError::Reading {
path: from.to_path_buf(),
source,
})?;
for entry in read_dir { for entry in read_dir {
let entry = entry?; let entry = entry?;
@ -228,12 +275,20 @@ pub fn copy_dir_recursive<
let new_to = to.join(entry.file_name()); let new_to = to.join(entry.file_name());
if file_type.is_dir() { if file_type.is_dir() {
copy_dir_recursive(sys, &new_from, &new_to).with_context(|| { copy_dir_recursive(sys, &new_from, &new_to).map_err(|source| {
format!("Dir {} to {}", new_from.display(), new_to.display()) CopyDirRecursiveError::Dir {
from: new_from.to_path_buf(),
to: new_to.to_path_buf(),
source: Box::new(source),
}
})?; })?;
} else if file_type.is_file() { } else if file_type.is_file() {
sys.fs_copy(&new_from, &new_to).with_context(|| { sys.fs_copy(&new_from, &new_to).map_err(|source| {
format!("Copying {} to {}", new_from.display(), new_to.display()) 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. // Copyright 2018-2025 the Deno authors. MIT license.
use std::convert::Infallible; 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> { pub trait InfallibleResultExt<T> {
fn unwrap_infallible(self) -> 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_ast::ModuleSpecifier;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::v8; use deno_core::v8;
@ -17,6 +18,7 @@ use deno_core::FeatureChecker;
use deno_core::ModuleLoader; use deno_core::ModuleLoader;
use deno_core::PollEventLoopOptions; use deno_core::PollEventLoopOptions;
use deno_core::SharedArrayBufferStore; use deno_core::SharedArrayBufferStore;
use deno_error::JsErrorBox;
use deno_runtime::code_cache; use deno_runtime::code_cache;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
@ -50,7 +52,6 @@ use crate::args::CliLockfile;
use crate::args::DenoSubcommand; use crate::args::DenoSubcommand;
use crate::args::NpmCachingStrategy; use crate::args::NpmCachingStrategy;
use crate::args::StorageKeyResolver; use crate::args::StorageKeyResolver;
use crate::errors;
use crate::node::CliNodeResolver; use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver; use crate::node::CliPackageJsonResolver;
use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolver;
@ -80,9 +81,9 @@ pub trait ModuleLoaderFactory: Send + Sync {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
pub trait HmrRunner: Send + Sync { pub trait HmrRunner: Send + Sync {
async fn start(&mut self) -> Result<(), AnyError>; async fn start(&mut self) -> Result<(), CoreError>;
async fn stop(&mut self) -> Result<(), AnyError>; async fn stop(&mut self) -> Result<(), CoreError>;
async fn run(&mut self) -> Result<(), AnyError>; async fn run(&mut self) -> Result<(), CoreError>;
} }
pub trait CliCodeCache: code_cache::CodeCache { pub trait CliCodeCache: code_cache::CodeCache {
@ -195,7 +196,7 @@ impl CliMainWorker {
Ok(()) Ok(())
} }
pub async fn run(&mut self) -> Result<i32, AnyError> { pub async fn run(&mut self) -> Result<i32, CoreError> {
let mut maybe_coverage_collector = let mut maybe_coverage_collector =
self.maybe_setup_coverage_collector().await?; self.maybe_setup_coverage_collector().await?;
let mut maybe_hmr_runner = self.maybe_setup_hmr_runner().await?; let mut maybe_hmr_runner = self.maybe_setup_hmr_runner().await?;
@ -216,7 +217,7 @@ impl CliMainWorker {
let result; let result;
select! { select! {
hmr_result = hmr_future => { hmr_result = hmr_future => {
result = hmr_result; result = hmr_result.map_err(Into::into);
}, },
event_loop_result = event_loop_future => { event_loop_result = event_loop_future => {
result = event_loop_result; result = event_loop_result;
@ -331,12 +332,12 @@ impl CliMainWorker {
executor.execute().await 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?; let id = self.worker.preload_main_module(&self.main_module).await?;
self.worker.evaluate_module(id).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?; let id = self.worker.preload_side_module(&self.main_module).await?;
self.worker.evaluate_module(id).await self.worker.evaluate_module(id).await
} }
@ -393,7 +394,7 @@ impl CliMainWorker {
&mut self, &mut self,
name: &'static str, name: &'static str,
source_code: &'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) self.worker.js_runtime.execute_script(name, source_code)
} }
} }
@ -465,7 +466,7 @@ impl CliMainWorkerFactory {
&self, &self,
mode: WorkerExecutionMode, mode: WorkerExecutionMode,
main_module: ModuleSpecifier, main_module: ModuleSpecifier,
) -> Result<CliMainWorker, AnyError> { ) -> Result<CliMainWorker, CoreError> {
self self
.create_custom_worker( .create_custom_worker(
mode, mode,
@ -484,7 +485,7 @@ impl CliMainWorkerFactory {
permissions: PermissionsContainer, permissions: PermissionsContainer,
custom_extensions: Vec<Extension>, custom_extensions: Vec<Extension>,
stdio: deno_runtime::deno_io::Stdio, stdio: deno_runtime::deno_io::Stdio,
) -> Result<CliMainWorker, AnyError> { ) -> Result<CliMainWorker, CoreError> {
let shared = &self.shared; let shared = &self.shared;
let CreateModuleLoaderResult { let CreateModuleLoaderResult {
module_loader, module_loader,
@ -513,16 +514,15 @@ impl CliMainWorkerFactory {
} }
// use a fake referrer that can be used to discover the package.json if necessary // use a fake referrer that can be used to discover the package.json if necessary
let referrer = let referrer = ModuleSpecifier::from_directory_path(
ModuleSpecifier::from_directory_path(self.shared.fs.cwd()?) self.shared.fs.cwd().map_err(JsErrorBox::from_err)?,
.unwrap() )
.join("package.json")?; .unwrap()
.join("package.json")?;
let package_folder = shared let package_folder = shared
.npm_resolver .npm_resolver
.resolve_pkg_folder_from_deno_module_req( .resolve_pkg_folder_from_deno_module_req(package_ref.req(), &referrer)
package_ref.req(), .map_err(JsErrorBox::from_err)?;
&referrer,
)?;
let main_module = self let main_module = self
.resolve_binary_entrypoint(&package_folder, package_ref.sub_path())?; .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_break_on_first_statement: shared.options.inspect_brk,
should_wait_for_inspector_session: shared.options.inspect_wait, should_wait_for_inspector_session: shared.options.inspect_wait,
strace_ops: shared.options.strace_ops.clone(), strace_ops: shared.options.strace_ops.clone(),
get_error_class_fn: Some(&errors::get_error_class_name),
cache_storage_dir, cache_storage_dir,
origin_storage_dir, origin_storage_dir,
stdio, stdio,
@ -834,7 +833,6 @@ fn create_web_worker_callback(
create_web_worker_cb, create_web_worker_cb,
format_js_error_fn: Some(Arc::new(format_js_error)), format_js_error_fn: Some(Arc::new(format_js_error)),
worker_type: args.worker_type, worker_type: args.worker_type,
get_error_class_fn: Some(&errors::get_error_class_name),
stdio: stdio.clone(), stdio: stdio.clone(),
cache_storage_dir, cache_storage_dir,
strace_ops: shared.options.strace_ops.clone(), strace_ops: shared.options.strace_ops.clone(),

View file

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

View file

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

View file

@ -16,6 +16,7 @@ path = "lib.rs"
[dependencies] [dependencies]
async-trait.workspace = true async-trait.workspace = true
deno_core.workspace = true deno_core.workspace = true
deno_error.workspace = true
rusqlite.workspace = true rusqlite.workspace = true
serde.workspace = true serde.workspace = true
sha2.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 std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use deno_core::error::type_error;
use deno_core::op2; use deno_core::op2;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
use deno_core::serde::Serialize; use deno_core::serde::Serialize;
@ -14,22 +13,38 @@ use deno_core::ByteString;
use deno_core::OpState; use deno_core::OpState;
use deno_core::Resource; use deno_core::Resource;
use deno_core::ResourceId; use deno_core::ResourceId;
use deno_error::JsErrorBox;
mod sqlite; mod sqlite;
pub use sqlite::SqliteBackedCache; pub use sqlite::SqliteBackedCache;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CacheError { pub enum CacheError {
#[class(type)]
#[error("CacheStorage is not available in this context")]
ContextUnsupported,
#[class(generic)]
#[error(transparent)] #[error(transparent)]
Sqlite(#[from] rusqlite::Error), Sqlite(#[from] rusqlite::Error),
#[class(generic)]
#[error(transparent)] #[error(transparent)]
JoinError(#[from] tokio::task::JoinError), JoinError(#[from] tokio::task::JoinError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Other(deno_core::error::AnyError), Other(JsErrorBox),
#[class(inherit)]
#[error("{0}")] #[error("{0}")]
Io(#[from] std::io::Error), 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)] #[derive(Clone)]
@ -237,9 +252,7 @@ where
state.put(cache); state.put(cache);
Ok(state.borrow::<CA>().clone()) Ok(state.borrow::<CA>().clone())
} else { } else {
Err(CacheError::Other(type_error( Err(CacheError::ContextUnsupported)
"CacheStorage is not available in this context",
)))
} }
} }

21
ext/cache/sqlite.rs vendored
View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -23,6 +23,7 @@ const-oid = "0.9.0"
ctr = "0.9.1" ctr = "0.9.1"
curve25519-dalek = "4.1.3" curve25519-dalek = "4.1.3"
deno_core.workspace = true deno_core.workspace = true
deno_error.workspace = true
deno_web.workspace = true deno_web.workspace = true
ed448-goldilocks = { version = "0.8.3", features = ["zeroize"] } ed448-goldilocks = { version = "0.8.3", features = ["zeroize"] }
elliptic-curve = { version = "0.13.1", features = ["std", "pem"] } 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 { pub enum DecryptError {
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
General(#[from] SharedError), General(
#[from]
#[inherit]
SharedError,
),
#[class(generic)]
#[error(transparent)] #[error(transparent)]
Pkcs1(#[from] rsa::pkcs1::Error), Pkcs1(#[from] rsa::pkcs1::Error),
#[class("DOMExceptionOperationError")]
#[error("Decryption failed")] #[error("Decryption failed")]
Failed, Failed,
#[class(type)]
#[error("invalid length")] #[error("invalid length")]
InvalidLength, InvalidLength,
#[class(type)]
#[error("invalid counter length. Currently supported 32/64/128 bits")] #[error("invalid counter length. Currently supported 32/64/128 bits")]
InvalidCounterLength, InvalidCounterLength,
#[class(type)]
#[error("tag length not equal to 128")] #[error("tag length not equal to 128")]
InvalidTagLength, InvalidTagLength,
#[class("DOMExceptionOperationError")]
#[error("invalid key or iv")] #[error("invalid key or iv")]
InvalidKeyOrIv, InvalidKeyOrIv,
#[class("DOMExceptionOperationError")]
#[error("tried to decrypt too much data")] #[error("tried to decrypt too much data")]
TooMuchData, TooMuchData,
#[class(type)]
#[error("iv length not equal to 12 or 16")] #[error("iv length not equal to 12 or 16")]
InvalidIvLength, InvalidIvLength,
#[class("DOMExceptionOperationError")]
#[error("{0}")] #[error("{0}")]
Rsa(rsa::Error), Rsa(rsa::Error),
} }

View file

@ -13,12 +13,15 @@ use spki::der::asn1::BitString;
use spki::der::Decode; use spki::der::Decode;
use spki::der::Encode; use spki::der::Encode;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum Ed25519Error { pub enum Ed25519Error {
#[class("DOMExceptionOperationError")]
#[error("Failed to export key")] #[error("Failed to export key")]
FailedExport, FailedExport,
#[class(generic)]
#[error(transparent)] #[error(transparent)]
Der(#[from] rsa::pkcs1::der::Error), Der(#[from] rsa::pkcs1::der::Error),
#[class(generic)]
#[error(transparent)] #[error(transparent)]
KeyRejected(#[from] ring::error::KeyRejected), 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 { pub enum EncryptError {
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
General(#[from] SharedError), General(
#[from]
#[inherit]
SharedError,
),
#[class(type)]
#[error("invalid length")] #[error("invalid length")]
InvalidLength, InvalidLength,
#[class("DOMExceptionOperationError")]
#[error("invalid key or iv")] #[error("invalid key or iv")]
InvalidKeyOrIv, InvalidKeyOrIv,
#[class(type)]
#[error("iv length not equal to 12 or 16")] #[error("iv length not equal to 12 or 16")]
InvalidIvLength, InvalidIvLength,
#[class(type)]
#[error("invalid counter length. Currently supported 32/64/128 bits")] #[error("invalid counter length. Currently supported 32/64/128 bits")]
InvalidCounterLength, InvalidCounterLength,
#[class("DOMExceptionOperationError")]
#[error("tried to encrypt too much data")] #[error("tried to encrypt too much data")]
TooMuchData, TooMuchData,
#[class("DOMExceptionOperationError")]
#[error("Encryption failed")] #[error("Encryption failed")]
Failed, Failed,
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,6 +18,7 @@ base64.workspace = true
bytes.workspace = true bytes.workspace = true
data-url.workspace = true data-url.workspace = true
deno_core.workspace = true deno_core.workspace = true
deno_error.workspace = true
deno_path_util.workspace = true deno_path_util.workspace = true
deno_permissions.workspace = true deno_permissions.workspace = true
deno_tls.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::url::Url;
use deno_core::CancelFuture; use deno_core::CancelFuture;
use deno_core::OpState; use deno_core::OpState;
use deno_error::JsErrorBox;
use http::StatusCode; use http::StatusCode;
use http_body_util::BodyExt; use http_body_util::BodyExt;
use tokio_util::io::ReaderStream; use tokio_util::io::ReaderStream;
@ -34,7 +35,7 @@ impl FetchHandler for FsFetchHandler {
let file = tokio::fs::File::open(path).map_err(|_| ()).await?; let file = tokio::fs::File::open(path).map_err(|_| ()).await?;
let stream = ReaderStream::new(file) let stream = ReaderStream::new(file)
.map_ok(hyper::body::Frame::data) .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 body = http_body_util::StreamBody::new(stream).boxed();
let response = http::Response::builder() let response = http::Response::builder()
.status(StatusCode::OK) .status(StatusCode::OK)

View file

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

View file

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

View file

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

View file

@ -35,14 +35,17 @@ thread_local! {
static LOCAL_THREAD_ID: RefCell<u32> = const { RefCell::new(0) }; static LOCAL_THREAD_ID: RefCell<u32> = const { RefCell::new(0) };
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CallbackError { pub enum CallbackError {
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Resource(deno_core::error::AnyError), Resource(#[from] deno_core::error::ResourceError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError), Permission(#[from] deno_permissions::PermissionCheckError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Other(deno_core::error::AnyError), Other(#[from] deno_error::JsErrorBox),
} }
#[derive(Clone)] #[derive(Clone)]
@ -63,13 +66,8 @@ impl PtrSymbol {
.clone() .clone()
.into_iter() .into_iter()
.map(libffi::middle::Type::try_from) .map(libffi::middle::Type::try_from)
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()?,
.map_err(CallbackError::Other)?, def.result.clone().try_into()?,
def
.result
.clone()
.try_into()
.map_err(CallbackError::Other)?,
); );
Ok(Self { cif, ptr }) Ok(Self { cif, ptr })
@ -540,10 +538,8 @@ pub fn op_ffi_unsafe_callback_ref(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
) -> Result<impl Future<Output = ()>, CallbackError> { ) -> Result<impl Future<Output = ()>, CallbackError> {
let state = state.borrow(); let state = state.borrow();
let callback_resource = state let callback_resource =
.resource_table state.resource_table.get::<UnsafeCallbackResource>(rid)?;
.get::<UnsafeCallbackResource>(rid)
.map_err(CallbackError::Resource)?;
Ok(async move { Ok(async move {
let info: &mut CallbackInfo = let info: &mut CallbackInfo =
@ -610,10 +606,8 @@ where
.parameters .parameters
.into_iter() .into_iter()
.map(libffi::middle::Type::try_from) .map(libffi::middle::Type::try_from)
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()?,
.map_err(CallbackError::Other)?, libffi::middle::Type::try_from(args.result)?,
libffi::middle::Type::try_from(args.result)
.map_err(CallbackError::Other)?,
); );
// SAFETY: CallbackInfo is leaked, is not null and stays valid as long as the callback exists. // 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 // It is up to the user to know that it is safe to call the `close()` on the
// UnsafeCallback instance. // UnsafeCallback instance.
unsafe { unsafe {
let callback_resource = state let callback_resource =
.resource_table state.resource_table.take::<UnsafeCallbackResource>(rid)?;
.take::<UnsafeCallbackResource>(rid)
.map_err(CallbackError::Resource)?;
let info = Box::from_raw(callback_resource.info); let info = Box::from_raw(callback_resource.info);
let _ = v8::Global::from_raw(scope, info.callback); let _ = v8::Global::from_raw(scope, info.callback);
let _ = v8::Global::from_raw(scope, info.context); 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::GarbageCollected;
use deno_core::OpState; use deno_core::OpState;
use deno_core::Resource; use deno_core::Resource;
use deno_error::JsErrorBox;
use deno_error::JsErrorClass;
use dlopen2::raw::Library; use dlopen2::raw::Library;
use serde::Deserialize; use serde::Deserialize;
use serde_value::ValueDeserializer; use serde_value::ValueDeserializer;
@ -22,20 +24,34 @@ use crate::turbocall;
use crate::turbocall::Turbocall; use crate::turbocall::Turbocall;
use crate::FfiPermissions; 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 { pub enum DlfcnError {
#[class(generic)]
#[error("Failed to register symbol {symbol}: {error}")] #[error("Failed to register symbol {symbol}: {error}")]
RegisterSymbol { RegisterSymbol {
symbol: String, symbol: String,
#[source] #[source]
error: dlopen2::Error, error: dlopen2::Error,
}, },
#[class(generic)]
#[error(transparent)] #[error(transparent)]
Dlopen(#[from] dlopen2::Error), Dlopen(#[from] dlopen2::Error),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Permission(#[from] deno_permissions::PermissionCheckError), Permission(#[from] deno_permissions::PermissionCheckError),
#[class(inherit)]
#[error(transparent)] #[error(transparent)]
Other(deno_core::error::AnyError), Other(#[from] JsErrorBox),
} }
pub struct DynamicLibraryResource { pub struct DynamicLibraryResource {
@ -190,13 +206,8 @@ where
.clone() .clone()
.into_iter() .into_iter()
.map(libffi::middle::Type::try_from) .map(libffi::middle::Type::try_from)
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()?,
.map_err(DlfcnError::Other)?, foreign_fn.result.clone().try_into()?,
foreign_fn
.result
.clone()
.try_into()
.map_err(DlfcnError::Other)?,
); );
let func_key = v8::String::new(scope, &symbol_key).unwrap(); 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()) }; unsafe { result.to_v8(scope, data.symbol.result_type.clone()) };
rv.set(result); rv.set(result);
} }
Err(err) => { Err(err) => deno_core::error::throw_js_error_class(scope, &err),
deno_core::_ops::throw_type_error(scope, err.to_string());
}
}; };
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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