1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-20 20:42:19 -05:00

refactor: update deno_core and use more concrete errors (#27620)

waiting for https://github.com/denoland/deno_core/pull/1043

Fixes #27672
This commit is contained in:
Leo Kettmeir 2025-01-17 18:41:52 +01:00 committed by GitHub
parent b55451b178
commit 054075730c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 474 additions and 202 deletions

20
Cargo.lock generated
View file

@ -1532,9 +1532,9 @@ dependencies = [
[[package]]
name = "deno_core"
version = "0.330.0"
version = "0.331.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd38bbbd68ed873165ccb630322704b44140d3a8c8d50f898beac4d1a8a3358c"
checksum = "ce2d1779358cad2bc56d71176298767be628d707bb75585f6f8a4be2da8ccda1"
dependencies = [
"anyhow",
"az",
@ -1658,9 +1658,9 @@ dependencies = [
[[package]]
name = "deno_error"
version = "0.5.3"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4da6a58de6932a96f84e133c072fd3b525966ee122a71f3efd48bbff2eed5ac"
checksum = "9c23dbc46d5804814b08b4675838f9884e3a52916987ec5105af36d42f9911b5"
dependencies = [
"deno_error_macro",
"libc",
@ -1672,9 +1672,9 @@ dependencies = [
[[package]]
name = "deno_error_macro"
version = "0.5.3"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46351dff93aed2039407c91e2ded2a5591e42d2795ab3d111288625bb710d3d2"
checksum = "babccedee31ce7e57c3e6dff2cb3ab8d68c49d0df8222fe0d11d628e65192790"
dependencies = [
"proc-macro2",
"quote",
@ -2151,9 +2151,9 @@ dependencies = [
[[package]]
name = "deno_ops"
version = "0.206.0"
version = "0.207.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c25ffa9d088ea00748dbef870bba110ac22ebf8cf7b2e9eb288409c5d852af3"
checksum = "96f000a21f6969b4c945bc8e9e785aa439f11ca4fd3fbddcd5bebc102167eb37"
dependencies = [
"indexmap 2.3.0",
"proc-macro-rules",
@ -6947,9 +6947,9 @@ dependencies = [
[[package]]
name = "serde_v8"
version = "0.239.0"
version = "0.240.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3caa6d882827148e5d9052d9d8d6d1c9d6ad426ed00cab46cafb8c07a0e7126a"
checksum = "cd0494d74c40ab94f53a19485de359ea6a55f05341b817b93440b673c1ce8ec6"
dependencies = [
"deno_error",
"num-bigint",

View file

@ -49,7 +49,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies]
deno_ast = { version = "=0.44.0", features = ["transpiling"] }
deno_core = { version = "0.330.0" }
deno_core = { version = "0.331.0" }
deno_bench_util = { version = "0.180.0", path = "./bench_util" }
deno_config = { version = "=0.45.0", features = ["workspace", "sync"] }
@ -123,7 +123,7 @@ dashmap = "5.5.3"
data-encoding = "2.3.3"
data-url = "=0.3.1"
deno_cache_dir = "=0.16.0"
deno_error = "=0.5.3"
deno_error = "=0.5.5"
deno_package_json = { version = "0.4.0", default-features = false }
deno_unsync = "0.4.2"
dlopen2 = "0.6.1"

View file

@ -61,11 +61,13 @@ 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,
pub enum AtomicWriteFileWithRetriesError {
#[class(inherit)]
#[error(transparent)]
Changed(JsErrorBox),
#[class(inherit)]
#[error("Failed writing lockfile")]
Io(#[source] std::io::Error),
}
impl CliLockfile {
@ -87,12 +89,16 @@ impl CliLockfile {
self.lockfile.lock().overwrite
}
pub fn write_if_changed(&self) -> Result<(), JsErrorBox> {
pub fn write_if_changed(
&self,
) -> Result<(), AtomicWriteFileWithRetriesError> {
if self.skip_write {
return Ok(());
}
self.error_if_changed()?;
self
.error_if_changed()
.map_err(AtomicWriteFileWithRetriesError::Changed)?;
let mut lockfile = self.lockfile.lock();
let Some(bytes) = lockfile.resolve_write_bytes() else {
return Ok(()); // nothing to do
@ -105,9 +111,7 @@ impl CliLockfile {
&bytes,
cache::CACHE_PERM,
)
.map_err(|source| {
JsErrorBox::from_err(AtomicWriteFileWithRetriesError { source })
})?;
.map_err(AtomicWriteFileWithRetriesError::Io)?;
lockfile.has_content_changed = false;
Ok(())
}

View file

@ -82,6 +82,7 @@ use deno_terminal::colors;
use dotenvy::from_filename;
pub use flags::*;
use import_map::resolve_import_map_value_from_specifier;
pub use lockfile::AtomicWriteFileWithRetriesError;
pub use lockfile::CliLockfile;
pub use lockfile::CliLockfileReadFromPathOptions;
use once_cell::sync::Lazy;

View file

@ -112,9 +112,9 @@ impl Emitter {
&self,
specifier: &ModuleSpecifier,
media_type: MediaType,
module_kind: deno_ast::ModuleKind,
module_kind: ModuleKind,
source: &Arc<str>,
) -> Result<String, AnyError> {
) -> Result<String, EmitParsedSourceHelperError> {
// Note: keep this in sync with the sync version below
let helper = EmitParsedSourceHelper(self);
match helper.pre_emit_parsed_source(specifier, module_kind, source) {

View file

@ -201,7 +201,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
match result {
Ok(v) => Ok(v),
Err(script_err) => {
if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = util::result::any_and_jserrorbox_downcast_ref::<ResolvePkgFolderFromDenoReqError>(&script_err) {
if let Some(worker::CreateCustomWorkerError::ResolvePkgFolderFromDenoReq(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_)))) = util::result::any_and_jserrorbox_downcast_ref::<worker::CreateCustomWorkerError>(&script_err) {
if flags.node_modules_dir.is_none() {
let mut flags = flags.deref().clone();
let watch = match &flags.subcommand {

View file

@ -13,8 +13,6 @@ use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleKind;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::error::ModuleLoaderError;
use deno_core::futures::future::FutureExt;
@ -45,6 +43,7 @@ use deno_lib::worker::ModuleLoaderFactory;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::code_cache;
use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::ops::require::UnableToGetCwdError;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
@ -99,6 +98,11 @@ pub enum PrepareModuleLoadError {
Check(#[from] CheckError),
#[class(inherit)]
#[error(transparent)]
AtomicWriteFileWithRetries(
#[from] crate::args::AtomicWriteFileWithRetriesError,
),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
@ -419,6 +423,55 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LoadCodeSourceError {
#[class(inherit)]
#[error(transparent)]
NpmModuleLoad(crate::resolver::NpmModuleLoadError),
#[class(inherit)]
#[error(transparent)]
LoadPreparedModule(#[from] LoadPreparedModuleError),
#[class(generic)]
#[error("Loading unprepared module: {}{}", .specifier, .maybe_referrer.as_ref().map(|r| format!(", imported from: {}", r)).unwrap_or_default())]
LoadUnpreparedModule {
specifier: ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>,
},
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LoadPreparedModuleError {
#[class(inherit)]
#[error(transparent)]
NpmModuleLoad(#[from] crate::emit::EmitParsedSourceHelperError),
#[class(inherit)]
#[error(transparent)]
LoadMaybeCjs(#[from] LoadMaybeCjsError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum LoadMaybeCjsError {
#[class(inherit)]
#[error(transparent)]
NpmModuleLoad(#[from] crate::emit::EmitParsedSourceHelperError),
#[class(inherit)]
#[error(transparent)]
TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(inherit)]
#[error("Could not resolve '{reference}'")]
pub struct CouldNotResolveError {
reference: deno_semver::npm::NpmPackageNvReference,
#[source]
#[inherit]
source: node_resolver::errors::PackageSubpathResolveError,
}
struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
lib: TsTypeLib,
is_worker: bool,
@ -443,7 +496,10 @@ impl<TGraphContainer: ModuleGraphContainer>
maybe_referrer: Option<&ModuleSpecifier>,
requested_module_type: RequestedModuleType,
) -> 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
.map_err(JsErrorBox::from_err)?;
let code = if self.shared.is_inspecting
|| code_source.media_type == MediaType::Wasm
{
@ -504,7 +560,7 @@ impl<TGraphContainer: ModuleGraphContainer>
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
) -> Result<ModuleCodeStringSource, AnyError> {
) -> Result<ModuleCodeStringSource, LoadCodeSourceError> {
if let Some(code_source) = self.load_prepared_module(specifier).await? {
return Ok(code_source);
}
@ -513,14 +569,14 @@ impl<TGraphContainer: ModuleGraphContainer>
.shared
.npm_module_loader
.load(specifier, maybe_referrer)
.await;
.await
.map_err(LoadCodeSourceError::NpmModuleLoad);
}
let mut msg = format!("Loading unprepared module: {specifier}");
if let Some(referrer) = maybe_referrer {
msg = format!("{}, imported from: {}", msg, referrer.as_str());
}
Err(anyhow!(msg))
Err(LoadCodeSourceError::LoadUnpreparedModule {
specifier: specifier.clone(),
maybe_referrer: maybe_referrer.cloned(),
})
}
fn resolve_referrer(
@ -543,7 +599,8 @@ impl<TGraphContainer: ModuleGraphContainer>
.map_err(|e| e.into())
} else {
// this cwd check is slow, so try to avoid it
let cwd = std::env::current_dir().context("Unable to get CWD")?;
let cwd = std::env::current_dir()
.map_err(|e| JsErrorBox::from_err(UnableToGetCwdError(e)))?;
deno_core::resolve_path(referrer, &cwd).map_err(|e| e.into())
}
}
@ -622,8 +679,11 @@ impl<TGraphContainer: ModuleGraphContainer>
ResolutionMode::Import,
NodeResolutionKind::Execution,
)
.with_context(|| {
format!("Could not resolve '{}'.", module.nv_reference)
.map_err(|source| {
JsErrorBox::from_err(CouldNotResolveError {
reference: module.nv_reference.clone(),
source,
})
})?
}
Some(Module::Node(module)) => module.specifier.clone(),
@ -644,7 +704,7 @@ impl<TGraphContainer: ModuleGraphContainer>
async fn load_prepared_module(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<ModuleCodeStringSource>, AnyError> {
) -> Result<Option<ModuleCodeStringSource>, LoadPreparedModuleError> {
// Note: keep this in sync with the sync version below
let graph = self.graph_container.graph();
match self.load_prepared_module_or_defer_emit(&graph, specifier)? {
@ -676,7 +736,8 @@ impl<TGraphContainer: ModuleGraphContainer>
}) => self
.load_maybe_cjs(specifier, media_type, source)
.await
.map(Some),
.map(Some)
.map_err(LoadPreparedModuleError::LoadMaybeCjs),
None => Ok(None),
}
}
@ -837,7 +898,7 @@ impl<TGraphContainer: ModuleGraphContainer>
specifier: &ModuleSpecifier,
media_type: MediaType,
original_source: &Arc<str>,
) -> Result<ModuleCodeStringSource, AnyError> {
) -> Result<ModuleCodeStringSource, LoadMaybeCjsError> {
let js_source = if media_type.is_emittable() {
Cow::Owned(
self

View file

@ -5,13 +5,14 @@ use std::sync::Arc;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_error::JsErrorBox;
use deno_graph::ParsedSourceStore;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker;
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
use node_resolver::analyze::CjsAnalysisExports;
use node_resolver::analyze::CjsCodeAnalysisError;
use node_resolver::analyze::CjsCodeAnalyzer;
use node_resolver::analyze::NodeCodeTranslator;
use serde::Deserialize;
@ -75,7 +76,7 @@ impl CliCjsCodeAnalyzer {
&self,
specifier: &ModuleSpecifier,
source: &str,
) -> Result<CliCjsAnalysis, AnyError> {
) -> Result<CliCjsAnalysis, CjsCodeAnalysisError> {
let source_hash = CacheDBHash::from_hashable(source);
if let Some(analysis) =
self.cache.get_cjs_analysis(specifier.as_str(), source_hash)
@ -102,9 +103,10 @@ impl CliCjsCodeAnalyzer {
deno_core::unsync::spawn_blocking({
let specifier = specifier.clone();
let source: Arc<str> = source.into();
move || -> Result<_, AnyError> {
let parsed_source =
maybe_parsed_source.map(Ok).unwrap_or_else(|| {
move || -> Result<_, CjsCodeAnalysisError> {
let parsed_source = maybe_parsed_source
.map(Ok)
.unwrap_or_else(|| {
deno_ast::parse_program(deno_ast::ParseParams {
specifier,
text: source,
@ -113,7 +115,8 @@ impl CliCjsCodeAnalyzer {
scope_analysis: false,
maybe_syntax: None,
})
})?;
})
.map_err(JsErrorBox::from_err)?;
let is_script = parsed_source.compute_is_script();
let is_cjs = cjs_tracker.is_cjs_with_known_is_script(
parsed_source.specifier(),
@ -151,7 +154,7 @@ impl CjsCodeAnalyzer for CliCjsCodeAnalyzer {
&self,
specifier: &ModuleSpecifier,
source: Option<Cow<'a, str>>,
) -> Result<ExtNodeCjsAnalysis<'a>, AnyError> {
) -> Result<ExtNodeCjsAnalysis<'a>, CjsCodeAnalysisError> {
let source = match source {
Some(source) => source,
None => {

View file

@ -1,6 +1,7 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::path::PathBuf;
use std::sync::Arc;
use async_trait::async_trait;
@ -8,8 +9,6 @@ use dashmap::DashSet;
use deno_ast::MediaType;
use deno_config::workspace::MappedResolutionDiagnostic;
use deno_config::workspace::MappedResolutionError;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_core::ModuleSourceCode;
use deno_core::ModuleSpecifier;
@ -84,6 +83,62 @@ pub struct NpmModuleLoader {
node_code_translator: Arc<CliNodeCodeTranslator>,
}
#[derive(Debug, Error, deno_error::JsError)]
pub enum NpmModuleLoadError {
#[class(inherit)]
#[error(transparent)]
NotSupportedKindInNpm(#[from] NotSupportedKindInNpmError),
#[class(inherit)]
#[error(transparent)]
ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError),
#[class(inherit)]
#[error(transparent)]
TranslateCjsToEsm(#[from] node_resolver::analyze::TranslateCjsToEsmError),
#[class(inherit)]
#[error("{}", format_message(file_path, maybe_referrer))]
Fs {
file_path: PathBuf,
maybe_referrer: Option<ModuleSpecifier>,
#[source]
#[inherit]
source: deno_runtime::deno_io::fs::FsError,
},
}
fn format_message(
file_path: &std::path::Path,
maybe_referrer: &Option<ModuleSpecifier>,
) -> String {
if file_path.is_dir() {
// directory imports are not allowed when importing from an
// ES module, so provide the user with a helpful error message
let dir_path = file_path;
let mut msg = "Directory import ".to_string();
msg.push_str(&dir_path.to_string_lossy());
if let Some(referrer) = maybe_referrer {
msg.push_str(" is not supported resolving import from ");
msg.push_str(referrer.as_str());
let entrypoint_name = ["index.mjs", "index.js", "index.cjs"]
.iter()
.find(|e| dir_path.join(e).is_file());
if let Some(entrypoint_name) = entrypoint_name {
msg.push_str("\nDid you mean to import ");
msg.push_str(entrypoint_name);
msg.push_str(" within the directory?");
}
}
msg
} else {
let mut msg = "Unable to load ".to_string();
msg.push_str(&file_path.to_string_lossy());
if let Some(referrer) = maybe_referrer {
msg.push_str(" imported from ");
msg.push_str(referrer.as_str());
}
msg
}
}
impl NpmModuleLoader {
pub fn new(
cjs_tracker: Arc<CliCjsTracker>,
@ -101,50 +156,26 @@ impl NpmModuleLoader {
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
) -> Result<ModuleCodeStringSource, AnyError> {
) -> Result<ModuleCodeStringSource, NpmModuleLoadError> {
let file_path = specifier.to_file_path().unwrap();
let code = self
.fs
.read_file_async(file_path.clone(), None)
.await
.map_err(AnyError::from)
.with_context(|| {
if file_path.is_dir() {
// directory imports are not allowed when importing from an
// ES module, so provide the user with a helpful error message
let dir_path = file_path;
let mut msg = "Directory import ".to_string();
msg.push_str(&dir_path.to_string_lossy());
if let Some(referrer) = &maybe_referrer {
msg.push_str(" is not supported resolving import from ");
msg.push_str(referrer.as_str());
let entrypoint_name = ["index.mjs", "index.js", "index.cjs"]
.iter()
.find(|e| dir_path.join(e).is_file());
if let Some(entrypoint_name) = entrypoint_name {
msg.push_str("\nDid you mean to import ");
msg.push_str(entrypoint_name);
msg.push_str(" within the directory?");
}
}
msg
} else {
let mut msg = "Unable to load ".to_string();
msg.push_str(&file_path.to_string_lossy());
if let Some(referrer) = &maybe_referrer {
msg.push_str(" imported from ");
msg.push_str(referrer.as_str());
}
msg
}
.map_err(|source| NpmModuleLoadError::Fs {
file_path,
maybe_referrer: maybe_referrer.cloned(),
source,
})?;
let media_type = MediaType::from_specifier(specifier);
if media_type.is_emittable() {
return Err(AnyError::from(NotSupportedKindInNpmError {
media_type,
specifier: specifier.clone(),
}));
return Err(NpmModuleLoadError::NotSupportedKindInNpm(
NotSupportedKindInNpmError {
media_type,
specifier: specifier.clone(),
},
));
}
let code = if self.cjs_tracker.is_maybe_cjs(specifier, media_type)? {

View file

@ -37,6 +37,7 @@ use deno_core::futures::AsyncReadExt;
use deno_core::futures::AsyncSeekExt;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_graph::ModuleGraph;
use deno_lib::cache::DenoDir;
use deno_lib::standalone::virtual_fs::FileSystemCaseSensitivity;
@ -278,7 +279,7 @@ impl StandaloneModules {
pub fn resolve_specifier<'a>(
&'a self,
specifier: &'a ModuleSpecifier,
) -> Result<Option<&'a ModuleSpecifier>, AnyError> {
) -> Result<Option<&'a ModuleSpecifier>, JsErrorBox> {
if specifier.scheme() == "file" {
Ok(Some(specifier))
} else {

View file

@ -414,7 +414,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
let code_source = shared
.npm_module_loader
.load(&original_specifier, maybe_referrer.as_ref())
.await?;
.await
.map_err(JsErrorBox::from_err)?;
let code_cache_entry = shared.get_code_cache(
&code_source.found_url,
code_source.code.as_bytes(),
@ -477,7 +478,8 @@ impl ModuleLoader for EmbeddedModuleLoader {
let source = shared
.node_code_translator
.translate_cjs_to_esm(&module_specifier, Some(source))
.await?;
.await
.map_err(JsErrorBox::from_err)?;
let module_source = match source {
Cow::Owned(source) => ModuleSourceCode::String(source.into()),
Cow::Borrowed(source) => {

View file

@ -17,6 +17,7 @@ use deno_core::url::Url;
use deno_core::FastString;
use deno_core::ModuleSourceCode;
use deno_core::ModuleType;
use deno_error::JsErrorBox;
use deno_lib::standalone::virtual_fs::VirtualDirectoryEntries;
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
use deno_npm::resolution::SerializedNpmResolutionSnapshotPackage;
@ -441,12 +442,15 @@ impl RemoteModulesStore {
pub fn resolve_specifier<'a>(
&'a self,
specifier: &'a Url,
) -> Result<Option<&'a Url>, AnyError> {
) -> Result<Option<&'a Url>, JsErrorBox> {
let mut count = 0;
let mut current = specifier;
loop {
if count > 10 {
bail!("Too many redirects resolving '{}'", specifier);
return Err(JsErrorBox::generic(format!(
"Too many redirects resolving '{}'",
specifier
)));
}
match self.specifiers.get(current) {
Some(RemoteModulesStoreSpecifierValue::Redirect(to)) => {

View file

@ -48,6 +48,7 @@ use crate::util::fs::collect_specifiers;
use crate::util::path::is_script_ext;
use crate::util::path::matches_pattern_or_exact_path;
use crate::worker::CliMainWorkerFactory;
use crate::worker::CreateCustomWorkerError;
mod mitata;
mod reporters;
@ -164,7 +165,7 @@ async fn bench_specifier(
.await
{
Ok(()) => Ok(()),
Err(CoreError::Js(error)) => {
Err(CreateCustomWorkerError::Core(CoreError::Js(error))) => {
sender.send(BenchEvent::UncaughtError(
specifier.to_string(),
Box::new(error),
@ -182,7 +183,7 @@ async fn bench_specifier_inner(
specifier: ModuleSpecifier,
sender: &UnboundedSender<BenchEvent>,
filter: TestFilter,
) -> Result<(), CoreError> {
) -> Result<(), CreateCustomWorkerError> {
let mut worker = worker_factory
.create_custom_worker(
WorkerExecutionMode::Bench,
@ -201,7 +202,7 @@ async fn bench_specifier_inner(
// Ensure that there are no pending exceptions before we start running tests
worker.run_up_to_duration(Duration::from_millis(0)).await?;
worker.dispatch_load_event()?;
worker.dispatch_load_event().map_err(CoreError::Js)?;
let benchmarks = {
let state_rc = worker.js_runtime.op_state();
@ -236,11 +237,13 @@ async fn bench_specifier_inner(
used_only,
names: benchmarks.iter().map(|(d, _)| d.name.clone()).collect(),
}))
.map_err(JsErrorBox::from_err)?;
.map_err(JsErrorBox::from_err)
.map_err(CoreError::JsBox)?;
for (desc, function) in benchmarks {
sender
.send(BenchEvent::Wait(desc.id))
.map_err(JsErrorBox::from_err)?;
.map_err(JsErrorBox::from_err)
.map_err(CoreError::JsBox)?;
let call = worker.js_runtime.call(&function);
let result = worker
.js_runtime
@ -249,18 +252,26 @@ async fn bench_specifier_inner(
let scope = &mut worker.js_runtime.handle_scope();
let result = v8::Local::new(scope, result);
let result = serde_v8::from_v8::<BenchResult>(scope, result)
.map_err(JsErrorBox::from_err)?;
.map_err(JsErrorBox::from_err)
.map_err(CoreError::JsBox)?;
sender
.send(BenchEvent::Result(desc.id, result))
.map_err(JsErrorBox::from_err)?;
.map_err(JsErrorBox::from_err)
.map_err(CoreError::JsBox)?;
}
// Ignore `defaultPrevented` of the `beforeunload` event. We don't allow the
// event loop to continue beyond what's needed to await results.
worker.dispatch_beforeunload_event()?;
worker.dispatch_process_beforeexit_event()?;
worker.dispatch_unload_event()?;
worker.dispatch_process_exit_event()?;
worker
.dispatch_beforeunload_event()
.map_err(CoreError::Js)?;
worker
.dispatch_process_beforeexit_event()
.map_err(CoreError::Js)?;
worker.dispatch_unload_event().map_err(CoreError::Js)?;
worker
.dispatch_process_exit_event()
.map_err(CoreError::Js)?;
// Ensure the worker has settled so we can catch any remaining unhandled rejections. We don't
// want to wait forever here.

View file

@ -18,10 +18,12 @@ use deno_config::glob::PathOrPatternSet;
use deno_core::anyhow::anyhow;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::serde_json;
use deno_core::sourcemap::SourceMap;
use deno_core::url::Url;
use deno_core::LocalInspectorSession;
use deno_error::JsErrorBox;
use deno_resolver::npm::DenoInNpmPackageChecker;
use node_resolver::InNpmPackageChecker;
use regex::Regex;
@ -53,7 +55,7 @@ pub struct CoverageCollector {
#[async_trait::async_trait(?Send)]
impl crate::worker::CoverageCollector for CoverageCollector {
async fn start_collecting(&mut self) -> Result<(), AnyError> {
async fn start_collecting(&mut self) -> Result<(), CoreError> {
self.enable_debugger().await?;
self.enable_profiler().await?;
self
@ -67,7 +69,7 @@ impl crate::worker::CoverageCollector for CoverageCollector {
Ok(())
}
async fn stop_collecting(&mut self) -> Result<(), AnyError> {
async fn stop_collecting(&mut self) -> Result<(), CoreError> {
fs::create_dir_all(&self.dir)?;
let script_coverages = self.take_precise_coverage().await?.result;
@ -88,7 +90,8 @@ impl crate::worker::CoverageCollector for CoverageCollector {
let filepath = self.dir.join(filename);
let mut out = BufWriter::new(File::create(&filepath)?);
let coverage = serde_json::to_string(&script_coverage)?;
let coverage = serde_json::to_string(&script_coverage)
.map_err(JsErrorBox::from_err)?;
let formatted_coverage =
format_json(&filepath, &coverage, &Default::default())
.ok()
@ -111,7 +114,7 @@ impl CoverageCollector {
Self { dir, session }
}
async fn enable_debugger(&mut self) -> Result<(), AnyError> {
async fn enable_debugger(&mut self) -> Result<(), CoreError> {
self
.session
.post_message::<()>("Debugger.enable", None)
@ -119,7 +122,7 @@ impl CoverageCollector {
Ok(())
}
async fn enable_profiler(&mut self) -> Result<(), AnyError> {
async fn enable_profiler(&mut self) -> Result<(), CoreError> {
self
.session
.post_message::<()>("Profiler.enable", None)
@ -127,7 +130,7 @@ impl CoverageCollector {
Ok(())
}
async fn disable_debugger(&mut self) -> Result<(), AnyError> {
async fn disable_debugger(&mut self) -> Result<(), CoreError> {
self
.session
.post_message::<()>("Debugger.disable", None)
@ -135,7 +138,7 @@ impl CoverageCollector {
Ok(())
}
async fn disable_profiler(&mut self) -> Result<(), AnyError> {
async fn disable_profiler(&mut self) -> Result<(), CoreError> {
self
.session
.post_message::<()>("Profiler.disable", None)
@ -146,26 +149,28 @@ impl CoverageCollector {
async fn start_precise_coverage(
&mut self,
parameters: cdp::StartPreciseCoverageArgs,
) -> Result<cdp::StartPreciseCoverageResponse, AnyError> {
) -> Result<cdp::StartPreciseCoverageResponse, CoreError> {
let return_value = self
.session
.post_message("Profiler.startPreciseCoverage", Some(parameters))
.await?;
let return_object = serde_json::from_value(return_value)?;
let return_object =
serde_json::from_value(return_value).map_err(JsErrorBox::from_err)?;
Ok(return_object)
}
async fn take_precise_coverage(
&mut self,
) -> Result<cdp::TakePreciseCoverageResponse, AnyError> {
) -> Result<cdp::TakePreciseCoverageResponse, CoreError> {
let return_value = self
.session
.post_message::<()>("Profiler.takePreciseCoverage", None)
.await?;
let return_object = serde_json::from_value(return_value)?;
let return_object =
serde_json::from_value(return_value).map_err(JsErrorBox::from_err)?;
Ok(return_object)
}

View file

@ -87,6 +87,7 @@ use crate::util::path::is_script_ext;
use crate::util::path::matches_pattern_or_exact_path;
use crate::worker::CliMainWorkerFactory;
use crate::worker::CoverageCollector;
use crate::worker::CreateCustomWorkerError;
mod channel;
pub mod fmt;
@ -614,7 +615,10 @@ async fn configure_main_worker(
permissions_container: PermissionsContainer,
worker_sender: TestEventWorkerSender,
options: &TestSpecifierOptions,
) -> Result<(Option<Box<dyn CoverageCollector>>, MainWorker), CoreError> {
) -> Result<
(Option<Box<dyn CoverageCollector>>, MainWorker),
CreateCustomWorkerError,
> {
let mut worker = worker_factory
.create_custom_worker(
WorkerExecutionMode::Test,
@ -647,7 +651,7 @@ async fn configure_main_worker(
&worker.js_runtime.op_state(),
TestEvent::UncaughtError(specifier.to_string(), Box::new(err)),
)
.map_err(JsErrorBox::from_err)?;
.map_err(|e| CoreError::JsBox(JsErrorBox::from_err(e)))?;
Ok(())
}
Err(err) => Err(err),
@ -687,7 +691,7 @@ pub async fn test_specifier(
.await
{
Ok(()) => Ok(()),
Err(CoreError::Js(err)) => {
Err(TestSpecifierError::Core(CoreError::Js(err))) => {
send_test_event(
&worker.js_runtime.op_state(),
TestEvent::UncaughtError(specifier.to_string(), Box::new(err)),
@ -698,6 +702,16 @@ pub async fn test_specifier(
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum TestSpecifierError {
#[class(inherit)]
#[error(transparent)]
Core(#[from] CoreError),
#[class(inherit)]
#[error(transparent)]
RunTestsForWorker(#[from] RunTestsForWorkerErr),
}
/// Test a single specifier as documentation containing test programs, an executable test module or
/// both.
#[allow(clippy::too_many_arguments)]
@ -707,19 +721,21 @@ async fn test_specifier_inner(
specifier: ModuleSpecifier,
fail_fast_tracker: FailFastTracker,
options: TestSpecifierOptions,
) -> Result<(), CoreError> {
) -> Result<(), TestSpecifierError> {
// Ensure that there are no pending exceptions before we start running tests
worker.run_up_to_duration(Duration::from_millis(0)).await?;
worker.dispatch_load_event()?;
worker.dispatch_load_event().map_err(CoreError::Js)?;
run_tests_for_worker(worker, &specifier, &options, &fail_fast_tracker)
.await?;
// Ignore `defaultPrevented` of the `beforeunload` event. We don't allow the
// event loop to continue beyond what's needed to await results.
worker.dispatch_beforeunload_event()?;
worker.dispatch_unload_event()?;
worker
.dispatch_beforeunload_event()
.map_err(CoreError::Js)?;
worker.dispatch_unload_event().map_err(CoreError::Js)?;
// Ensure all output has been flushed
_ = worker
@ -780,12 +796,25 @@ pub fn send_test_event(
.send(event)
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum RunTestsForWorkerErr {
#[class(inherit)]
#[error(transparent)]
ChannelClosed(#[from] ChannelClosedError),
#[class(inherit)]
#[error(transparent)]
Core(#[from] CoreError),
#[class(inherit)]
#[error(transparent)]
SerdeV8(#[from] serde_v8::Error),
}
pub async fn run_tests_for_worker(
worker: &mut MainWorker,
specifier: &ModuleSpecifier,
options: &TestSpecifierOptions,
fail_fast_tracker: &FailFastTracker,
) -> Result<(), AnyError> {
) -> Result<(), RunTestsForWorkerErr> {
let state_rc = worker.js_runtime.op_state();
// Take whatever tests have been registered
let TestContainer(tests, test_functions) =
@ -814,7 +843,7 @@ async fn run_tests_for_worker_inner(
test_functions: Vec<v8::Global<v8::Function>>,
options: &TestSpecifierOptions,
fail_fast_tracker: &FailFastTracker,
) -> Result<(), AnyError> {
) -> Result<(), RunTestsForWorkerErr> {
let unfiltered = tests.len();
let state_rc = worker.js_runtime.op_state();
@ -1109,7 +1138,7 @@ async fn wait_for_activity_to_stabilize(
before: RuntimeActivityStats,
sanitize_ops: bool,
sanitize_resources: bool,
) -> Result<Option<RuntimeActivityDiff>, AnyError> {
) -> Result<Option<RuntimeActivityDiff>, CoreError> {
// First, check to see if there's any diff at all. If not, just continue.
let after = stats.clone().capture(filter);
let mut diff = RuntimeActivityStats::diff(&before, &after);

View file

@ -36,7 +36,7 @@ pub fn any_and_jserrorbox_downcast_ref<
})
.or_else(|| {
err.downcast_ref::<CoreError>().and_then(|e| match e {
CoreError::JsNative(e) => e.as_any().downcast_ref::<E>(),
CoreError::JsBox(e) => e.as_any().downcast_ref::<E>(),
_ => None,
})
})

View file

@ -4,8 +4,6 @@ use std::path::Path;
use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::error::CoreError;
use deno_core::futures::FutureExt;
use deno_core::v8;
@ -19,6 +17,7 @@ use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::worker::MainWorker;
use deno_runtime::WorkerExecutionMode;
use deno_semver::npm::NpmPackageReqReference;
use node_resolver::errors::ResolvePkgJsonBinExportError;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use sys_traits::EnvCurrentDir;
@ -52,8 +51,8 @@ pub trait CliCodeCache: code_cache::CodeCache {
#[async_trait::async_trait(?Send)]
pub trait CoverageCollector: Send + Sync {
async fn start_collecting(&mut self) -> Result<(), AnyError>;
async fn stop_collecting(&mut self) -> Result<(), AnyError>;
async fn start_collecting(&mut self) -> Result<(), CoreError>;
async fn stop_collecting(&mut self) -> Result<(), CoreError>;
}
pub type CreateHmrRunnerCb = Box<
@ -91,7 +90,7 @@ impl CliMainWorker {
self.worker.into_main_worker()
}
pub async fn setup_repl(&mut self) -> Result<(), AnyError> {
pub async fn setup_repl(&mut self) -> Result<(), CoreError> {
self.worker.run_event_loop(false).await?;
Ok(())
}
@ -172,7 +171,7 @@ impl CliMainWorker {
Ok(self.worker.exit_code())
}
pub async fn run_for_watcher(self) -> Result<(), AnyError> {
pub async fn run_for_watcher(self) -> Result<(), CoreError> {
/// The FileWatcherModuleExecutor provides module execution with safe dispatching of life-cycle events by tracking the
/// state of any pending events and emitting accordingly on drop in the case of a future
/// cancellation.
@ -191,7 +190,7 @@ impl CliMainWorker {
/// Execute the given main module emitting load and unload events before and after execution
/// respectively.
pub async fn execute(&mut self) -> Result<(), AnyError> {
pub async fn execute(&mut self) -> Result<(), CoreError> {
self.inner.execute_main_module().await?;
self.inner.worker.dispatch_load_event()?;
self.pending_unload = true;
@ -245,7 +244,7 @@ impl CliMainWorker {
pub async fn maybe_setup_hmr_runner(
&mut self,
) -> Result<Option<Box<dyn HmrRunner>>, AnyError> {
) -> Result<Option<Box<dyn HmrRunner>>, CoreError> {
let Some(setup_hmr_runner) = self.shared.create_hmr_runner.as_ref() else {
return Ok(None);
};
@ -267,7 +266,7 @@ impl CliMainWorker {
pub async fn maybe_setup_coverage_collector(
&mut self,
) -> Result<Option<Box<dyn CoverageCollector>>, AnyError> {
) -> Result<Option<Box<dyn CoverageCollector>>, CoreError> {
let Some(create_coverage_collector) =
self.shared.create_coverage_collector.as_ref()
else {
@ -296,6 +295,58 @@ impl CliMainWorker {
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ResolveBinaryEntrypointError {
#[class(inherit)]
#[error(transparent)]
ResolvePkgJsonBinExport(ResolvePkgJsonBinExportError),
#[class(generic)]
#[error("{original:#}\n\nFallback failed: {fallback:#}")]
Fallback {
fallback: ResolveBinaryEntrypointFallbackError,
original: ResolvePkgJsonBinExportError,
},
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ResolveBinaryEntrypointFallbackError {
#[class(inherit)]
#[error(transparent)]
PackageSubpathResolve(node_resolver::errors::PackageSubpathResolveError),
#[class(generic)]
#[error("Cannot find module '{0}'")]
ModuleNotFound(ModuleSpecifier),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CreateCustomWorkerError {
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
#[class(inherit)]
#[error(transparent)]
Core(#[from] CoreError),
#[class(inherit)]
#[error(transparent)]
ResolvePkgFolderFromDenoReq(
#[from] deno_resolver::npm::ResolvePkgFolderFromDenoReqError,
),
#[class(inherit)]
#[error(transparent)]
UrlParse(#[from] deno_core::url::ParseError),
#[class(inherit)]
#[error(transparent)]
ResolveBinaryEntrypoint(#[from] ResolveBinaryEntrypointError),
#[class(inherit)]
#[error(transparent)]
NpmPackageReq(JsErrorBox),
#[class(inherit)]
#[error(transparent)]
AtomicWriteFileWithRetries(
#[from] crate::args::AtomicWriteFileWithRetriesError,
),
}
pub struct CliMainWorkerFactory {
lib_main_worker_factory: LibMainWorkerFactory<CliSys>,
maybe_lockfile: Option<Arc<CliLockfile>>,
@ -344,7 +395,7 @@ impl CliMainWorkerFactory {
&self,
mode: WorkerExecutionMode,
main_module: ModuleSpecifier,
) -> Result<CliMainWorker, CoreError> {
) -> Result<CliMainWorker, CreateCustomWorkerError> {
self
.create_custom_worker(
mode,
@ -363,7 +414,7 @@ impl CliMainWorkerFactory {
permissions: PermissionsContainer,
custom_extensions: Vec<Extension>,
stdio: deno_runtime::deno_io::Stdio,
) -> Result<CliMainWorker, CoreError> {
) -> Result<CliMainWorker, CreateCustomWorkerError> {
let main_module = if let Ok(package_ref) =
NpmPackageReqReference::from_specifier(&main_module)
{
@ -381,19 +432,20 @@ impl CliMainWorkerFactory {
PackageCaching::All
},
)
.await?;
.await
.map_err(CreateCustomWorkerError::NpmPackageReq)?;
}
// use a fake referrer that can be used to discover the package.json if necessary
let referrer = ModuleSpecifier::from_directory_path(
self.sys.env_current_dir().map_err(JsErrorBox::from_err)?,
)
.unwrap()
.join("package.json")?;
let package_folder = self
.npm_resolver
.resolve_pkg_folder_from_deno_module_req(package_ref.req(), &referrer)
.map_err(JsErrorBox::from_err)?;
let referrer =
ModuleSpecifier::from_directory_path(self.sys.env_current_dir()?)
.unwrap()
.join("package.json")?;
let package_folder =
self.npm_resolver.resolve_pkg_folder_from_deno_module_req(
package_ref.req(),
&referrer,
)?;
let main_module = self
.resolve_binary_entrypoint(&package_folder, package_ref.sub_path())?;
@ -447,7 +499,7 @@ impl CliMainWorkerFactory {
&self,
package_folder: &Path,
sub_path: Option<&str>,
) -> Result<ModuleSpecifier, AnyError> {
) -> Result<ModuleSpecifier, ResolveBinaryEntrypointError> {
match self
.node_resolver
.resolve_binary_export(package_folder, sub_path)
@ -459,10 +511,13 @@ impl CliMainWorkerFactory {
self.resolve_binary_entrypoint_fallback(package_folder, sub_path);
match result {
Ok(Some(specifier)) => Ok(specifier),
Ok(None) => Err(original_err.into()),
Err(fallback_err) => {
bail!("{:#}\n\nFallback failed: {:#}", original_err, fallback_err)
}
Ok(None) => Err(
ResolveBinaryEntrypointError::ResolvePkgJsonBinExport(original_err),
),
Err(fallback_err) => Err(ResolveBinaryEntrypointError::Fallback {
original: original_err,
fallback: fallback_err,
}),
}
}
}
@ -473,7 +528,7 @@ impl CliMainWorkerFactory {
&self,
package_folder: &Path,
sub_path: Option<&str>,
) -> Result<Option<ModuleSpecifier>, AnyError> {
) -> Result<Option<ModuleSpecifier>, ResolveBinaryEntrypointFallbackError> {
// only fallback if the user specified a sub path
if sub_path.is_none() {
// it's confusing to users if the package doesn't have any binary
@ -490,7 +545,8 @@ impl CliMainWorkerFactory {
/* referrer */ None,
ResolutionMode::Import,
NodeResolutionKind::Execution,
)?;
)
.map_err(ResolveBinaryEntrypointFallbackError::PackageSubpathResolve)?;
if specifier
.to_file_path()
.map(|p| p.exists())
@ -498,7 +554,9 @@ impl CliMainWorkerFactory {
{
Ok(Some(specifier))
} else {
bail!("Cannot find module '{}'", specifier)
Err(ResolveBinaryEntrypointFallbackError::ModuleNotFound(
specifier,
))
}
}
}

View file

@ -99,9 +99,6 @@ pub enum QuicError {
#[class(range)]
#[error("Connection has reached the maximum number of concurrent outgoing {0} streams")]
MaxStreams(&'static str),
#[class(generic)]
#[error("{0}")]
Core(#[from] deno_core::error::AnyError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),

View file

@ -106,10 +106,15 @@ pub enum RequireErrorKind {
JsErrorBox,
),
#[class(inherit)]
#[error("Unable to get CWD: {0}")]
UnableToGetCwd(#[inherit] std::io::Error),
#[error(transparent)]
UnableToGetCwd(UnableToGetCwdError),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[error("Unable to get CWD")]
#[class(inherit)]
pub struct UnableToGetCwdError(#[source] pub std::io::Error);
#[op2]
#[serde]
pub fn op_require_init_paths() -> Vec<String> {
@ -177,7 +182,7 @@ pub fn op_require_node_module_paths<
} else {
let current_dir = &sys
.env_current_dir()
.map_err(RequireErrorKind::UnableToGetCwd)?;
.map_err(|e| RequireErrorKind::UnableToGetCwd(UnableToGetCwdError(e)))?;
normalize_path(current_dir.join(from))
};

View file

@ -6,8 +6,7 @@ use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
use anyhow::Context;
use anyhow::Error as AnyError;
use deno_error::JsErrorBox;
use deno_path_util::url_from_file_path;
use deno_path_util::url_to_file_path;
use futures::future::LocalBoxFuture;
@ -43,6 +42,16 @@ pub struct CjsAnalysisExports {
pub reexports: Vec<String>,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CjsCodeAnalysisError {
#[class(inherit)]
#[error(transparent)]
ClosestPkgJson(#[from] crate::errors::ClosestPkgJsonError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
/// Code analyzer for CJS and ESM files.
#[async_trait::async_trait(?Send)]
pub trait CjsCodeAnalyzer {
@ -57,7 +66,28 @@ pub trait CjsCodeAnalyzer {
&self,
specifier: &Url,
maybe_source: Option<Cow<'a, str>>,
) -> Result<CjsAnalysis<'a>, AnyError>;
) -> Result<CjsAnalysis<'a>, CjsCodeAnalysisError>;
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum TranslateCjsToEsmError {
#[class(inherit)]
#[error(transparent)]
CjsCodeAnalysis(#[from] CjsCodeAnalysisError),
#[class(inherit)]
#[error(transparent)]
ExportAnalysis(#[from] JsErrorBox),
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(generic)]
#[error("Could not load '{reexport}' ({reexport_specifier}) referenced from {referrer}")]
pub struct CjsAnalysisCouldNotLoadError {
reexport: String,
reexport_specifier: Url,
referrer: Url,
#[source]
source: CjsCodeAnalysisError,
}
pub struct NodeCodeTranslator<
@ -128,7 +158,7 @@ impl<
&self,
entry_specifier: &Url,
source: Option<Cow<'a, str>>,
) -> Result<Cow<'a, str>, AnyError> {
) -> Result<Cow<'a, str>, TranslateCjsToEsmError> {
let mut temp_var_count = 0;
let analysis = self
@ -164,7 +194,7 @@ impl<
// surface errors afterwards in a deterministic way
if !errors.is_empty() {
errors.sort_by_cached_key(|e| e.to_string());
return Err(errors.remove(0));
return Err(TranslateCjsToEsmError::ExportAnalysis(errors.remove(0)));
}
}
@ -208,7 +238,7 @@ impl<
all_exports: &mut BTreeSet<String>,
// this goes through the modules concurrently, so collect
// the errors in order to be deterministic
errors: &mut Vec<anyhow::Error>,
errors: &mut Vec<JsErrorBox>,
) {
struct Analysis {
reexport_specifier: url::Url,
@ -216,7 +246,7 @@ impl<
analysis: CjsAnalysis<'static>,
}
type AnalysisFuture<'a> = LocalBoxFuture<'a, Result<Analysis, AnyError>>;
type AnalysisFuture<'a> = LocalBoxFuture<'a, Result<Analysis, JsErrorBox>>;
let mut handled_reexports: HashSet<Url> = HashSet::default();
handled_reexports.insert(entry_specifier.clone());
@ -227,7 +257,7 @@ impl<
|referrer: url::Url,
reexports: Vec<String>,
analyze_futures: &mut FuturesUnordered<AnalysisFuture<'a>>,
errors: &mut Vec<anyhow::Error>| {
errors: &mut Vec<JsErrorBox>| {
// 1. Resolve the re-exports and start a future to analyze each one
for reexport in reexports {
let result = self.resolve(
@ -256,11 +286,13 @@ impl<
let analysis = cjs_code_analyzer
.analyze_cjs(&reexport_specifier, None)
.await
.with_context(|| {
format!(
"Could not load '{}' ({}) referenced from {}",
reexport, reexport_specifier, referrer
)
.map_err(|source| {
JsErrorBox::from_err(CjsAnalysisCouldNotLoadError {
reexport,
reexport_specifier: reexport_specifier.clone(),
referrer: referrer.clone(),
source,
})
})?;
Ok(Analysis {
@ -297,11 +329,10 @@ impl<
match analysis {
CjsAnalysis::Esm(_) => {
// todo(dsherret): support this once supporting requiring ES modules
errors.push(anyhow::anyhow!(
errors.push(JsErrorBox::generic(format!(
"Cannot require ES module '{}' from '{}'",
reexport_specifier,
referrer,
));
reexport_specifier, referrer,
)));
}
CjsAnalysis::Cjs(analysis) => {
if !analysis.reexports.is_empty() {
@ -331,7 +362,7 @@ impl<
referrer: &Url,
conditions: &[&str],
resolution_kind: NodeResolutionKind,
) -> Result<Option<Url>, AnyError> {
) -> Result<Option<Url>, JsErrorBox> {
if specifier.starts_with('/') {
todo!();
}
@ -341,7 +372,7 @@ impl<
if let Some(parent) = referrer_path.parent() {
return self
.file_extension_probe(parent.join(specifier), &referrer_path)
.and_then(|p| url_from_file_path(&p).map_err(AnyError::from))
.and_then(|p| url_from_file_path(&p).map_err(JsErrorBox::from_err))
.map(Some);
} else {
todo!();
@ -364,13 +395,14 @@ impl<
{
return Ok(None);
}
other => other,
}?;
other => other.map_err(JsErrorBox::from_err)?,
};
let package_json_path = module_dir.join("package.json");
let maybe_package_json = self
.pkg_json_resolver
.load_package_json(&package_json_path)?;
.load_package_json(&package_json_path)
.map_err(JsErrorBox::from_err)?;
if let Some(package_json) = maybe_package_json {
if let Some(exports) = &package_json.exports {
return Some(
@ -385,7 +417,7 @@ impl<
conditions,
resolution_kind,
)
.map_err(AnyError::from),
.map_err(JsErrorBox::from_err),
)
.transpose();
}
@ -398,29 +430,40 @@ impl<
let package_json_path = d.join("package.json");
let maybe_package_json = self
.pkg_json_resolver
.load_package_json(&package_json_path)?;
.load_package_json(&package_json_path)
.map_err(JsErrorBox::from_err)?;
if let Some(package_json) = maybe_package_json {
if let Some(main) =
package_json.main(deno_package_json::NodeModuleKind::Cjs)
{
return Ok(Some(url_from_file_path(&d.join(main).clean())?));
return Ok(Some(
url_from_file_path(&d.join(main).clean())
.map_err(JsErrorBox::from_err)?,
));
}
}
return Ok(Some(url_from_file_path(&d.join("index.js").clean())?));
return Ok(Some(
url_from_file_path(&d.join("index.js").clean())
.map_err(JsErrorBox::from_err)?,
));
}
return self
.file_extension_probe(d, &referrer_path)
.and_then(|p| url_from_file_path(&p).map_err(AnyError::from))
.and_then(|p| url_from_file_path(&p).map_err(JsErrorBox::from_err))
.map(Some);
} else if let Some(main) =
package_json.main(deno_package_json::NodeModuleKind::Cjs)
{
return Ok(Some(url_from_file_path(&module_dir.join(main).clean())?));
return Ok(Some(
url_from_file_path(&module_dir.join(main).clean())
.map_err(JsErrorBox::from_err)?,
));
} else {
return Ok(Some(url_from_file_path(
&module_dir.join("index.js").clean(),
)?));
return Ok(Some(
url_from_file_path(&module_dir.join("index.js").clean())
.map_err(JsErrorBox::from_err)?,
));
}
}
@ -436,7 +479,9 @@ impl<
parent.join("node_modules").join(specifier)
};
if let Ok(path) = self.file_extension_probe(path, &referrer_path) {
return Ok(Some(url_from_file_path(&path)?));
return Ok(Some(
url_from_file_path(&path).map_err(JsErrorBox::from_err)?,
));
}
last = parent;
}
@ -448,7 +493,7 @@ impl<
&self,
p: PathBuf,
referrer: &Path,
) -> Result<PathBuf, AnyError> {
) -> Result<PathBuf, JsErrorBox> {
let p = p.clean();
if self.sys.fs_exists_no_err(&p) {
let file_name = p.file_name().unwrap();
@ -638,13 +683,13 @@ fn parse_specifier(specifier: &str) -> Option<(String, String)> {
Some((package_name, package_subpath))
}
fn not_found(path: &str, referrer: &Path) -> AnyError {
fn not_found(path: &str, referrer: &Path) -> JsErrorBox {
let msg = format!(
"[ERR_MODULE_NOT_FOUND] Cannot find module \"{}\" imported from \"{}\"",
path,
referrer.to_string_lossy()
);
std::io::Error::new(std::io::ErrorKind::NotFound, msg).into()
JsErrorBox::from_err(std::io::Error::new(std::io::ErrorKind::NotFound, msg))
}
fn to_double_quote_string(text: &str) -> String {

View file

@ -4,11 +4,12 @@ use std::path::Path;
use std::path::PathBuf;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_path_util::normalize_path;
#[inline]
pub fn resolve_from_cwd(path: &Path) -> Result<PathBuf, AnyError> {
pub fn resolve_from_cwd(
path: &Path,
) -> Result<PathBuf, deno_core::anyhow::Error> {
if path.is_absolute() {
Ok(normalize_path(path))
} else {

View file

@ -10,8 +10,6 @@ use std::process;
use std::rc::Rc;
use std::thread;
use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::futures::channel::mpsc;
use deno_core::futures::channel::mpsc::UnboundedReceiver;
use deno_core::futures::channel::mpsc::UnboundedSender;
@ -49,17 +47,33 @@ pub struct InspectorServer {
thread_handle: Option<thread::JoinHandle<()>>,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum InspectorServerError {
#[class(inherit)]
#[error(transparent)]
Io(#[from] std::io::Error),
#[class(inherit)]
#[error("Failed to start inspector server at \"{host}\"")]
Connect {
host: SocketAddr,
#[source]
#[inherit]
source: std::io::Error,
},
}
impl InspectorServer {
pub fn new(host: SocketAddr, name: &'static str) -> Result<Self, AnyError> {
pub fn new(
host: SocketAddr,
name: &'static str,
) -> Result<Self, InspectorServerError> {
let (register_inspector_tx, register_inspector_rx) =
mpsc::unbounded::<InspectorInfo>();
let (shutdown_server_tx, shutdown_server_rx) = broadcast::channel(1);
let tcp_listener =
std::net::TcpListener::bind(host).with_context(|| {
format!("Failed to start inspector server at \"{}\"", host)
})?;
let tcp_listener = std::net::TcpListener::bind(host)
.map_err(|source| InspectorServerError::Connect { host, source })?;
tcp_listener.set_nonblocking(true)?;
let thread_handle = thread::spawn(move || {