1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

refactor(ext/node): allow injecting NodeFs from CLI (#18829)

This allows providing a `NodeFs` as part of the `WorkerOptions`.
This commit is contained in:
David Sherret 2023-04-24 19:44:35 -04:00 committed by GitHub
parent bb74e75a04
commit aa286fdecb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1631 additions and 1687 deletions

View file

@ -2,6 +2,7 @@
use std::env;
use std::path::PathBuf;
use std::sync::Arc;
use deno_core::snapshot_util::*;
use deno_core::Extension;
@ -361,7 +362,10 @@ fn create_cli_snapshot(snapshot_path: PathBuf) {
deno_http::deno_http::init_ops(),
deno_io::deno_io::init_ops(Default::default()),
deno_fs::deno_fs::init_ops::<_, PermissionsContainer>(false, StdFs),
deno_node::deno_node::init_ops::<deno_runtime::RuntimeNodeEnv>(None),
deno_node::deno_node::init_ops::<deno_runtime::RuntimeNodeEnv>(
None,
Some(Arc::new(deno_node::RealFs)),
),
cli::init_ops_and_esm(), // NOTE: This needs to be init_ops_and_esm!
];

View file

@ -17,7 +17,6 @@ use crate::file_fetcher::get_source_from_bytes;
use crate::file_fetcher::map_content_type;
use crate::file_fetcher::SUPPORTED_SCHEMES;
use crate::lsp::logging::lsp_warn;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmRegistryApi;
use crate::npm::NpmResolution;
use crate::npm::PackageJsonDepsInstaller;
@ -39,8 +38,8 @@ use deno_graph::Resolution;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_node::PackageJson;
use deno_runtime::deno_node::RealFs;
use deno_runtime::permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReq;
use deno_semver::npm::NpmPackageReqReference;
@ -1057,7 +1056,7 @@ impl Documents {
&self,
specifiers: Vec<String>,
referrer_doc: &AssetOrDocument,
maybe_node_resolver: Option<&Arc<CliNodeResolver>>,
maybe_node_resolver: Option<&Arc<NodeResolver>>,
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
let referrer = referrer_doc.specifier();
let dependencies = match referrer_doc {
@ -1071,7 +1070,7 @@ impl Documents {
// we're in an npm package, so use node resolution
results.push(Some(NodeResolution::into_specifier_and_media_type(
node_resolver
.resolve::<RealFs>(
.resolve(
&specifier,
referrer,
NodeResolutionMode::Types,
@ -1419,7 +1418,7 @@ impl Documents {
fn resolve_dependency(
&self,
specifier: &ModuleSpecifier,
maybe_node_resolver: Option<&Arc<CliNodeResolver>>,
maybe_node_resolver: Option<&Arc<NodeResolver>>,
) -> Option<(ModuleSpecifier, MediaType)> {
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(specifier) {
return node_resolve_npm_req_ref(npm_ref, maybe_node_resolver);
@ -1454,12 +1453,12 @@ impl Documents {
fn node_resolve_npm_req_ref(
npm_req_ref: NpmPackageReqReference,
maybe_node_resolver: Option<&Arc<CliNodeResolver>>,
maybe_node_resolver: Option<&Arc<NodeResolver>>,
) -> Option<(ModuleSpecifier, MediaType)> {
maybe_node_resolver.map(|node_resolver| {
NodeResolution::into_specifier_and_media_type(
node_resolver
.resolve_npm_req_reference::<RealFs>(
.resolve_npm_req_reference(
&npm_req_ref,
NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(),

View file

@ -9,6 +9,7 @@ use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::ModuleSpecifier;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_node::PackageJson;
use deno_runtime::deno_web::BlobStore;
@ -79,7 +80,6 @@ use crate::file_fetcher::FileFetcher;
use crate::graph_util;
use crate::http_util::HttpClient;
use crate::lsp::urls::LspUrlKind;
use crate::node::CliNodeResolver;
use crate::npm::create_npm_fs_resolver;
use crate::npm::CliNpmRegistryApi;
use crate::npm::CliNpmResolver;
@ -103,7 +103,7 @@ pub struct StateSnapshot {
pub cache_metadata: cache::CacheMetadata,
pub documents: Documents,
pub maybe_import_map: Option<Arc<ImportMap>>,
pub maybe_node_resolver: Option<Arc<CliNodeResolver>>,
pub maybe_node_resolver: Option<Arc<NodeResolver>>,
pub maybe_npm_resolver: Option<Arc<CliNpmResolver>>,
}
@ -449,6 +449,7 @@ fn create_lsp_structs(
let resolution =
Arc::new(NpmResolution::from_serialized(api.clone(), None, None));
let fs_resolver = create_npm_fs_resolver(
Arc::new(deno_node::RealFs),
npm_cache.clone(),
&progress_bar,
registry_url.clone(),
@ -700,9 +701,11 @@ impl Inner {
self.npm_resolution.snapshot(),
None,
));
let node_fs = Arc::new(deno_node::RealFs);
let npm_resolver = Arc::new(CliNpmResolver::new(
npm_resolution.clone(),
create_npm_fs_resolver(
node_fs.clone(),
self.npm_cache.clone(),
&ProgressBar::new(ProgressBarStyle::TextOnly),
self.npm_api.base_url().clone(),
@ -711,7 +714,8 @@ impl Inner {
),
None,
));
let node_resolver = Arc::new(NodeResolver::new(npm_resolver.clone()));
let node_resolver =
Arc::new(NodeResolver::new(node_fs, npm_resolver.clone()));
Arc::new(StateSnapshot {
assets: self.assets.snapshot(),
cache_metadata: self.cache_metadata.clone(),

View file

@ -12,7 +12,6 @@ use crate::graph_util::ModuleGraphBuilder;
use crate::graph_util::ModuleGraphContainer;
use crate::node;
use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::proc_state::CjsResolutionStore;
use crate::proc_state::FileWatcherReporter;
use crate::proc_state::ProcState;
@ -51,7 +50,7 @@ use deno_lockfile::Lockfile;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::RealFs;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use std::borrow::Cow;
@ -244,7 +243,7 @@ pub struct CliModuleLoader {
graph_container: Arc<ModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>,
node_resolver: Arc<CliNodeResolver>,
node_resolver: Arc<NodeResolver>,
parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliGraphResolver>,
}
@ -387,7 +386,7 @@ impl CliModuleLoader {
self.root_permissions.clone()
};
// translate cjs to esm if it's cjs and inject node globals
self.node_code_translator.translate_cjs_to_esm::<RealFs>(
self.node_code_translator.translate_cjs_to_esm(
specifier,
&code,
&mut permissions,
@ -466,7 +465,7 @@ impl ModuleLoader for CliModuleLoader {
if self.node_resolver.in_npm_package(referrer) {
// we're in an npm package, so use node resolution
return self
.handle_node_resolve_result(self.node_resolver.resolve::<RealFs>(
.handle_node_resolve_result(self.node_resolver.resolve(
specifier,
referrer,
NodeResolutionMode::Execution,
@ -492,7 +491,7 @@ impl ModuleLoader for CliModuleLoader {
return match graph.get(specifier) {
Some(Module::Npm(module)) => self
.handle_node_resolve_result(
self.node_resolver.resolve_npm_reference::<RealFs>(
self.node_resolver.resolve_npm_reference(
&module.nv_reference,
NodeResolutionMode::Execution,
&mut permissions,
@ -554,7 +553,7 @@ impl ModuleLoader for CliModuleLoader {
{
return self
.handle_node_resolve_result(
self.node_resolver.resolve_npm_req_reference::<RealFs>(
self.node_resolver.resolve_npm_req_reference(
&reference,
NodeResolutionMode::Execution,
&mut permissions,

View file

@ -1,7 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::collections::HashSet;
use std::sync::Arc;
use deno_ast::swc::common::SyntaxContext;
use deno_ast::view::Node;
@ -15,15 +14,11 @@ use deno_core::error::AnyError;
use deno_runtime::deno_node::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
use deno_runtime::deno_node::analyze::CjsEsmCodeAnalyzer;
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
use deno_runtime::deno_node::NodeResolver;
use crate::cache::NodeAnalysisCache;
use crate::npm::CliNpmResolver;
use crate::util::fs::canonicalize_path_maybe_not_exists;
pub type CliNodeCodeTranslator =
NodeCodeTranslator<CliCjsEsmCodeAnalyzer, Arc<CliNpmResolver>>;
pub type CliNodeResolver = NodeResolver<Arc<CliNpmResolver>>;
pub type CliNodeCodeTranslator = NodeCodeTranslator<CliCjsEsmCodeAnalyzer>;
/// Resolves a specifier that is pointing into a node_modules folder.
///

View file

@ -23,6 +23,7 @@ use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use deno_runtime::deno_core::futures;
use deno_runtime::deno_node::NodeFs;
use deno_runtime::deno_node::NodePermissions;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::PackageJson;
@ -43,6 +44,7 @@ use super::common::NpmPackageFsResolver;
/// and resolves packages from it.
#[derive(Debug)]
pub struct LocalNpmPackageResolver {
fs: Arc<dyn NodeFs>,
cache: Arc<NpmCache>,
progress_bar: ProgressBar,
resolution: Arc<NpmResolution>,
@ -53,6 +55,7 @@ pub struct LocalNpmPackageResolver {
impl LocalNpmPackageResolver {
pub fn new(
fs: Arc<dyn NodeFs>,
cache: Arc<NpmCache>,
progress_bar: ProgressBar,
registry_url: Url,
@ -60,6 +63,7 @@ impl LocalNpmPackageResolver {
resolution: Arc<NpmResolution>,
) -> Self {
Self {
fs,
cache,
progress_bar,
resolution,
@ -149,9 +153,10 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
if sub_dir.is_dir() {
// if doing types resolution, only resolve the package if it specifies a types property
if mode.is_types() && !name.starts_with("@types/") {
let package_json = PackageJson::load_skip_read_permission::<
deno_runtime::deno_node::RealFs,
>(sub_dir.join("package.json"))?;
let package_json = PackageJson::load_skip_read_permission(
&*self.fs,
sub_dir.join("package.json"),
)?;
if package_json.types.is_some() {
return Ok(sub_dir);
}

View file

@ -18,6 +18,7 @@ use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::resolution::PackageReqNotFoundError;
use deno_npm::resolution::SerializedNpmResolutionSnapshot;
use deno_npm::NpmPackageId;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodePermissions;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::NpmResolver;
@ -269,6 +270,7 @@ impl NpmResolver for CliNpmResolver {
}
pub fn create_npm_fs_resolver(
fs: Arc<dyn deno_node::NodeFs>,
cache: Arc<NpmCache>,
progress_bar: &ProgressBar,
registry_url: Url,
@ -277,6 +279,7 @@ pub fn create_npm_fs_resolver(
) -> Arc<dyn NpmPackageFsResolver> {
match maybe_node_modules_path {
Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new(
fs,
cache,
progress_bar.clone(),
registry_url,

View file

@ -19,7 +19,6 @@ use crate::http_util::HttpClient;
use crate::module_loader::ModuleLoadPreparer;
use crate::node::CliCjsEsmCodeAnalyzer;
use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::npm::create_npm_fs_resolver;
use crate::npm::CliNpmRegistryApi;
use crate::npm::CliNpmResolver;
@ -38,6 +37,7 @@ use deno_core::ModuleSpecifier;
use deno_core::SharedArrayBufferStore;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_node;
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::deno_tls::rustls::RootCertStore;
@ -79,7 +79,8 @@ pub struct Inner {
pub module_graph_builder: Arc<ModuleGraphBuilder>,
pub module_load_preparer: Arc<ModuleLoadPreparer>,
pub node_code_translator: Arc<CliNodeCodeTranslator>,
pub node_resolver: Arc<CliNodeResolver>,
pub node_fs: Arc<dyn deno_node::NodeFs>,
pub node_resolver: Arc<NodeResolver>,
pub npm_api: Arc<CliNpmRegistryApi>,
pub npm_cache: Arc<NpmCache>,
pub npm_resolver: Arc<CliNpmResolver>,
@ -150,6 +151,7 @@ impl ProcState {
module_graph_builder: self.module_graph_builder.clone(),
module_load_preparer: self.module_load_preparer.clone(),
node_code_translator: self.node_code_translator.clone(),
node_fs: self.node_fs.clone(),
node_resolver: self.node_resolver.clone(),
npm_api: self.npm_api.clone(),
npm_cache: self.npm_cache.clone(),
@ -245,7 +247,9 @@ impl ProcState {
npm_snapshot,
lockfile.as_ref().cloned(),
));
let node_fs = Arc::new(deno_node::RealFs);
let npm_fs_resolver = create_npm_fs_resolver(
node_fs.clone(),
npm_cache,
&progress_bar,
npm_registry_url,
@ -308,11 +312,14 @@ impl ProcState {
let node_analysis_cache =
NodeAnalysisCache::new(caches.node_analysis_db(&dir));
let cjs_esm_analyzer = CliCjsEsmCodeAnalyzer::new(node_analysis_cache);
let node_resolver =
Arc::new(NodeResolver::new(node_fs.clone(), npm_resolver.clone()));
let node_code_translator = Arc::new(NodeCodeTranslator::new(
cjs_esm_analyzer,
node_fs.clone(),
node_resolver.clone(),
npm_resolver.clone(),
));
let node_resolver = Arc::new(NodeResolver::new(npm_resolver.clone()));
let type_checker = Arc::new(TypeChecker::new(
dir.clone(),
caches.clone(),
@ -365,6 +372,7 @@ impl ProcState {
maybe_file_watcher_reporter,
module_graph_builder,
node_code_translator,
node_fs,
node_resolver,
npm_api,
npm_cache,

View file

@ -190,6 +190,7 @@ fn create_web_worker_callback(
root_cert_store: Some(ps.root_cert_store.clone()),
seed: ps.options.seed(),
module_loader,
node_fs: Some(ps.node_fs.clone()),
npm_resolver: None, // not currently supported
create_web_worker_cb,
preload_module_cb: web_worker_cb.clone(),
@ -285,6 +286,7 @@ pub async fn run(
should_break_on_first_statement: false,
should_wait_for_inspector_session: false,
module_loader,
node_fs: Some(ps.node_fs.clone()),
npm_resolver: None, // not currently supported
get_error_class_fn: Some(&get_error_class_name),
cache_storage_dir: None,

View file

@ -9,6 +9,7 @@ use deno_core::error::AnyError;
use deno_graph::Module;
use deno_graph::ModuleGraph;
use deno_runtime::colors;
use deno_runtime::deno_node::NodeResolver;
use once_cell::sync::Lazy;
use regex::Regex;
@ -21,7 +22,6 @@ use crate::cache::Caches;
use crate::cache::DenoDir;
use crate::cache::FastInsecureHasher;
use crate::cache::TypeCheckCache;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver;
use crate::tsc;
use crate::version;
@ -42,7 +42,7 @@ pub struct TypeChecker {
deno_dir: DenoDir,
caches: Arc<Caches>,
cli_options: Arc<CliOptions>,
node_resolver: Arc<CliNodeResolver>,
node_resolver: Arc<NodeResolver>,
npm_resolver: Arc<CliNpmResolver>,
}
@ -51,7 +51,7 @@ impl TypeChecker {
deno_dir: DenoDir,
caches: Arc<Caches>,
cli_options: Arc<CliOptions>,
node_resolver: Arc<CliNodeResolver>,
node_resolver: Arc<NodeResolver>,
npm_resolver: Arc<CliNpmResolver>,
) -> Self {
Self {

View file

@ -4,7 +4,6 @@ use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::TaskFlags;
use crate::colors;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver;
use crate::proc_state::ProcState;
use crate::util::fs::canonicalize_path;
@ -13,7 +12,7 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::futures;
use deno_core::futures::future::LocalBoxFuture;
use deno_runtime::deno_node::RealFs;
use deno_runtime::deno_node::NodeResolver;
use deno_semver::npm::NpmPackageNv;
use deno_task_shell::ExecuteResult;
use deno_task_shell::ShellCommand;
@ -236,13 +235,12 @@ impl ShellCommand for NpmPackageBinCommand {
fn resolve_npm_commands(
npm_resolver: &CliNpmResolver,
node_resolver: &CliNodeResolver,
node_resolver: &NodeResolver,
) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> {
let mut result = HashMap::new();
let snapshot = npm_resolver.snapshot();
for id in snapshot.top_level_packages() {
let bin_commands =
node_resolver.resolve_binary_commands::<RealFs>(&id.nv)?;
let bin_commands = node_resolver.resolve_binary_commands(&id.nv)?;
for bin_command in bin_commands {
result.insert(
bin_command.to_string(),

View file

@ -4,7 +4,6 @@ use crate::args::TsConfig;
use crate::args::TypeCheckMode;
use crate::cache::FastInsecureHasher;
use crate::node;
use crate::node::CliNodeResolver;
use crate::util::checksum;
use crate::util::path::mapped_specifier_for_tsc;
@ -35,7 +34,7 @@ use deno_graph::ResolutionResolved;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::NodeResolutionMode;
use deno_runtime::deno_node::RealFs;
use deno_runtime::deno_node::NodeResolver;
use deno_runtime::permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use lsp_types::Url;
@ -307,7 +306,7 @@ pub struct Request {
pub debug: bool,
pub graph: Arc<ModuleGraph>,
pub hash_data: u64,
pub maybe_node_resolver: Option<Arc<CliNodeResolver>>,
pub maybe_node_resolver: Option<Arc<NodeResolver>>,
pub maybe_tsbuildinfo: Option<String>,
/// A vector of strings that represent the root/entry point modules for the
/// program.
@ -331,7 +330,7 @@ struct State {
graph: Arc<ModuleGraph>,
maybe_tsbuildinfo: Option<String>,
maybe_response: Option<RespondArgs>,
maybe_node_resolver: Option<Arc<CliNodeResolver>>,
maybe_node_resolver: Option<Arc<NodeResolver>>,
remapped_specifiers: HashMap<String, ModuleSpecifier>,
root_map: HashMap<String, ModuleSpecifier>,
current_dir: PathBuf,
@ -341,7 +340,7 @@ impl State {
pub fn new(
graph: Arc<ModuleGraph>,
hash_data: u64,
maybe_node_resolver: Option<Arc<CliNodeResolver>>,
maybe_node_resolver: Option<Arc<NodeResolver>>,
maybe_tsbuildinfo: Option<String>,
root_map: HashMap<String, ModuleSpecifier>,
remapped_specifiers: HashMap<String, ModuleSpecifier>,
@ -637,7 +636,7 @@ fn resolve_graph_specifier_types(
}
Some(Module::Npm(module)) => {
if let Some(node_resolver) = &state.maybe_node_resolver {
let maybe_resolution = node_resolver.resolve_npm_reference::<RealFs>(
let maybe_resolution = node_resolver.resolve_npm_reference(
&module.nv_reference,
NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(),
@ -655,9 +654,7 @@ fn resolve_graph_specifier_types(
let specifier =
node::resolve_specifier_into_node_modules(&module.specifier);
NodeResolution::into_specifier_and_media_type(
node_resolver
.url_to_node_resolution::<RealFs>(specifier)
.ok(),
node_resolver.url_to_node_resolution(specifier).ok(),
)
}))
}
@ -678,7 +675,7 @@ fn resolve_non_graph_specifier_types(
// we're in an npm package, so use node resolution
Ok(Some(NodeResolution::into_specifier_and_media_type(
node_resolver
.resolve::<RealFs>(
.resolve(
specifier,
referrer,
NodeResolutionMode::Types,
@ -692,7 +689,7 @@ fn resolve_non_graph_specifier_types(
// we don't need this special code here.
// This could occur when resolving npm:@types/node when it is
// injected and not part of the graph
let maybe_resolution = node_resolver.resolve_npm_req_reference::<RealFs>(
let maybe_resolution = node_resolver.resolve_npm_req_reference(
&npm_ref,
NodeResolutionMode::Types,
&mut PermissionsContainer::allow_all(),

View file

@ -1,7 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use deno_ast::ModuleSpecifier;
@ -14,7 +13,6 @@ use deno_core::ModuleId;
use deno_runtime::colors;
use deno_runtime::deno_node;
use deno_runtime::deno_node::NodeResolution;
use deno_runtime::deno_node::RealFs;
use deno_runtime::fmt_errors::format_js_error;
use deno_runtime::ops::worker_host::CreateWebWorkerCb;
use deno_runtime::ops::worker_host::WorkerEventCb;
@ -259,15 +257,13 @@ pub async fn create_custom_worker(
ps.npm_resolver
.add_package_reqs(vec![package_ref.req.clone()])
.await?;
let node_resolution = ps
.node_resolver
.resolve_binary_export::<RealFs>(&package_ref)?;
let node_resolution =
ps.node_resolver.resolve_binary_export(&package_ref)?;
let is_main_cjs = matches!(node_resolution, NodeResolution::CommonJs(_));
(node_resolution.into_url(), is_main_cjs)
} else if ps.options.is_npm_main() {
let node_resolution = ps
.node_resolver
.url_to_node_resolution::<RealFs>(main_module)?;
let node_resolution =
ps.node_resolver.url_to_node_resolution(main_module)?;
let is_main_cjs = matches!(node_resolution, NodeResolution::CommonJs(_));
(node_resolution.into_url(), is_main_cjs)
} else {
@ -345,7 +341,8 @@ pub async fn create_custom_worker(
should_break_on_first_statement: ps.options.inspect_brk().is_some(),
should_wait_for_inspector_session: ps.options.inspect_wait().is_some(),
module_loader,
npm_resolver: Some(Rc::new(ps.npm_resolver.clone())),
node_fs: Some(ps.node_fs.clone()),
npm_resolver: Some(ps.npm_resolver.clone()),
get_error_class_fn: Some(&errors::get_error_class_name),
cache_storage_dir,
origin_storage_dir,
@ -468,7 +465,8 @@ fn create_web_worker_callback(
format_js_error_fn: Some(Arc::new(format_js_error)),
source_map_getter: Some(Box::new(module_loader.clone())),
module_loader,
npm_resolver: Some(Rc::new(ps.npm_resolver.clone())),
node_fs: Some(ps.node_fs.clone()),
npm_resolver: Some(ps.npm_resolver.clone()),
worker_type: args.worker_type,
maybe_inspector_server,
get_error_class_fn: Some(&errors::get_error_class_name),
@ -492,6 +490,8 @@ fn create_web_worker_callback(
#[cfg(test)]
mod tests {
use std::rc::Rc;
use super::*;
use deno_core::resolve_path;
use deno_core::FsModuleLoader;
@ -520,6 +520,7 @@ mod tests {
should_break_on_first_statement: false,
should_wait_for_inspector_session: false,
module_loader: Rc::new(FsModuleLoader),
node_fs: Some(Arc::new(deno_node::RealFs)),
npm_resolver: None,
get_error_class_fn: None,
cache_storage_dir: None,

View file

@ -5,6 +5,7 @@ use std::collections::VecDeque;
use std::fmt::Write;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use deno_core::anyhow::Context;
use deno_core::ModuleSpecifier;
@ -12,11 +13,11 @@ use once_cell::sync::Lazy;
use deno_core::error::AnyError;
use crate::package_exports_resolve;
use crate::NodeFs;
use crate::NodeModuleKind;
use crate::NodePermissions;
use crate::NodeResolutionMode;
use crate::NodeResolver;
use crate::NpmResolver;
use crate::PackageJson;
use crate::PathClean;
@ -64,23 +65,26 @@ pub trait CjsEsmCodeAnalyzer {
) -> Result<HashSet<String>, AnyError>;
}
pub struct NodeCodeTranslator<
TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer,
TNpmResolver: NpmResolver,
> {
pub struct NodeCodeTranslator<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer> {
cjs_esm_code_analyzer: TCjsEsmCodeAnalyzer,
npm_resolver: TNpmResolver,
fs: Arc<dyn NodeFs>,
node_resolver: Arc<NodeResolver>,
npm_resolver: Arc<dyn NpmResolver>,
}
impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
NodeCodeTranslator<TCjsEsmCodeAnalyzer, TNpmResolver>
impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer>
NodeCodeTranslator<TCjsEsmCodeAnalyzer>
{
pub fn new(
cjs_esm_code_analyzer: TCjsEsmCodeAnalyzer,
npm_resolver: TNpmResolver,
fs: Arc<dyn NodeFs>,
node_resolver: Arc<NodeResolver>,
npm_resolver: Arc<dyn NpmResolver>,
) -> Self {
Self {
cjs_esm_code_analyzer,
fs,
node_resolver,
npm_resolver,
}
}
@ -105,7 +109,7 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
/// For all discovered reexports the analysis will be performed recursively.
///
/// If successful a source code for equivalent ES module is returned.
pub fn translate_cjs_to_esm<Fs: NodeFs>(
pub fn translate_cjs_to_esm(
&self,
specifier: &ModuleSpecifier,
source: &str,
@ -142,7 +146,7 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
handled_reexports.insert(reexport.to_string());
// First, resolve relate reexport specifier
let resolved_reexport = self.resolve::<Fs>(
let resolved_reexport = self.resolve(
&reexport,
&referrer,
// FIXME(bartlomieju): check if these conditions are okay, probably
@ -154,7 +158,9 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
// Second, read the source code from disk
let reexport_specifier =
ModuleSpecifier::from_file_path(&resolved_reexport).unwrap();
let reexport_file_text = Fs::read_to_string(&resolved_reexport)
let reexport_file_text = self
.fs
.read_to_string(&resolved_reexport)
.with_context(|| {
format!(
"Could not find '{}' ({}) referenced from {}",
@ -208,7 +214,7 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
Ok(translated_source)
}
fn resolve<Fs: NodeFs>(
fn resolve(
&self,
specifier: &str,
referrer: &ModuleSpecifier,
@ -223,10 +229,8 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
let referrer_path = referrer.to_file_path().unwrap();
if specifier.starts_with("./") || specifier.starts_with("../") {
if let Some(parent) = referrer_path.parent() {
return file_extension_probe::<Fs>(
parent.join(specifier),
&referrer_path,
);
return self
.file_extension_probe(parent.join(specifier), &referrer_path);
} else {
todo!();
}
@ -245,15 +249,16 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
)?;
let package_json_path = module_dir.join("package.json");
if Fs::exists(&package_json_path) {
let package_json = PackageJson::load::<Fs>(
&self.npm_resolver,
if self.fs.exists(&package_json_path) {
let package_json = PackageJson::load(
&*self.fs,
&*self.npm_resolver,
permissions,
package_json_path.clone(),
)?;
if let Some(exports) = &package_json.exports {
return package_exports_resolve::<Fs>(
return self.node_resolver.package_exports_resolve(
&package_json_path,
package_subpath,
exports,
@ -261,7 +266,6 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
NodeModuleKind::Esm,
conditions,
mode,
&self.npm_resolver,
permissions,
);
}
@ -269,12 +273,13 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
// old school
if package_subpath != "." {
let d = module_dir.join(package_subpath);
if Fs::is_dir(&d) {
if self.fs.is_dir(&d) {
// subdir might have a package.json that specifies the entrypoint
let package_json_path = d.join("package.json");
if Fs::exists(&package_json_path) {
let package_json = PackageJson::load::<Fs>(
&self.npm_resolver,
if self.fs.exists(&package_json_path) {
let package_json = PackageJson::load(
&*self.fs,
&*self.npm_resolver,
permissions,
package_json_path,
)?;
@ -285,7 +290,7 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
return Ok(d.join("index.js").clean());
}
return file_extension_probe::<Fs>(d, &referrer_path);
return self.file_extension_probe(d, &referrer_path);
} else if let Some(main) = package_json.main(NodeModuleKind::Cjs) {
return Ok(module_dir.join(main).clean());
} else {
@ -294,6 +299,33 @@ impl<TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, TNpmResolver: NpmResolver>
}
Err(not_found(specifier, &referrer_path))
}
fn file_extension_probe(
&self,
p: PathBuf,
referrer: &Path,
) -> Result<PathBuf, AnyError> {
let p = p.clean();
if self.fs.exists(&p) {
let file_name = p.file_name().unwrap();
let p_js =
p.with_file_name(format!("{}.js", file_name.to_str().unwrap()));
if self.fs.is_file(&p_js) {
return Ok(p_js);
} else if self.fs.is_dir(&p) {
return Ok(p.join("index.js"));
} else {
return Ok(p);
}
} else if let Some(file_name) = p.file_name() {
let p_js =
p.with_file_name(format!("{}.js", file_name.to_str().unwrap()));
if self.fs.is_file(&p_js) {
return Ok(p_js);
}
}
Err(not_found(&p.to_string_lossy(), referrer))
}
}
fn esm_code_from_top_level_decls(
@ -455,30 +487,6 @@ fn parse_specifier(specifier: &str) -> Option<(String, String)> {
Some((package_name, package_subpath))
}
fn file_extension_probe<Fs: NodeFs>(
p: PathBuf,
referrer: &Path,
) -> Result<PathBuf, AnyError> {
let p = p.clean();
if Fs::exists(&p) {
let file_name = p.file_name().unwrap();
let p_js = p.with_file_name(format!("{}.js", file_name.to_str().unwrap()));
if Fs::is_file(&p_js) {
return Ok(p_js);
} else if Fs::is_dir(&p) {
return Ok(p.join("index.js"));
} else {
return Ok(p);
}
} else if let Some(file_name) = p.file_name() {
let p_js = p.with_file_name(format!("{}.js", file_name.to_str().unwrap()));
if Fs::is_file(&p_js) {
return Ok(p_js);
}
}
Err(not_found(&p.to_string_lossy(), referrer))
}
fn not_found(path: &str, referrer: &Path) -> AnyError {
let msg = format!(
"[ERR_MODULE_NOT_FOUND] Cannot find module \"{}\" imported from \"{}\"",

View file

@ -27,7 +27,6 @@ mod package_json;
mod path;
mod polyfill;
mod resolution;
mod resolver;
pub use package_json::PackageJson;
pub use path::PathClean;
@ -35,22 +34,13 @@ pub use polyfill::is_builtin_node_module;
pub use polyfill::resolve_builtin_node_module;
pub use polyfill::NodeModulePolyfill;
pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES;
pub use resolution::get_closest_package_json;
pub use resolution::get_package_scope_config;
pub use resolution::legacy_main_resolve;
pub use resolution::package_exports_resolve;
pub use resolution::package_imports_resolve;
pub use resolution::package_resolve;
pub use resolution::path_to_declaration_path;
pub use resolution::NodeModuleKind;
pub use resolution::NodeResolution;
pub use resolution::NodeResolutionMode;
pub use resolution::DEFAULT_CONDITIONS;
pub use resolver::NodeResolution;
pub use resolver::NodeResolver;
pub use resolution::NodeResolver;
pub trait NodeEnv {
type P: NodePermissions;
type Fs: NodeFs;
}
pub trait NodePermissions {
@ -71,24 +61,26 @@ pub struct NodeFsMetadata {
pub is_dir: bool,
}
pub trait NodeFs {
fn current_dir() -> io::Result<PathBuf>;
fn metadata<P: AsRef<Path>>(path: P) -> io::Result<NodeFsMetadata>;
fn is_file<P: AsRef<Path>>(path: P) -> bool;
fn is_dir<P: AsRef<Path>>(path: P) -> bool;
fn exists<P: AsRef<Path>>(path: P) -> bool;
fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String>;
fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf>;
pub trait NodeFs: std::fmt::Debug + Send + Sync {
fn current_dir(&self) -> io::Result<PathBuf>;
fn metadata(&self, path: &Path) -> io::Result<NodeFsMetadata>;
fn is_file(&self, path: &Path) -> bool;
fn is_dir(&self, path: &Path) -> bool;
fn exists(&self, path: &Path) -> bool;
fn read_to_string(&self, path: &Path) -> io::Result<String>;
fn canonicalize(&self, path: &Path) -> io::Result<PathBuf>;
}
#[derive(Debug)]
pub struct RealFs;
impl NodeFs for RealFs {
fn current_dir() -> io::Result<PathBuf> {
fn current_dir(&self) -> io::Result<PathBuf> {
#[allow(clippy::disallowed_methods)]
std::env::current_dir()
}
fn metadata<P: AsRef<Path>>(path: P) -> io::Result<NodeFsMetadata> {
fn metadata(&self, path: &Path) -> io::Result<NodeFsMetadata> {
#[allow(clippy::disallowed_methods)]
std::fs::metadata(path).map(|metadata| {
// on most systems, calling is_file() and is_dir() is cheap
@ -100,35 +92,35 @@ impl NodeFs for RealFs {
})
}
fn exists<P: AsRef<Path>>(path: P) -> bool {
fn exists(&self, path: &Path) -> bool {
#[allow(clippy::disallowed_methods)]
std::fs::metadata(path).is_ok()
}
fn is_file<P: AsRef<Path>>(path: P) -> bool {
fn is_file(&self, path: &Path) -> bool {
#[allow(clippy::disallowed_methods)]
std::fs::metadata(path)
.map(|m| m.is_file())
.unwrap_or(false)
}
fn is_dir<P: AsRef<Path>>(path: P) -> bool {
fn is_dir(&self, path: &Path) -> bool {
#[allow(clippy::disallowed_methods)]
std::fs::metadata(path).map(|m| m.is_dir()).unwrap_or(false)
}
fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
fn read_to_string(&self, path: &Path) -> io::Result<String> {
#[allow(clippy::disallowed_methods)]
std::fs::read_to_string(path)
}
fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
#[allow(clippy::disallowed_methods)]
std::path::Path::canonicalize(path.as_ref())
std::path::Path::canonicalize(path)
}
}
pub trait NpmResolver {
pub trait NpmResolver: std::fmt::Debug + Send + Sync {
/// Resolves an npm package folder path from an npm package referrer.
fn resolve_package_folder_from_package(
&self,
@ -177,57 +169,6 @@ pub trait NpmResolver {
) -> Result<(), AnyError>;
}
impl<T: NpmResolver + ?Sized> NpmResolver for Arc<T> {
fn resolve_package_folder_from_package(
&self,
specifier: &str,
referrer: &ModuleSpecifier,
mode: NodeResolutionMode,
) -> Result<PathBuf, AnyError> {
(**self).resolve_package_folder_from_package(specifier, referrer, mode)
}
fn resolve_package_folder_from_path(
&self,
path: &Path,
) -> Result<PathBuf, AnyError> {
(**self).resolve_package_folder_from_path(path)
}
fn resolve_package_folder_from_deno_module(
&self,
pkg_nv: &NpmPackageNv,
) -> Result<PathBuf, AnyError> {
(**self).resolve_package_folder_from_deno_module(pkg_nv)
}
fn resolve_pkg_id_from_pkg_req(
&self,
req: &NpmPackageReq,
) -> Result<NpmPackageId, PackageReqNotFoundError> {
(**self).resolve_pkg_id_from_pkg_req(req)
}
fn resolve_nv_ref_from_pkg_req_ref(
&self,
req_ref: &NpmPackageReqReference,
) -> Result<NpmPackageNvReference, PackageReqNotFoundError> {
(**self).resolve_nv_ref_from_pkg_req_ref(req_ref)
}
fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
(**self).in_npm_package(specifier)
}
fn ensure_read_permission(
&self,
permissions: &mut dyn NodePermissions,
path: &Path,
) -> Result<(), AnyError> {
(**self).ensure_read_permission(permissions, path)
}
}
pub static NODE_GLOBAL_THIS_NAME: Lazy<String> = Lazy::new(|| {
let now = std::time::SystemTime::now();
let seconds = now
@ -582,11 +523,18 @@ deno_core::extension!(deno_node,
"zlib.ts",
],
options = {
maybe_npm_resolver: Option<Rc<dyn NpmResolver>>,
maybe_npm_resolver: Option<Arc<dyn NpmResolver>>,
fs: Option<Arc<dyn NodeFs>>,
},
state = |state, options| {
let fs = options.fs.unwrap_or_else(|| Arc::new(RealFs));
state.put(fs.clone());
if let Some(npm_resolver) = options.maybe_npm_resolver {
state.put(npm_resolver);
state.put(npm_resolver.clone());
state.put(Rc::new(NodeResolver::new(
fs,
npm_resolver,
)))
}
},
);

View file

@ -13,6 +13,7 @@ use std::cell::RefCell;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use crate::resolution;
use crate::NodeEnv;
@ -20,6 +21,7 @@ use crate::NodeFs;
use crate::NodeModuleKind;
use crate::NodePermissions;
use crate::NodeResolutionMode;
use crate::NodeResolver;
use crate::NpmResolver;
use crate::PackageJson;
@ -31,7 +33,7 @@ where
P: NodePermissions + 'static,
{
let resolver = {
let resolver = state.borrow::<Rc<dyn NpmResolver>>();
let resolver = state.borrow::<Arc<dyn NpmResolver>>();
resolver.clone()
};
let permissions = state.borrow_mut::<P>();
@ -96,10 +98,11 @@ pub fn op_require_node_module_paths<Env>(
where
Env: NodeEnv + 'static,
{
let fs = state.borrow::<Arc<dyn NodeFs>>().clone();
// Guarantee that "from" is absolute.
let from = deno_core::resolve_path(
&from,
&(Env::Fs::current_dir()).context("Unable to get CWD")?,
&(fs.current_dir()).context("Unable to get CWD")?,
)
.unwrap()
.to_file_path()
@ -191,7 +194,7 @@ fn op_require_resolve_deno_dir(
request: String,
parent_filename: String,
) -> Option<String> {
let resolver = state.borrow::<Rc<dyn NpmResolver>>();
let resolver = state.borrow::<Arc<dyn NpmResolver>>();
resolver
.resolve_package_folder_from_package(
&request,
@ -204,7 +207,7 @@ fn op_require_resolve_deno_dir(
#[op]
fn op_require_is_deno_dir_package(state: &mut OpState, path: String) -> bool {
let resolver = state.borrow::<Rc<dyn NpmResolver>>();
let resolver = state.borrow::<Arc<dyn NpmResolver>>();
resolver.in_npm_package_at_path(&PathBuf::from(path))
}
@ -264,7 +267,8 @@ where
{
let path = PathBuf::from(path);
ensure_read_permission::<Env::P>(state, &path)?;
if let Ok(metadata) = Env::Fs::metadata(&path) {
let fs = state.borrow::<Arc<dyn NodeFs>>().clone();
if let Ok(metadata) = fs.metadata(&path) {
if metadata.is_file {
return Ok(0);
} else {
@ -285,7 +289,8 @@ where
{
let path = PathBuf::from(request);
ensure_read_permission::<Env::P>(state, &path)?;
let mut canonicalized_path = Env::Fs::canonicalize(&path)?;
let fs = state.borrow::<Arc<dyn NodeFs>>().clone();
let mut canonicalized_path = fs.canonicalize(&path)?;
if cfg!(windows) {
canonicalized_path = PathBuf::from(
canonicalized_path
@ -353,7 +358,8 @@ where
if let Some(parent_id) = maybe_parent_id {
if parent_id == "<repl>" || parent_id == "internal/preload" {
if let Ok(cwd) = Env::Fs::current_dir() {
let fs = state.borrow::<Arc<dyn NodeFs>>().clone();
if let Ok(cwd) = fs.current_dir() {
ensure_read_permission::<Env::P>(state, &cwd)?;
return Ok(Some(cwd.to_string_lossy().to_string()));
}
@ -375,11 +381,11 @@ where
return Ok(None);
}
let resolver = state.borrow::<Rc<dyn NpmResolver>>().clone();
let node_resolver = state.borrow::<Rc<NodeResolver>>().clone();
let permissions = state.borrow_mut::<Env::P>();
let pkg = resolution::get_package_scope_config::<Env::Fs>(
let pkg = node_resolver
.get_package_scope_config(
&Url::from_file_path(parent_path.unwrap()).unwrap(),
&*resolver,
permissions,
)
.ok();
@ -408,7 +414,8 @@ where
let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap();
if let Some(exports) = &pkg.exports {
resolution::package_exports_resolve::<Env::Fs>(
node_resolver
.package_exports_resolve(
&pkg.path,
expansion,
exports,
@ -416,7 +423,6 @@ where
NodeModuleKind::Cjs,
resolution::REQUIRE_CONDITIONS,
NodeResolutionMode::Execution,
&*resolver,
permissions,
)
.map(|r| Some(r.to_string_lossy().to_string()))
@ -435,7 +441,8 @@ where
{
let file_path = PathBuf::from(file_path);
ensure_read_permission::<Env::P>(state, &file_path)?;
Ok(Env::Fs::read_to_string(file_path)?)
let fs = state.borrow::<Arc<dyn NodeFs>>().clone();
Ok(fs.read_to_string(&file_path)?)
}
#[op]
@ -462,10 +469,12 @@ fn op_require_resolve_exports<Env>(
where
Env: NodeEnv + 'static,
{
let resolver = state.borrow::<Rc<dyn NpmResolver>>().clone();
let fs = state.borrow::<Arc<dyn NodeFs>>().clone();
let npm_resolver = state.borrow::<Arc<dyn NpmResolver>>().clone();
let node_resolver = state.borrow::<Rc<NodeResolver>>().clone();
let permissions = state.borrow_mut::<Env::P>();
let pkg_path = if resolver
let pkg_path = if npm_resolver
.in_npm_package_at_path(&PathBuf::from(&modules_path))
&& !uses_local_node_modules_dir
{
@ -473,21 +482,21 @@ where
} else {
let orignal = modules_path.clone();
let mod_dir = path_resolve(vec![modules_path, name]);
if Env::Fs::is_dir(&mod_dir) {
if fs.is_dir(Path::new(&mod_dir)) {
mod_dir
} else {
orignal
}
};
let pkg = PackageJson::load::<Env::Fs>(
&*resolver,
let pkg = node_resolver.load_package_json(
permissions,
PathBuf::from(&pkg_path).join("package.json"),
)?;
if let Some(exports) = &pkg.exports {
let referrer = Url::from_file_path(parent_path).unwrap();
resolution::package_exports_resolve::<Env::Fs>(
node_resolver
.package_exports_resolve(
&pkg.path,
format!(".{expansion}"),
exports,
@ -495,7 +504,6 @@ where
NodeModuleKind::Cjs,
resolution::REQUIRE_CONDITIONS,
NodeResolutionMode::Execution,
&*resolver,
permissions,
)
.map(|r| Some(r.to_string_lossy().to_string()))
@ -516,11 +524,10 @@ where
state,
PathBuf::from(&filename).parent().unwrap(),
)?;
let resolver = state.borrow::<Rc<dyn NpmResolver>>().clone();
let node_resolver = state.borrow::<Rc<NodeResolver>>().clone();
let permissions = state.borrow_mut::<Env::P>();
resolution::get_closest_package_json::<Env::Fs>(
node_resolver.get_closest_package_json(
&Url::from_file_path(filename).unwrap(),
&*resolver,
permissions,
)
}
@ -533,10 +540,12 @@ fn op_require_read_package_scope<Env>(
where
Env: NodeEnv + 'static,
{
let resolver = state.borrow::<Rc<dyn NpmResolver>>().clone();
let node_resolver = state.borrow::<Rc<NodeResolver>>().clone();
let permissions = state.borrow_mut::<Env::P>();
let package_json_path = PathBuf::from(package_json_path);
PackageJson::load::<Env::Fs>(&*resolver, permissions, package_json_path).ok()
node_resolver
.load_package_json(permissions, package_json_path)
.ok()
}
#[op]
@ -550,29 +559,24 @@ where
{
let parent_path = PathBuf::from(&parent_filename);
ensure_read_permission::<Env::P>(state, &parent_path)?;
let resolver = state.borrow::<Rc<dyn NpmResolver>>().clone();
let node_resolver = state.borrow::<Rc<NodeResolver>>().clone();
let permissions = state.borrow_mut::<Env::P>();
let pkg = PackageJson::load::<Env::Fs>(
&*resolver,
permissions,
parent_path.join("package.json"),
)?;
let pkg = node_resolver
.load_package_json(permissions, parent_path.join("package.json"))?;
if pkg.imports.is_some() {
let referrer =
deno_core::url::Url::from_file_path(&parent_filename).unwrap();
let r = resolution::package_imports_resolve::<Env::Fs>(
node_resolver
.package_imports_resolve(
&request,
&referrer,
NodeModuleKind::Cjs,
resolution::REQUIRE_CONDITIONS,
NodeResolutionMode::Execution,
&*resolver,
permissions,
)
.map(|r| Some(Url::from_file_path(r).unwrap().to_string()));
state.put(resolver);
r
.map(|r| Some(Url::from_file_path(r).unwrap().to_string()))
} else {
Ok(None)
}

View file

@ -62,16 +62,18 @@ impl PackageJson {
}
}
pub fn load<Fs: NodeFs>(
pub fn load(
fs: &dyn NodeFs,
resolver: &dyn NpmResolver,
permissions: &mut dyn NodePermissions,
path: PathBuf,
) -> Result<PackageJson, AnyError> {
resolver.ensure_read_permission(permissions, &path)?;
Self::load_skip_read_permission::<Fs>(path)
Self::load_skip_read_permission(fs, path)
}
pub fn load_skip_read_permission<Fs: NodeFs>(
pub fn load_skip_read_permission(
fs: &dyn NodeFs,
path: PathBuf,
) -> Result<PackageJson, AnyError> {
assert!(path.is_absolute());
@ -80,7 +82,7 @@ impl PackageJson {
return Ok(CACHE.with(|cache| cache.borrow()[&path].clone()));
}
let source = match Fs::read_to_string(&path) {
let source = match fs.read_to_string(&path) {
Ok(source) => source,
Err(err) if err.kind() == ErrorKind::NotFound => {
return Ok(PackageJson::empty(path));

File diff suppressed because it is too large Load diff

View file

@ -1,686 +0,0 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::path::Path;
use std::path::PathBuf;
use deno_core::anyhow::bail;
use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::serde_json::Value;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_media_type::MediaType;
use deno_semver::npm::NpmPackageNv;
use deno_semver::npm::NpmPackageNvReference;
use deno_semver::npm::NpmPackageReqReference;
use crate::errors;
use crate::get_closest_package_json;
use crate::legacy_main_resolve;
use crate::package_exports_resolve;
use crate::package_imports_resolve;
use crate::package_resolve;
use crate::path_to_declaration_path;
use crate::AllowAllNodePermissions;
use crate::NodeFs;
use crate::NodeModuleKind;
use crate::NodePermissions;
use crate::NodeResolutionMode;
use crate::NpmResolver;
use crate::PackageJson;
use crate::DEFAULT_CONDITIONS;
#[derive(Debug)]
pub enum NodeResolution {
Esm(ModuleSpecifier),
CommonJs(ModuleSpecifier),
BuiltIn(String),
}
impl NodeResolution {
pub fn into_url(self) -> ModuleSpecifier {
match self {
Self::Esm(u) => u,
Self::CommonJs(u) => u,
Self::BuiltIn(specifier) => {
if specifier.starts_with("node:") {
ModuleSpecifier::parse(&specifier).unwrap()
} else {
ModuleSpecifier::parse(&format!("node:{specifier}")).unwrap()
}
}
}
}
pub fn into_specifier_and_media_type(
resolution: Option<Self>,
) -> (ModuleSpecifier, MediaType) {
match resolution {
Some(NodeResolution::CommonJs(specifier)) => {
let media_type = MediaType::from_specifier(&specifier);
(
specifier,
match media_type {
MediaType::JavaScript | MediaType::Jsx => MediaType::Cjs,
MediaType::TypeScript | MediaType::Tsx => MediaType::Cts,
MediaType::Dts => MediaType::Dcts,
_ => media_type,
},
)
}
Some(NodeResolution::Esm(specifier)) => {
let media_type = MediaType::from_specifier(&specifier);
(
specifier,
match media_type {
MediaType::JavaScript | MediaType::Jsx => MediaType::Mjs,
MediaType::TypeScript | MediaType::Tsx => MediaType::Mts,
MediaType::Dts => MediaType::Dmts,
_ => media_type,
},
)
}
Some(resolution) => (resolution.into_url(), MediaType::Dts),
None => (
ModuleSpecifier::parse("internal:///missing_dependency.d.ts").unwrap(),
MediaType::Dts,
),
}
}
}
#[derive(Debug)]
pub struct NodeResolver<TRequireNpmResolver: NpmResolver> {
npm_resolver: TRequireNpmResolver,
}
impl<TRequireNpmResolver: NpmResolver> NodeResolver<TRequireNpmResolver> {
pub fn new(require_npm_resolver: TRequireNpmResolver) -> Self {
Self {
npm_resolver: require_npm_resolver,
}
}
pub fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
self.npm_resolver.in_npm_package(specifier)
}
/// This function is an implementation of `defaultResolve` in
/// `lib/internal/modules/esm/resolve.js` from Node.
pub fn resolve<Fs: NodeFs>(
&self,
specifier: &str,
referrer: &ModuleSpecifier,
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<NodeResolution>, AnyError> {
// Note: if we are here, then the referrer is an esm module
// TODO(bartlomieju): skipped "policy" part as we don't plan to support it
if crate::is_builtin_node_module(specifier) {
return Ok(Some(NodeResolution::BuiltIn(specifier.to_string())));
}
if let Ok(url) = Url::parse(specifier) {
if url.scheme() == "data" {
return Ok(Some(NodeResolution::Esm(url)));
}
let protocol = url.scheme();
if protocol == "node" {
let split_specifier = url.as_str().split(':');
let specifier = split_specifier.skip(1).collect::<String>();
if crate::is_builtin_node_module(&specifier) {
return Ok(Some(NodeResolution::BuiltIn(specifier)));
}
}
if protocol != "file" && protocol != "data" {
return Err(errors::err_unsupported_esm_url_scheme(&url));
}
// todo(dsherret): this seems wrong
if referrer.scheme() == "data" {
let url = referrer.join(specifier).map_err(AnyError::from)?;
return Ok(Some(NodeResolution::Esm(url)));
}
}
let url = self.module_resolve::<Fs>(
specifier,
referrer,
DEFAULT_CONDITIONS,
mode,
permissions,
)?;
let url = match url {
Some(url) => url,
None => return Ok(None),
};
let url = match mode {
NodeResolutionMode::Execution => url,
NodeResolutionMode::Types => {
let path = url.to_file_path().unwrap();
// todo(16370): the module kind is not correct here. I think we need
// typescript to tell us if the referrer is esm or cjs
let path =
match path_to_declaration_path::<Fs>(path, NodeModuleKind::Esm) {
Some(path) => path,
None => return Ok(None),
};
ModuleSpecifier::from_file_path(path).unwrap()
}
};
let resolve_response = self.url_to_node_resolution::<Fs>(url)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(Some(resolve_response))
}
fn module_resolve<Fs: NodeFs>(
&self,
specifier: &str,
referrer: &ModuleSpecifier,
conditions: &[&str],
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<ModuleSpecifier>, AnyError> {
// note: if we're here, the referrer is an esm module
let url = if should_be_treated_as_relative_or_absolute_path(specifier) {
let resolved_specifier = referrer.join(specifier)?;
if mode.is_types() {
let file_path = to_file_path(&resolved_specifier);
// todo(dsherret): the node module kind is not correct and we
// should use the value provided by typescript instead
let declaration_path =
path_to_declaration_path::<Fs>(file_path, NodeModuleKind::Esm);
declaration_path.map(|declaration_path| {
ModuleSpecifier::from_file_path(declaration_path).unwrap()
})
} else {
Some(resolved_specifier)
}
} else if specifier.starts_with('#') {
Some(
package_imports_resolve::<Fs>(
specifier,
referrer,
NodeModuleKind::Esm,
conditions,
mode,
&self.npm_resolver,
permissions,
)
.map(|p| ModuleSpecifier::from_file_path(p).unwrap())?,
)
} else if let Ok(resolved) = Url::parse(specifier) {
Some(resolved)
} else {
package_resolve::<Fs>(
specifier,
referrer,
NodeModuleKind::Esm,
conditions,
mode,
&self.npm_resolver,
permissions,
)?
.map(|p| ModuleSpecifier::from_file_path(p).unwrap())
};
Ok(match url {
Some(url) => Some(finalize_resolution::<Fs>(url, referrer)?),
None => None,
})
}
pub fn resolve_npm_req_reference<Fs: NodeFs>(
&self,
reference: &NpmPackageReqReference,
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<NodeResolution>, AnyError> {
let reference = self
.npm_resolver
.resolve_nv_ref_from_pkg_req_ref(reference)?;
self.resolve_npm_reference::<Fs>(&reference, mode, permissions)
}
pub fn resolve_npm_reference<Fs: NodeFs>(
&self,
reference: &NpmPackageNvReference,
mode: NodeResolutionMode,
permissions: &mut dyn NodePermissions,
) -> Result<Option<NodeResolution>, AnyError> {
let package_folder = self
.npm_resolver
.resolve_package_folder_from_deno_module(&reference.nv)?;
let node_module_kind = NodeModuleKind::Esm;
let maybe_resolved_path = package_config_resolve::<Fs>(
&reference
.sub_path
.as_ref()
.map(|s| format!("./{s}"))
.unwrap_or_else(|| ".".to_string()),
&package_folder,
node_module_kind,
DEFAULT_CONDITIONS,
mode,
&self.npm_resolver,
permissions,
)
.with_context(|| {
format!("Error resolving package config for '{reference}'")
})?;
let resolved_path = match maybe_resolved_path {
Some(resolved_path) => resolved_path,
None => return Ok(None),
};
let resolved_path = match mode {
NodeResolutionMode::Execution => resolved_path,
NodeResolutionMode::Types => {
match path_to_declaration_path::<Fs>(resolved_path, node_module_kind) {
Some(path) => path,
None => return Ok(None),
}
}
};
let url = ModuleSpecifier::from_file_path(resolved_path).unwrap();
let resolve_response = self.url_to_node_resolution::<Fs>(url)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(Some(resolve_response))
}
pub fn resolve_binary_commands<Fs: NodeFs>(
&self,
pkg_nv: &NpmPackageNv,
) -> Result<Vec<String>, AnyError> {
let package_folder = self
.npm_resolver
.resolve_package_folder_from_deno_module(pkg_nv)?;
let package_json_path = package_folder.join("package.json");
let package_json = PackageJson::load::<Fs>(
&self.npm_resolver,
&mut AllowAllNodePermissions,
package_json_path,
)?;
Ok(match package_json.bin {
Some(Value::String(_)) => vec![pkg_nv.name.to_string()],
Some(Value::Object(o)) => {
o.into_iter().map(|(key, _)| key).collect::<Vec<_>>()
}
_ => Vec::new(),
})
}
pub fn resolve_binary_export<Fs: NodeFs>(
&self,
pkg_ref: &NpmPackageReqReference,
) -> Result<NodeResolution, AnyError> {
let pkg_nv = self
.npm_resolver
.resolve_pkg_id_from_pkg_req(&pkg_ref.req)?
.nv;
let bin_name = pkg_ref.sub_path.as_deref();
let package_folder = self
.npm_resolver
.resolve_package_folder_from_deno_module(&pkg_nv)?;
let package_json_path = package_folder.join("package.json");
let package_json = PackageJson::load::<Fs>(
&self.npm_resolver,
&mut AllowAllNodePermissions,
package_json_path,
)?;
let bin = match &package_json.bin {
Some(bin) => bin,
None => bail!(
"package '{}' did not have a bin property in its package.json",
&pkg_nv.name,
),
};
let bin_entry = resolve_bin_entry_value(&pkg_nv, bin_name, bin)?;
let url =
ModuleSpecifier::from_file_path(package_folder.join(bin_entry)).unwrap();
let resolve_response = self.url_to_node_resolution::<Fs>(url)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
// "preserveSymlinksMain"/"preserveSymlinks" options.
Ok(resolve_response)
}
pub fn url_to_node_resolution<Fs: NodeFs>(
&self,
url: ModuleSpecifier,
) -> Result<NodeResolution, AnyError> {
let url_str = url.as_str().to_lowercase();
if url_str.starts_with("http") {
Ok(NodeResolution::Esm(url))
} else if url_str.ends_with(".js") || url_str.ends_with(".d.ts") {
let package_config = get_closest_package_json::<Fs>(
&url,
&self.npm_resolver,
&mut AllowAllNodePermissions,
)?;
if package_config.typ == "module" {
Ok(NodeResolution::Esm(url))
} else {
Ok(NodeResolution::CommonJs(url))
}
} else if url_str.ends_with(".mjs") || url_str.ends_with(".d.mts") {
Ok(NodeResolution::Esm(url))
} else if url_str.ends_with(".ts") {
Err(generic_error(format!(
"TypeScript files are not supported in npm packages: {url}"
)))
} else {
Ok(NodeResolution::CommonJs(url))
}
}
}
fn resolve_bin_entry_value<'a>(
pkg_nv: &NpmPackageNv,
bin_name: Option<&str>,
bin: &'a Value,
) -> Result<&'a str, AnyError> {
let bin_entry = match bin {
Value::String(_) => {
if bin_name.is_some() && bin_name.unwrap() != pkg_nv.name {
None
} else {
Some(bin)
}
}
Value::Object(o) => {
if let Some(bin_name) = bin_name {
o.get(bin_name)
} else if o.len() == 1 || o.len() > 1 && o.values().all(|v| v == o.values().next().unwrap()) {
o.values().next()
} else {
o.get(&pkg_nv.name)
}
},
_ => bail!("package '{}' did not have a bin property with a string or object value in its package.json", pkg_nv),
};
let bin_entry = match bin_entry {
Some(e) => e,
None => {
let keys = bin
.as_object()
.map(|o| {
o.keys()
.map(|k| format!(" * npm:{pkg_nv}/{k}"))
.collect::<Vec<_>>()
})
.unwrap_or_default();
bail!(
"package '{}' did not have a bin entry for '{}' in its package.json{}",
pkg_nv,
bin_name.unwrap_or(&pkg_nv.name),
if keys.is_empty() {
"".to_string()
} else {
format!("\n\nPossibilities:\n{}", keys.join("\n"))
}
)
}
};
match bin_entry {
Value::String(s) => Ok(s),
_ => bail!(
"package '{}' had a non-string sub property of bin in its package.json",
pkg_nv,
),
}
}
fn package_config_resolve<Fs: NodeFs>(
package_subpath: &str,
package_dir: &Path,
referrer_kind: NodeModuleKind,
conditions: &[&str],
mode: NodeResolutionMode,
npm_resolver: &dyn NpmResolver,
permissions: &mut dyn NodePermissions,
) -> Result<Option<PathBuf>, AnyError> {
let package_json_path = package_dir.join("package.json");
let referrer = ModuleSpecifier::from_directory_path(package_dir).unwrap();
let package_config = PackageJson::load::<Fs>(
npm_resolver,
permissions,
package_json_path.clone(),
)?;
if let Some(exports) = &package_config.exports {
let result = package_exports_resolve::<Fs>(
&package_json_path,
package_subpath.to_string(),
exports,
&referrer,
referrer_kind,
conditions,
mode,
npm_resolver,
permissions,
);
match result {
Ok(found) => return Ok(Some(found)),
Err(exports_err) => {
if mode.is_types() && package_subpath == "." {
if let Ok(Some(path)) =
legacy_main_resolve::<Fs>(&package_config, referrer_kind, mode)
{
return Ok(Some(path));
} else {
return Ok(None);
}
}
return Err(exports_err);
}
}
}
if package_subpath == "." {
return legacy_main_resolve::<Fs>(&package_config, referrer_kind, mode);
}
Ok(Some(package_dir.join(package_subpath)))
}
fn finalize_resolution<Fs: NodeFs>(
resolved: ModuleSpecifier,
base: &ModuleSpecifier,
) -> Result<ModuleSpecifier, AnyError> {
let encoded_sep_re = lazy_regex::regex!(r"%2F|%2C");
if encoded_sep_re.is_match(resolved.path()) {
return Err(errors::err_invalid_module_specifier(
resolved.path(),
"must not include encoded \"/\" or \"\\\\\" characters",
Some(to_file_path_string(base)),
));
}
let path = to_file_path(&resolved);
// TODO(bartlomieju): currently not supported
// if (getOptionValue('--experimental-specifier-resolution') === 'node') {
// ...
// }
let p_str = path.to_str().unwrap();
let p = if p_str.ends_with('/') {
p_str[p_str.len() - 1..].to_string()
} else {
p_str.to_string()
};
let (is_dir, is_file) = if let Ok(stats) = Fs::metadata(p) {
(stats.is_dir, stats.is_file)
} else {
(false, false)
};
if is_dir {
return Err(errors::err_unsupported_dir_import(
resolved.as_str(),
base.as_str(),
));
} else if !is_file {
return Err(errors::err_module_not_found(
resolved.as_str(),
base.as_str(),
"module",
));
}
Ok(resolved)
}
fn to_file_path(url: &ModuleSpecifier) -> PathBuf {
url
.to_file_path()
.unwrap_or_else(|_| panic!("Provided URL was not file:// URL: {url}"))
}
fn to_file_path_string(url: &ModuleSpecifier) -> String {
to_file_path(url).display().to_string()
}
fn should_be_treated_as_relative_or_absolute_path(specifier: &str) -> bool {
if specifier.is_empty() {
return false;
}
if specifier.starts_with('/') {
return true;
}
is_relative_specifier(specifier)
}
// TODO(ry) We very likely have this utility function elsewhere in Deno.
fn is_relative_specifier(specifier: &str) -> bool {
let specifier_len = specifier.len();
let specifier_chars: Vec<_> = specifier.chars().collect();
if !specifier_chars.is_empty() && specifier_chars[0] == '.' {
if specifier_len == 1 || specifier_chars[1] == '/' {
return true;
}
if specifier_chars[1] == '.'
&& (specifier_len == 2 || specifier_chars[2] == '/')
{
return true;
}
}
false
}
#[cfg(test)]
mod tests {
use deno_core::serde_json::json;
use super::*;
#[test]
fn test_resolve_bin_entry_value() {
// should resolve the specified value
let value = json!({
"bin1": "./value1",
"bin2": "./value2",
"test": "./value3",
});
assert_eq!(
resolve_bin_entry_value(
&NpmPackageNv::from_str("test@1.1.1").unwrap(),
Some("bin1"),
&value
)
.unwrap(),
"./value1"
);
// should resolve the value with the same name when not specified
assert_eq!(
resolve_bin_entry_value(
&NpmPackageNv::from_str("test@1.1.1").unwrap(),
None,
&value
)
.unwrap(),
"./value3"
);
// should not resolve when specified value does not exist
assert_eq!(
resolve_bin_entry_value(
&NpmPackageNv::from_str("test@1.1.1").unwrap(),
Some("other"),
&value
)
.err()
.unwrap()
.to_string(),
concat!(
"package 'test@1.1.1' did not have a bin entry for 'other' in its package.json\n",
"\n",
"Possibilities:\n",
" * npm:test@1.1.1/bin1\n",
" * npm:test@1.1.1/bin2\n",
" * npm:test@1.1.1/test"
)
);
// should not resolve when default value can't be determined
assert_eq!(
resolve_bin_entry_value(
&NpmPackageNv::from_str("asdf@1.2.3").unwrap(),
None,
&value
)
.err()
.unwrap()
.to_string(),
concat!(
"package 'asdf@1.2.3' did not have a bin entry for 'asdf' in its package.json\n",
"\n",
"Possibilities:\n",
" * npm:asdf@1.2.3/bin1\n",
" * npm:asdf@1.2.3/bin2\n",
" * npm:asdf@1.2.3/test"
)
);
// should resolve since all the values are the same
let value = json!({
"bin1": "./value",
"bin2": "./value",
});
assert_eq!(
resolve_bin_entry_value(
&NpmPackageNv::from_str("test@1.2.3").unwrap(),
None,
&value
)
.unwrap(),
"./value"
);
// should not resolve when specified and is a string
let value = json!("./value");
assert_eq!(
resolve_bin_entry_value(
&NpmPackageNv::from_str("test@1.2.3").unwrap(),
Some("path"),
&value
)
.err()
.unwrap()
.to_string(),
"package 'test@1.2.3' did not have a bin entry for 'path' in its package.json"
);
}
}

View file

@ -222,7 +222,6 @@ mod startup_snapshot {
impl deno_node::NodeEnv for SnapshotNodeEnv {
type P = Permissions;
type Fs = deno_node::RealFs;
}
deno_core::extension!(runtime,
@ -324,7 +323,7 @@ mod startup_snapshot {
runtime::init_ops_and_esm(),
// FIXME(bartlomieju): these extensions are specified last, because they
// depend on `runtime`, even though it should be other way around
deno_node::deno_node::init_ops_and_esm::<SnapshotNodeEnv>(None),
deno_node::deno_node::init_ops_and_esm::<SnapshotNodeEnv>(None, None),
#[cfg(not(feature = "snapshot_from_snapshot"))]
runtime_main::init_ops_and_esm(),
];

View file

@ -43,6 +43,7 @@ async fn main() -> Result<(), AnyError> {
should_break_on_first_statement: false,
should_wait_for_inspector_session: false,
module_loader,
node_fs: None,
npm_resolver: None,
get_error_class_fn: Some(&get_error_class_name),
cache_storage_dir: None,

View file

@ -39,5 +39,4 @@ pub use worker_bootstrap::BootstrapOptions;
pub struct RuntimeNodeEnv;
impl deno_node::NodeEnv for RuntimeNodeEnv {
type P = permissions::PermissionsContainer;
type Fs = deno_node::RealFs;
}

View file

@ -37,7 +37,6 @@ use deno_core::SourceMapGetter;
use deno_fs::StdFs;
use deno_io::Stdio;
use deno_kv::sqlite::SqliteDbHandler;
use deno_node::NpmResolver;
use deno_tls::rustls::RootCertStore;
use deno_web::create_entangled_message_port;
use deno_web::BlobStore;
@ -333,7 +332,8 @@ pub struct WebWorkerOptions {
pub root_cert_store: Option<RootCertStore>,
pub seed: Option<u64>,
pub module_loader: Rc<dyn ModuleLoader>,
pub npm_resolver: Option<Rc<dyn NpmResolver>>,
pub node_fs: Option<Arc<dyn deno_node::NodeFs>>,
pub npm_resolver: Option<Arc<dyn deno_node::NpmResolver>>,
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
pub preload_module_cb: Arc<ops::worker_host::WorkerEventCb>,
pub pre_execute_module_cb: Arc<ops::worker_host::WorkerEventCb>,
@ -444,6 +444,7 @@ impl WebWorker {
deno_fs::deno_fs::init_ops::<_, PermissionsContainer>(unstable, StdFs),
deno_node::deno_node::init_ops::<crate::RuntimeNodeEnv>(
options.npm_resolver,
options.node_fs,
),
// Runtime ops that are always initialized for WebWorkers
ops::web_worker::deno_web_worker::init_ops(),

View file

@ -33,7 +33,6 @@ use deno_core::SourceMapGetter;
use deno_fs::StdFs;
use deno_io::Stdio;
use deno_kv::sqlite::SqliteDbHandler;
use deno_node::NpmResolver;
use deno_tls::rustls::RootCertStore;
use deno_web::BlobStore;
use log::debug;
@ -94,7 +93,8 @@ pub struct WorkerOptions {
/// If not provided runtime will error if code being
/// executed tries to load modules.
pub module_loader: Rc<dyn ModuleLoader>,
pub npm_resolver: Option<Rc<dyn NpmResolver>>,
pub node_fs: Option<Arc<dyn deno_node::NodeFs>>,
pub npm_resolver: Option<Arc<dyn deno_node::NpmResolver>>,
// Callbacks invoked when creating new instance of WebWorker
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
pub web_worker_preload_module_cb: Arc<ops::worker_host::WorkerEventCb>,
@ -164,6 +164,7 @@ impl Default for WorkerOptions {
broadcast_channel: Default::default(),
source_map_getter: Default::default(),
root_cert_store: Default::default(),
node_fs: Default::default(),
npm_resolver: Default::default(),
blob_store: Default::default(),
extensions: Default::default(),
@ -268,6 +269,7 @@ impl MainWorker {
deno_fs::deno_fs::init_ops::<_, PermissionsContainer>(unstable, StdFs),
deno_node::deno_node::init_ops::<crate::RuntimeNodeEnv>(
options.npm_resolver,
options.node_fs,
),
// Ops from this crate
ops::runtime::deno_runtime::init_ops(main_module.clone()),