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

Merge remote-tracking branch 'upstream/main' into check-workspace-member-compiler-options

This commit is contained in:
Nayeem Rahman 2025-01-15 02:53:07 +00:00
commit 6128282d6e
84 changed files with 15106 additions and 4321 deletions

26
Cargo.lock generated
View file

@ -2139,6 +2139,27 @@ dependencies = [
"thiserror 2.0.3",
]
[[package]]
name = "deno_os"
version = "0.1.0"
dependencies = [
"deno_core",
"deno_error",
"deno_path_util",
"deno_permissions",
"deno_telemetry",
"libc",
"netif",
"ntapi",
"once_cell",
"serde",
"signal-hook",
"signal-hook-registry",
"thiserror 2.0.3",
"tokio",
"winapi",
]
[[package]]
name = "deno_package_json"
version = "0.4.0"
@ -2239,8 +2260,10 @@ dependencies = [
"deno_napi",
"deno_net",
"deno_node",
"deno_os",
"deno_path_util",
"deno_permissions",
"deno_resolver",
"deno_telemetry",
"deno_terminal 0.2.0",
"deno_tls",
@ -2261,7 +2284,6 @@ dependencies = [
"hyper-util",
"libc",
"log",
"netif",
"nix",
"node_resolver",
"notify",
@ -2272,8 +2294,6 @@ dependencies = [
"rustyline",
"same-file",
"serde",
"signal-hook",
"signal-hook-registry",
"sys_traits",
"tempfile",
"test_server",

View file

@ -85,6 +85,7 @@ deno_kv = { version = "0.93.0", path = "./ext/kv" }
deno_napi = { version = "0.116.0", path = "./ext/napi" }
deno_net = { version = "0.177.0", path = "./ext/net" }
deno_node = { version = "0.123.0", path = "./ext/node" }
deno_os = { version = "0.1.0", path = "./ext/os" }
deno_telemetry = { version = "0.7.0", path = "./ext/telemetry" }
deno_tls = { version = "0.172.0", path = "./ext/tls" }
deno_url = { version = "0.185.0", path = "./ext/url" }

5
cli/cache/mod.rs vendored
View file

@ -15,6 +15,7 @@ use deno_graph::source::CacheInfo;
use deno_graph::source::LoadFuture;
use deno_graph::source::LoadResponse;
use deno_graph::source::Loader;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::deno_permissions::PermissionsContainer;
use node_resolver::InNpmPackageChecker;
@ -76,7 +77,7 @@ pub struct FetchCacher {
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
file_fetcher: Arc<CliFileFetcher>,
global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
module_info_cache: Arc<ModuleInfoCache>,
permissions: PermissionsContainer,
sys: CliSys,
@ -88,7 +89,7 @@ impl FetchCacher {
pub fn new(
file_fetcher: Arc<CliFileFetcher>,
global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
module_info_cache: Arc<ModuleInfoCache>,
sys: CliSys,
options: FetchCacherOptions,

View file

@ -24,11 +24,11 @@ use deno_graph::ModuleGraph;
use crate::cache::EmitCache;
use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
#[derive(Debug)]
pub struct Emitter {
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
emit_cache: Arc<EmitCache>,
parsed_source_cache: Arc<ParsedSourceCache>,
transpile_and_emit_options:
@ -39,7 +39,7 @@ pub struct Emitter {
impl Emitter {
pub fn new(
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
emit_cache: Arc<EmitCache>,
parsed_source_cache: Arc<ParsedSourceCache>,
transpile_options: deno_ast::TranspileOptions,

View file

@ -24,6 +24,7 @@ use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
use deno_resolver::DenoResolverOptions;
@ -41,7 +42,6 @@ use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use log::warn;
use node_resolver::analyze::NodeCodeTranslator;
use node_resolver::InNpmPackageChecker;
use once_cell::sync::OnceCell;
use crate::args::check_warn_tsconfig;
@ -79,7 +79,6 @@ use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::create_cli_npm_resolver;
use crate::npm::installer::NpmInstaller;
use crate::npm::installer::NpmResolutionInstaller;
use crate::npm::CliByonmNpmResolverCreateOptions;
@ -94,7 +93,7 @@ use crate::npm::CliNpmTarballCache;
use crate::npm::NpmRegistryReadPermissionChecker;
use crate::npm::NpmRegistryReadPermissionCheckerMode;
use crate::npm::NpmResolutionInitializer;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
use crate::resolver::CliDenoResolver;
use crate::resolver::CliNpmGraphResolver;
use crate::resolver::CliNpmReqResolver;
@ -204,7 +203,7 @@ impl<T> Deferred<T> {
struct CliFactoryServices {
blob_store: Deferred<Arc<BlobStore>>,
caches: Deferred<Arc<Caches>>,
cjs_tracker: Deferred<Arc<CjsTracker>>,
cjs_tracker: Deferred<Arc<CliCjsTracker>>,
cli_options: Deferred<Arc<CliOptions>>,
code_cache: Deferred<Arc<CodeCache>>,
deno_resolver: Deferred<Arc<CliDenoResolver>>,
@ -217,7 +216,7 @@ struct CliFactoryServices {
global_http_cache: Deferred<Arc<GlobalHttpCache>>,
http_cache: Deferred<Arc<dyn HttpCache>>,
http_client_provider: Deferred<Arc<HttpClientProvider>>,
in_npm_pkg_checker: Deferred<Arc<dyn InNpmPackageChecker>>,
in_npm_pkg_checker: Deferred<DenoInNpmPackageChecker>,
main_graph_container: Deferred<Arc<MainModuleGraphContainer>>,
maybe_file_watcher_reporter: Deferred<Option<FileWatcherReporter>>,
maybe_inspector_server: Deferred<Option<Arc<InspectorServer>>>,
@ -237,7 +236,7 @@ struct CliFactoryServices {
npm_resolution: Arc<NpmResolutionCell>,
npm_resolution_initializer: Deferred<Arc<NpmResolutionInitializer>>,
npm_resolution_installer: Deferred<Arc<NpmResolutionInstaller>>,
npm_resolver: Deferred<Arc<dyn CliNpmResolver>>,
npm_resolver: Deferred<CliNpmResolver>,
npm_tarball_cache: Deferred<Arc<CliNpmTarballCache>>,
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
permission_desc_parser:
@ -413,7 +412,7 @@ impl CliFactory {
pub fn in_npm_pkg_checker(
&self,
) -> Result<&Arc<dyn InNpmPackageChecker>, AnyError> {
) -> Result<&DenoInNpmPackageChecker, AnyError> {
self.services.in_npm_pkg_checker.get_or_try_init(|| {
let cli_options = self.cli_options()?;
let options = if cli_options.use_byonm() {
@ -428,7 +427,7 @@ impl CliFactory {
},
)
};
Ok(deno_resolver::npm::create_in_npm_pkg_checker(options))
Ok(DenoInNpmPackageChecker::new(options))
})
}
@ -573,16 +572,14 @@ impl CliFactory {
})
}
pub async fn npm_resolver(
&self,
) -> Result<&Arc<dyn CliNpmResolver>, AnyError> {
pub async fn npm_resolver(&self) -> Result<&CliNpmResolver, AnyError> {
self
.services
.npm_resolver
.get_or_try_init_async(
async {
let cli_options = self.cli_options()?;
Ok(create_cli_npm_resolver(if cli_options.use_byonm() {
Ok(CliNpmResolver::new(if cli_options.use_byonm() {
CliNpmResolverCreateOptions::Byonm(
CliByonmNpmResolverCreateOptions {
sys: self.sys(),
@ -810,11 +807,7 @@ impl CliFactory {
Ok(Arc::new(CliNodeResolver::new(
self.in_npm_pkg_checker()?.clone(),
RealIsBuiltInNodeModuleChecker,
self
.npm_resolver()
.await?
.clone()
.into_npm_pkg_folder_resolver(),
self.npm_resolver().await?.clone(),
self.pkg_json_resolver().clone(),
self.sys(),
node_resolver::ConditionsFromResolutionMode::default(),
@ -847,11 +840,7 @@ impl CliFactory {
cjs_esm_analyzer,
self.in_npm_pkg_checker()?.clone(),
node_resolver,
self
.npm_resolver()
.await?
.clone()
.into_npm_pkg_folder_resolver(),
self.npm_resolver().await?.clone(),
self.pkg_json_resolver().clone(),
self.sys(),
)))
@ -871,7 +860,7 @@ impl CliFactory {
sys: self.sys(),
in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(),
node_resolver: self.node_resolver().await?.clone(),
npm_resolver: npm_resolver.clone().into_byonm_or_managed(),
npm_resolver: npm_resolver.clone(),
})))
})
.await
@ -1002,10 +991,10 @@ impl CliFactory {
.await
}
pub fn cjs_tracker(&self) -> Result<&Arc<CjsTracker>, AnyError> {
pub fn cjs_tracker(&self) -> Result<&Arc<CliCjsTracker>, AnyError> {
self.services.cjs_tracker.get_or_try_init(|| {
let options = self.cli_options()?;
Ok(Arc::new(CjsTracker::new(
Ok(Arc::new(CliCjsTracker::new(
self.in_npm_pkg_checker()?.clone(),
self.pkg_json_resolver().clone(),
if options.is_node_main() || options.unstable_detect_cjs() {
@ -1054,7 +1043,7 @@ impl CliFactory {
self.emitter()?,
self.file_fetcher()?,
self.http_client_provider(),
self.npm_resolver().await?.as_ref(),
self.npm_resolver().await?,
self.workspace_resolver().await?.as_ref(),
cli_options.npm_system_info(),
))

View file

@ -28,6 +28,7 @@ use deno_graph::ModuleLoadError;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use deno_graph::WorkspaceFastCheckOption;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
use deno_resolver::sloppy_imports::SloppyImportsResolutionKind;
use deno_runtime::deno_node;
@ -35,7 +36,6 @@ use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv;
use deno_semver::SmallStackString;
use node_resolver::InNpmPackageChecker;
use crate::args::config_to_deno_graph_workspace_member;
use crate::args::jsr_url;
@ -53,7 +53,7 @@ use crate::file_fetcher::CliFileFetcher;
use crate::npm::installer::NpmInstaller;
use crate::npm::installer::PackageCaching;
use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
use crate::resolver::CliNpmGraphResolver;
use crate::resolver::CliResolver;
use crate::resolver::CliSloppyImportsResolver;
@ -490,17 +490,17 @@ pub enum BuildGraphWithNpmResolutionError {
pub struct ModuleGraphBuilder {
caches: Arc<cache::Caches>,
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
cli_options: Arc<CliOptions>,
file_fetcher: Arc<CliFileFetcher>,
global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
lockfile: Option<Arc<CliLockfile>>,
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
module_info_cache: Arc<ModuleInfoCache>,
npm_graph_resolver: Arc<CliNpmGraphResolver>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer,
@ -511,17 +511,17 @@ impl ModuleGraphBuilder {
#[allow(clippy::too_many_arguments)]
pub fn new(
caches: Arc<cache::Caches>,
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
cli_options: Arc<CliOptions>,
file_fetcher: Arc<CliFileFetcher>,
global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
lockfile: Option<Arc<CliLockfile>>,
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
module_info_cache: Arc<ModuleInfoCache>,
npm_graph_resolver: Arc<CliNpmGraphResolver>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer,
@ -709,8 +709,7 @@ impl ModuleGraphBuilder {
let initial_package_deps_len = graph.packages.package_deps_sum();
let initial_package_mappings_len = graph.packages.mappings().len();
if roots.iter().any(|r| r.scheme() == "npm")
&& self.npm_resolver.as_byonm().is_some()
if roots.iter().any(|r| r.scheme() == "npm") && self.npm_resolver.is_byonm()
{
return Err(BuildGraphWithNpmResolutionError::UnsupportedNpmSpecifierEntrypointResolutionWay);
}
@ -1192,7 +1191,7 @@ fn format_deno_graph_error(err: &dyn Error) -> String {
#[derive(Debug)]
struct CliGraphResolver<'a> {
cjs_tracker: &'a CjsTracker,
cjs_tracker: &'a CliCjsTracker,
resolver: &'a CliResolver,
jsx_import_source_config: Option<JsxImportSourceConfig>,
}

View file

@ -8,7 +8,7 @@ import {
restorePermissions,
} from "ext:cli/40_test_common.js";
import { Console } from "ext:deno_console/01_console.js";
import { setExitHandler } from "ext:runtime/30_os.js";
import { setExitHandler } from "ext:deno_os/30_os.js";
const {
op_register_bench,
op_bench_get_origin,

File diff suppressed because it is too large Load diff

View file

@ -744,8 +744,7 @@ export function compileSelector(selector) {
fn = matchNthChild(node, fn);
break;
case PSEUDO_HAS:
// FIXME
// fn = matchIs(part, fn);
// TODO(@marvinhagemeister)
throw new Error("TODO: :has");
case PSEUDO_NOT:
fn = matchNot(node.selectors, fn);
@ -767,8 +766,7 @@ export function compileSelector(selector) {
*/
function matchFirstChild(next) {
return (ctx, id) => {
const parent = ctx.getParent(id);
const first = ctx.getFirstChild(parent);
const first = ctx.getFirstChild(id);
return first === id && next(ctx, first);
};
}
@ -779,8 +777,7 @@ function matchFirstChild(next) {
*/
function matchLastChild(next) {
return (ctx, id) => {
const parent = ctx.getParent(id);
const last = ctx.getLastChild(parent);
const last = ctx.getLastChild(id);
return last === id && next(ctx, id);
};
}
@ -955,7 +952,9 @@ function matchElem(part, next) {
else if (part.elem === 0) return false;
const type = ctx.getType(id);
if (type > 0 && type === part.elem) return next(ctx, id);
if (type > 0 && type === part.elem) {
return next(ctx, id);
}
return false;
};
@ -968,7 +967,16 @@ function matchElem(part, next) {
*/
function matchAttrExists(attr, next) {
return (ctx, id) => {
return ctx.hasAttrPath(id, attr.prop, 0) ? next(ctx, id) : false;
try {
ctx.getAttrPathValue(id, attr.prop, 0);
return next(ctx, id);
} catch (err) {
if (err === -1) {
return false;
}
throw err;
}
};
}
@ -979,9 +987,15 @@ function matchAttrExists(attr, next) {
*/
function matchAttrBin(attr, next) {
return (ctx, id) => {
if (!ctx.hasAttrPath(id, attr.prop, 0)) return false;
const value = ctx.getAttrPathValue(id, attr.prop, 0);
if (!matchAttrValue(attr, value)) return false;
try {
const value = ctx.getAttrPathValue(id, attr.prop, 0);
if (!matchAttrValue(attr, value)) return false;
} catch (err) {
if (err === -1) {
return false;
}
throw err;
}
return next(ctx, id);
};
}

View file

@ -12,6 +12,8 @@ export interface AstContext {
strTableOffset: number;
rootOffset: number;
nodes: Map<number, NodeFacade>;
spansOffset: number;
propsOffset: number;
strByType: number[];
strByProp: number[];
typeByStr: Map<string, number>;
@ -19,6 +21,12 @@ export interface AstContext {
matcher: MatchContext;
}
export interface Node {
range: Range;
}
export type Range = [number, number];
// TODO(@marvinhagemeister) Remove once we land "official" types
export interface RuleContext {
id: string;
@ -121,7 +129,6 @@ export interface MatchContext {
getSiblings(id: number): number[];
getParent(id: number): number;
getType(id: number): number;
hasAttrPath(id: number, propIds: number[], idx: number): boolean;
getAttrPathValue(id: number, propIds: number[], idx: number): unknown;
}

View file

@ -26,7 +26,7 @@ const {
TypeError,
} = primordials;
import { setExitHandler } from "ext:runtime/30_os.js";
import { setExitHandler } from "ext:deno_os/30_os.js";
// Capture `Deno` global so that users deleting or mangling it, won't
// have impact on our sanitizers.

View file

@ -19,6 +19,7 @@ use deno_core::ModuleSpecifier;
use deno_error::JsErrorBox;
use deno_lint::diagnostic::LintDiagnosticRange;
use deno_path_util::url_to_file_path;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_runtime::deno_node::PathClean;
use deno_semver::jsr::JsrPackageNvReference;
use deno_semver::jsr::JsrPackageReqReference;
@ -31,6 +32,7 @@ use deno_semver::SmallStackString;
use deno_semver::StackString;
use deno_semver::Version;
use import_map::ImportMap;
use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
use once_cell::sync::Lazy;
@ -365,7 +367,9 @@ impl<'a> TsResponseImportMapper<'a> {
if let Ok(Some(pkg_id)) =
npm_resolver.resolve_pkg_id_from_specifier(specifier)
{
let pkg_reqs = npm_resolver.resolve_pkg_reqs_from_pkg_id(&pkg_id);
let pkg_reqs = npm_resolver
.resolution()
.resolve_pkg_reqs_from_pkg_id(&pkg_id);
// check if any pkg reqs match what is found in an import map
if !pkg_reqs.is_empty() {
let sub_path = npm_resolver
@ -1295,6 +1299,19 @@ impl CodeActionCollection {
range: &lsp::Range,
language_server: &language_server::Inner,
) -> Option<lsp::CodeAction> {
fn top_package_req_for_name(
resolution: &NpmResolutionCell,
name: &str,
) -> Option<PackageReq> {
let package_reqs = resolution.package_reqs();
let mut entries = package_reqs
.into_iter()
.filter(|(_, nv)| nv.name == name)
.collect::<Vec<_>>();
entries.sort_by(|a, b| a.1.version.cmp(&b.1.version));
Some(entries.pop()?.0)
}
let (dep_key, dependency, _) =
document.get_maybe_dependency(&range.end)?;
if dependency.maybe_deno_types_specifier.is_some() {
@ -1382,9 +1399,10 @@ impl CodeActionCollection {
.and_then(|versions| versions.first().cloned())?;
let types_specifier_text =
if let Some(npm_resolver) = managed_npm_resolver {
let mut specifier_text = if let Some(req) =
npm_resolver.top_package_req_for_name(&types_package_name)
{
let mut specifier_text = if let Some(req) = top_package_req_for_name(
npm_resolver.resolution(),
&types_package_name,
) {
format!("npm:{req}")
} else {
format!("npm:{}@^{}", &types_package_name, types_package_version)

View file

@ -26,6 +26,7 @@ use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmReqResolver;
@ -35,7 +36,6 @@ use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::ResolutionMode;
@ -56,10 +56,10 @@ use crate::lsp::config::ConfigData;
use crate::lsp::logging::lsp_warn;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::create_cli_npm_resolver;
use crate::npm::installer::NpmInstaller;
use crate::npm::installer::NpmResolutionInstaller;
use crate::npm::CliByonmNpmResolverCreateOptions;
use crate::npm::CliManagedNpmResolver;
use crate::npm::CliManagedNpmResolverCreateOptions;
use crate::npm::CliNpmCache;
use crate::npm::CliNpmCacheHttpClient;
@ -67,14 +67,13 @@ use crate::npm::CliNpmRegistryInfoProvider;
use crate::npm::CliNpmResolver;
use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::ManagedCliNpmResolver;
use crate::npm::NpmResolutionInitializer;
use crate::resolver::CliDenoResolver;
use crate::resolver::CliIsCjsResolver;
use crate::resolver::CliNpmGraphResolver;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver;
use crate::resolver::FoundPackageJsonDepFlag;
use crate::resolver::IsCjsResolver;
use crate::sys::CliSys;
use crate::tsc::into_specifier_and_media_type;
use crate::util::progress_bar::ProgressBar;
@ -83,12 +82,13 @@ use crate::util::progress_bar::ProgressBarStyle;
#[derive(Debug, Clone)]
struct LspScopeResolver {
resolver: Arc<CliResolver>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
is_cjs_resolver: Arc<IsCjsResolver>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
is_cjs_resolver: Arc<CliIsCjsResolver>,
jsr_resolver: Option<Arc<JsrCacheResolver>>,
npm_graph_resolver: Arc<CliNpmGraphResolver>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
npm_resolution: Arc<NpmResolutionCell>,
npm_resolver: Option<CliNpmResolver>,
node_resolver: Option<Arc<CliNodeResolver>>,
npm_pkg_req_resolver: Option<Arc<CliNpmReqResolver>>,
pkg_json_resolver: Arc<CliPackageJsonResolver>,
@ -111,6 +111,7 @@ impl Default for LspScopeResolver {
npm_installer: None,
npm_resolver: None,
node_resolver: None,
npm_resolution: factory.services.npm_resolution.clone(),
npm_pkg_req_resolver: None,
pkg_json_resolver: factory.pkg_json_resolver().clone(),
redirect_resolver: None,
@ -224,6 +225,7 @@ impl LspScopeResolver {
npm_pkg_req_resolver,
npm_resolver,
npm_installer,
npm_resolution: factory.services.npm_resolution.clone(),
node_resolver,
pkg_json_resolver,
redirect_resolver,
@ -235,12 +237,58 @@ impl LspScopeResolver {
}
fn snapshot(&self) -> Arc<Self> {
// create a copy of the resolution and then re-initialize the npm resolver from that
// todo(dsherret): this is pretty terrible... we should improve this. It should
// be possible to just change the npm_resolution on the new factory then access
// another method to create a new npm resolver
let mut factory = ResolverFactory::new(self.config_data.as_ref());
let npm_resolver =
self.npm_resolver.as_ref().map(|r| r.clone_snapshotted());
factory
.services
.npm_resolution
.set_snapshot(self.npm_resolution.snapshot());
let npm_resolver = self.npm_resolver.as_ref();
if let Some(npm_resolver) = &npm_resolver {
factory.set_npm_resolver(npm_resolver.clone());
factory.set_npm_resolver(CliNpmResolver::new::<CliSys>(
match npm_resolver {
CliNpmResolver::Byonm(byonm_npm_resolver) => {
CliNpmResolverCreateOptions::Byonm(
CliByonmNpmResolverCreateOptions {
root_node_modules_dir: byonm_npm_resolver
.root_node_modules_path()
.map(|p| p.to_path_buf()),
sys: CliSys::default(),
pkg_json_resolver: self.pkg_json_resolver.clone(),
},
)
}
CliNpmResolver::Managed(managed_npm_resolver) => {
CliNpmResolverCreateOptions::Managed({
let npmrc = self
.config_data
.as_ref()
.and_then(|d| d.npmrc.clone())
.unwrap_or_else(create_default_npmrc);
let npm_cache_dir = Arc::new(NpmCacheDir::new(
&CliSys::default(),
managed_npm_resolver.global_cache_root_path().to_path_buf(),
npmrc.get_all_known_registries_urls(),
));
CliManagedNpmResolverCreateOptions {
sys: CliSys::default(),
npm_cache_dir,
maybe_node_modules_path: managed_npm_resolver
.root_node_modules_path()
.map(|p| p.to_path_buf()),
npmrc,
npm_resolution: factory.services.npm_resolution.clone(),
npm_system_info: NpmSystemInfo::default(),
}
})
}
},
));
}
Arc::new(Self {
resolver: factory.cli_resolver().clone(),
in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(),
@ -250,6 +298,7 @@ impl LspScopeResolver {
// npm installer isn't necessary for a snapshot
npm_installer: None,
npm_pkg_req_resolver: factory.npm_pkg_req_resolver().cloned(),
npm_resolution: factory.services.npm_resolution.clone(),
npm_resolver: factory.npm_resolver().cloned(),
node_resolver: factory.node_resolver().cloned(),
redirect_resolver: self.redirect_resolver.clone(),
@ -366,7 +415,7 @@ impl LspResolver {
pub fn as_is_cjs_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &IsCjsResolver {
) -> &CliIsCjsResolver {
let resolver = self.get_scope_resolver(file_referrer);
resolver.is_cjs_resolver.as_ref()
}
@ -382,7 +431,7 @@ impl LspResolver {
pub fn in_npm_pkg_checker(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &Arc<dyn InNpmPackageChecker> {
) -> &DenoInNpmPackageChecker {
let resolver = self.get_scope_resolver(file_referrer);
&resolver.in_npm_pkg_checker
}
@ -390,7 +439,7 @@ impl LspResolver {
pub fn maybe_managed_npm_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<&ManagedCliNpmResolver> {
) -> Option<&CliManagedNpmResolver> {
let resolver = self.get_scope_resolver(file_referrer);
resolver.npm_resolver.as_ref().and_then(|r| r.as_managed())
}
@ -605,13 +654,14 @@ pub struct ScopeDepInfo {
struct ResolverFactoryServices {
cli_resolver: Deferred<Arc<CliResolver>>,
found_pkg_json_dep_flag: Arc<FoundPackageJsonDepFlag>,
in_npm_pkg_checker: Deferred<Arc<dyn InNpmPackageChecker>>,
is_cjs_resolver: Deferred<Arc<IsCjsResolver>>,
in_npm_pkg_checker: Deferred<DenoInNpmPackageChecker>,
is_cjs_resolver: Deferred<Arc<CliIsCjsResolver>>,
node_resolver: Deferred<Option<Arc<CliNodeResolver>>>,
npm_graph_resolver: Deferred<Arc<CliNpmGraphResolver>>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_pkg_req_resolver: Deferred<Option<Arc<CliNpmReqResolver>>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
npm_resolver: Option<CliNpmResolver>,
npm_resolution: Arc<NpmResolutionCell>,
}
struct ResolverFactory<'a> {
@ -686,10 +736,9 @@ impl<'a> ResolverFactory<'a> {
npm_client.clone(),
npmrc.clone(),
));
let npm_resolution = Arc::new(NpmResolutionCell::default());
let npm_resolution_initializer = Arc::new(NpmResolutionInitializer::new(
registry_info_provider.clone(),
npm_resolution.clone(),
self.services.npm_resolution.clone(),
match self.config_data.and_then(|d| d.lockfile.as_ref()) {
Some(lockfile) => {
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
@ -712,13 +761,13 @@ impl<'a> ResolverFactory<'a> {
));
let npm_resolution_installer = Arc::new(NpmResolutionInstaller::new(
registry_info_provider,
npm_resolution.clone(),
self.services.npm_resolution.clone(),
maybe_lockfile.clone(),
));
let npm_installer = Arc::new(NpmInstaller::new(
npm_cache.clone(),
Arc::new(NpmInstallDepsProvider::empty()),
npm_resolution.clone(),
self.services.npm_resolution.clone(),
npm_resolution_initializer.clone(),
npm_resolution_installer,
&pb,
@ -745,22 +794,22 @@ impl<'a> ResolverFactory<'a> {
npm_cache_dir,
maybe_node_modules_path,
npmrc,
npm_resolution,
npm_resolution: self.services.npm_resolution.clone(),
npm_system_info: NpmSystemInfo::default(),
})
};
self.set_npm_resolver(create_cli_npm_resolver(options));
self.set_npm_resolver(CliNpmResolver::new(options));
}
pub fn set_npm_installer(&mut self, npm_installer: Arc<NpmInstaller>) {
self.services.npm_installer = Some(npm_installer);
}
pub fn set_npm_resolver(&mut self, npm_resolver: Arc<dyn CliNpmResolver>) {
pub fn set_npm_resolver(&mut self, npm_resolver: CliNpmResolver) {
self.services.npm_resolver = Some(npm_resolver);
}
pub fn npm_resolver(&self) -> Option<&Arc<dyn CliNpmResolver>> {
pub fn npm_resolver(&self) -> Option<&CliNpmResolver> {
self.services.npm_resolver.as_ref()
}
@ -825,29 +874,27 @@ impl<'a> ResolverFactory<'a> {
&self.pkg_json_resolver
}
pub fn in_npm_pkg_checker(&self) -> &Arc<dyn InNpmPackageChecker> {
pub fn in_npm_pkg_checker(&self) -> &DenoInNpmPackageChecker {
self.services.in_npm_pkg_checker.get_or_init(|| {
deno_resolver::npm::create_in_npm_pkg_checker(
match self.services.npm_resolver.as_ref().map(|r| r.as_inner()) {
Some(crate::npm::InnerCliNpmResolverRef::Byonm(_)) | None => {
CreateInNpmPkgCheckerOptions::Byonm
}
Some(crate::npm::InnerCliNpmResolverRef::Managed(m)) => {
CreateInNpmPkgCheckerOptions::Managed(
ManagedInNpmPkgCheckerCreateOptions {
root_cache_dir_url: m.global_cache_root_url(),
maybe_node_modules_path: m.maybe_node_modules_path(),
},
)
}
},
)
DenoInNpmPackageChecker::new(match &self.services.npm_resolver {
Some(CliNpmResolver::Byonm(_)) | None => {
CreateInNpmPkgCheckerOptions::Byonm
}
Some(CliNpmResolver::Managed(m)) => {
CreateInNpmPkgCheckerOptions::Managed(
ManagedInNpmPkgCheckerCreateOptions {
root_cache_dir_url: m.global_cache_root_url(),
maybe_node_modules_path: m.root_node_modules_path(),
},
)
}
})
})
}
pub fn is_cjs_resolver(&self) -> &Arc<IsCjsResolver> {
pub fn is_cjs_resolver(&self) -> &Arc<CliIsCjsResolver> {
self.services.is_cjs_resolver.get_or_init(|| {
Arc::new(IsCjsResolver::new(
Arc::new(CliIsCjsResolver::new(
self.in_npm_pkg_checker().clone(),
self.pkg_json_resolver().clone(),
if self
@ -871,7 +918,7 @@ impl<'a> ResolverFactory<'a> {
Some(Arc::new(CliNodeResolver::new(
self.in_npm_pkg_checker().clone(),
RealIsBuiltInNodeModuleChecker,
npm_resolver.clone().into_npm_pkg_folder_resolver(),
npm_resolver.clone(),
self.pkg_json_resolver.clone(),
self.sys.clone(),
node_resolver::ConditionsFromResolutionMode::default(),
@ -890,7 +937,7 @@ impl<'a> ResolverFactory<'a> {
Some(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions {
in_npm_pkg_checker: self.in_npm_pkg_checker().clone(),
node_resolver: node_resolver.clone(),
npm_resolver: npm_resolver.clone().into_byonm_or_managed(),
npm_resolver: npm_resolver.clone(),
sys: self.sys.clone(),
})))
})

View file

@ -39,6 +39,7 @@ use deno_graph::ModuleGraph;
use deno_graph::ModuleGraphError;
use deno_graph::Resolution;
use deno_graph::WasmModule;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::code_cache;
use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::NodeRequireLoader;
@ -70,7 +71,7 @@ use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver;
use crate::npm::NpmRegistryReadPermissionChecker;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver;
use crate::resolver::ModuleCodeStringSource;
@ -233,10 +234,10 @@ struct SharedCliModuleLoaderState {
initial_cwd: PathBuf,
is_inspecting: bool,
is_repl: bool,
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
main_module_graph_container: Arc<MainModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>,
@ -244,7 +245,7 @@ struct SharedCliModuleLoaderState {
npm_module_loader: NpmModuleLoader,
npm_registry_permission_checker: Arc<NpmRegistryReadPermissionChecker>,
npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>,
sys: CliSys,
@ -294,10 +295,10 @@ impl CliModuleLoaderFactory {
#[allow(clippy::too_many_arguments)]
pub fn new(
options: &CliOptions,
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<CodeCache>>,
emitter: Arc<Emitter>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
main_module_graph_container: Arc<MainModuleGraphContainer>,
module_load_preparer: Arc<ModuleLoadPreparer>,
node_code_translator: Arc<CliNodeCodeTranslator>,
@ -305,7 +306,7 @@ impl CliModuleLoaderFactory {
npm_module_loader: NpmModuleLoader,
npm_registry_permission_checker: Arc<NpmRegistryReadPermissionChecker>,
npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
parsed_source_cache: Arc<ParsedSourceCache>,
resolver: Arc<CliResolver>,
sys: CliSys,
@ -1139,11 +1140,11 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit {
#[derive(Debug)]
struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
emitter: Arc<Emitter>,
sys: CliSys,
graph_container: TGraphContainer,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
npm_registry_permission_checker: Arc<NpmRegistryReadPermissionChecker>,
}

View file

@ -7,6 +7,7 @@ use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
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;
@ -19,15 +20,22 @@ use serde::Serialize;
use crate::cache::CacheDBHash;
use crate::cache::NodeAnalysisCache;
use crate::cache::ParsedSourceCache;
use crate::resolver::CjsTracker;
use crate::npm::CliNpmResolver;
use crate::resolver::CliCjsTracker;
use crate::sys::CliSys;
pub type CliNodeCodeTranslator = NodeCodeTranslator<
CliCjsCodeAnalyzer,
DenoInNpmPackageChecker,
RealIsBuiltInNodeModuleChecker,
CliNpmResolver,
CliSys,
>;
pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver<
DenoInNpmPackageChecker,
CliNpmResolver,
CliSys,
>;
pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver<CliSys>;
pub type CliPackageJsonResolver = node_resolver::PackageJsonResolver<CliSys>;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -43,7 +51,7 @@ pub enum CliCjsAnalysis {
pub struct CliCjsCodeAnalyzer {
cache: NodeAnalysisCache,
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
fs: deno_fs::FileSystemRc,
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
}
@ -51,7 +59,7 @@ pub struct CliCjsCodeAnalyzer {
impl CliCjsCodeAnalyzer {
pub fn new(
cache: NodeAnalysisCache,
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
fs: deno_fs::FileSystemRc,
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
) -> Self {

View file

@ -1,21 +1,12 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_resolver::npm::ByonmNpmResolver;
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_resolver::npm::ByonmOrManagedNpmResolver;
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_semver::package::PackageReq;
use node_resolver::NpmPackageFolderResolver;
use super::CliNpmResolver;
use super::InnerCliNpmResolverRef;
use crate::args::NpmProcessState;
use crate::args::NpmProcessStateKind;
use crate::sys::CliSys;
@ -24,67 +15,18 @@ pub type CliByonmNpmResolverCreateOptions =
ByonmNpmResolverCreateOptions<CliSys>;
pub type CliByonmNpmResolver = ByonmNpmResolver<CliSys>;
// todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple.
#[derive(Debug)]
struct CliByonmWrapper(Arc<CliByonmNpmResolver>);
pub struct CliByonmNpmProcessStateProvider(pub Arc<CliByonmNpmResolver>);
impl NpmProcessStateProvider for CliByonmWrapper {
impl NpmProcessStateProvider for CliByonmNpmProcessStateProvider {
fn get_npm_process_state(&self) -> String {
serde_json::to_string(&NpmProcessState {
kind: NpmProcessStateKind::Byonm,
local_node_modules_path: self
.0
.root_node_modules_dir()
.root_node_modules_path()
.map(|p| p.to_string_lossy().to_string()),
})
.unwrap()
}
}
impl CliNpmResolver for CliByonmNpmResolver {
fn into_npm_pkg_folder_resolver(
self: Arc<Self>,
) -> Arc<dyn NpmPackageFolderResolver> {
self
}
fn into_process_state_provider(
self: Arc<Self>,
) -> Arc<dyn NpmProcessStateProvider> {
Arc::new(CliByonmWrapper(self))
}
fn into_byonm_or_managed(
self: Arc<Self>,
) -> ByonmOrManagedNpmResolver<CliSys> {
ByonmOrManagedNpmResolver::Byonm(self)
}
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver> {
Arc::new(self.clone())
}
fn as_inner(&self) -> InnerCliNpmResolverRef {
InnerCliNpmResolverRef::Byonm(self)
}
fn root_node_modules_path(&self) -> Option<&Path> {
self.root_node_modules_dir()
}
fn check_state_hash(&self) -> Option<u64> {
// it is very difficult to determine the check state hash for byonm
// so we just return None to signify check caching is not supported
None
}
fn resolve_pkg_folder_from_deno_module_req(
&self,
req: &PackageReq,
referrer: &Url,
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
self
.resolve_pkg_folder_from_deno_module_req(req, referrer)
.map_err(ResolvePkgFolderFromDenoReqError::Byonm)
}
}

View file

@ -4,44 +4,28 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_cache_dir::npm::NpmCacheDir;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsError;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmRegistryApi;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::resolution::PackageReqNotFoundError;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmPackageId;
use deno_npm::NpmResolutionPackage;
use deno_npm::NpmSystemInfo;
use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::managed::ResolvePkgFolderFromDenoModuleError;
use deno_resolver::npm::managed::ResolvePkgFolderFromPkgIdError;
use deno_resolver::npm::managed::ResolvePkgIdFromSpecifierError;
use deno_resolver::npm::ByonmOrManagedNpmResolver;
use deno_resolver::npm::ManagedNpmResolver;
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
use deno_resolver::npm::ManagedNpmResolverRc;
use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use node_resolver::NpmPackageFolderResolver;
use sys_traits::FsMetadata;
use thiserror::Error;
use super::CliNpmRegistryInfoProvider;
use super::CliNpmResolver;
use super::InnerCliNpmResolverRef;
use crate::args::CliLockfile;
use crate::args::NpmProcessState;
use crate::args::NpmProcessStateKind;
use crate::cache::FastInsecureHasher;
use crate::sys::CliSys;
pub type CliManagedNpmResolverCreateOptions =
ManagedNpmResolverCreateOptions<CliSys>;
#[derive(Debug, Clone)]
pub enum CliNpmResolverManagedSnapshotOption {
ResolveFromLockfile(Arc<CliLockfile>),
@ -139,36 +123,6 @@ impl NpmResolutionInitializer {
}
}
pub struct CliManagedNpmResolverCreateOptions {
pub npm_cache_dir: Arc<NpmCacheDir>,
pub sys: CliSys,
pub maybe_node_modules_path: Option<PathBuf>,
pub npm_system_info: NpmSystemInfo,
pub npmrc: Arc<ResolvedNpmRc>,
pub npm_resolution: Arc<NpmResolutionCell>,
}
pub fn create_managed_npm_resolver(
options: CliManagedNpmResolverCreateOptions,
) -> Arc<dyn CliNpmResolver> {
let managed_npm_resolver =
Arc::new(ManagedNpmResolver::<CliSys>::new::<CliSys>(
&options.npm_cache_dir,
&options.npmrc,
options.npm_resolution.clone(),
options.sys.clone(),
options.maybe_node_modules_path,
));
Arc::new(ManagedCliNpmResolver::new(
managed_npm_resolver,
options.npm_cache_dir,
options.npmrc,
options.npm_resolution,
options.sys,
options.npm_system_info,
))
}
#[derive(Debug, Error, Clone, JsError)]
#[error("failed reading lockfile '{}'", lockfile_path.display())]
#[class(inherit)]
@ -254,145 +208,6 @@ async fn snapshot_from_lockfile(
Ok(snapshot)
}
/// An npm resolver where the resolution is managed by Deno rather than
/// the user bringing their own node_modules (BYONM) on the file system.
pub struct ManagedCliNpmResolver {
managed_npm_resolver: Arc<ManagedNpmResolver<CliSys>>,
npm_cache_dir: Arc<NpmCacheDir>,
npm_rc: Arc<ResolvedNpmRc>,
sys: CliSys,
resolution: Arc<NpmResolutionCell>,
system_info: NpmSystemInfo,
}
impl std::fmt::Debug for ManagedCliNpmResolver {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ManagedCliNpmResolver")
.field("<omitted>", &"<omitted>")
.finish()
}
}
impl ManagedCliNpmResolver {
#[allow(clippy::too_many_arguments)]
pub fn new(
managed_npm_resolver: Arc<ManagedNpmResolver<CliSys>>,
npm_cache_dir: Arc<NpmCacheDir>,
npm_rc: Arc<ResolvedNpmRc>,
resolution: Arc<NpmResolutionCell>,
sys: CliSys,
system_info: NpmSystemInfo,
) -> Self {
Self {
managed_npm_resolver,
npm_cache_dir,
npm_rc,
resolution,
sys,
system_info,
}
}
pub fn resolve_pkg_folder_from_pkg_id(
&self,
pkg_id: &NpmPackageId,
) -> Result<PathBuf, ResolvePkgFolderFromPkgIdError> {
self
.managed_npm_resolver
.resolve_pkg_folder_from_pkg_id(pkg_id)
}
/// Resolves the package id from the provided specifier.
pub fn resolve_pkg_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageId>, ResolvePkgIdFromSpecifierError> {
self
.managed_npm_resolver
.resolve_pkg_id_from_specifier(specifier)
}
pub fn resolve_pkg_reqs_from_pkg_id(
&self,
id: &NpmPackageId,
) -> Vec<PackageReq> {
self.resolution.resolve_pkg_reqs_from_pkg_id(id)
}
pub fn all_system_packages(
&self,
system_info: &NpmSystemInfo,
) -> Vec<NpmResolutionPackage> {
self.resolution.all_system_packages(system_info)
}
/// Checks if the provided package req's folder is cached.
pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool {
self
.resolve_pkg_id_from_pkg_req(req)
.ok()
.and_then(|id| {
self
.managed_npm_resolver
.resolve_pkg_folder_from_pkg_id(&id)
.ok()
})
.map(|folder| self.sys.fs_exists_no_err(folder))
.unwrap_or(false)
}
pub fn snapshot(&self) -> NpmResolutionSnapshot {
self.resolution.snapshot()
}
pub fn top_package_req_for_name(&self, name: &str) -> Option<PackageReq> {
let package_reqs = self.resolution.package_reqs();
let mut entries = package_reqs
.iter()
.filter(|(_, nv)| nv.name == name)
.collect::<Vec<_>>();
entries.sort_by_key(|(_, nv)| &nv.version);
Some(entries.last()?.0.clone())
}
pub fn serialized_valid_snapshot_for_system(
&self,
system_info: &NpmSystemInfo,
) -> ValidSerializedNpmResolutionSnapshot {
self
.resolution
.serialized_valid_snapshot_for_system(system_info)
}
pub fn resolve_pkg_folder_from_deno_module(
&self,
nv: &PackageNv,
) -> Result<PathBuf, ResolvePkgFolderFromDenoModuleError> {
self
.managed_npm_resolver
.resolve_pkg_folder_from_deno_module(nv)
}
pub fn resolve_pkg_id_from_pkg_req(
&self,
req: &PackageReq,
) -> Result<NpmPackageId, PackageReqNotFoundError> {
self.resolution.resolve_pkg_id_from_pkg_req(req)
}
pub fn maybe_node_modules_path(&self) -> Option<&Path> {
self.managed_npm_resolver.node_modules_path()
}
pub fn global_cache_root_path(&self) -> &Path {
self.npm_cache_dir.root_dir()
}
pub fn global_cache_root_url(&self) -> &Url {
self.npm_cache_dir.root_dir_url()
}
}
pub fn npm_process_state(
snapshot: ValidSerializedNpmResolutionSnapshot,
node_modules_path: Option<&Path>,
@ -405,92 +220,14 @@ pub fn npm_process_state(
.unwrap()
}
impl NpmProcessStateProvider for ManagedCliNpmResolver {
#[derive(Debug)]
pub struct CliManagedNpmProcessStateProvider(pub ManagedNpmResolverRc<CliSys>);
impl NpmProcessStateProvider for CliManagedNpmProcessStateProvider {
fn get_npm_process_state(&self) -> String {
npm_process_state(
self.resolution.serialized_valid_snapshot(),
self.managed_npm_resolver.node_modules_path(),
self.0.resolution().serialized_valid_snapshot(),
self.0.root_node_modules_path(),
)
}
}
impl CliNpmResolver for ManagedCliNpmResolver {
fn into_npm_pkg_folder_resolver(
self: Arc<Self>,
) -> Arc<dyn NpmPackageFolderResolver> {
self.managed_npm_resolver.clone()
}
fn into_process_state_provider(
self: Arc<Self>,
) -> Arc<dyn NpmProcessStateProvider> {
self
}
fn into_byonm_or_managed(
self: Arc<Self>,
) -> ByonmOrManagedNpmResolver<CliSys> {
ByonmOrManagedNpmResolver::Managed(self.managed_npm_resolver.clone())
}
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver> {
// create a new snapshotted npm resolution and resolver
let npm_resolution =
Arc::new(NpmResolutionCell::new(self.resolution.snapshot()));
Arc::new(ManagedCliNpmResolver::new(
Arc::new(ManagedNpmResolver::<CliSys>::new::<CliSys>(
&self.npm_cache_dir,
&self.npm_rc,
npm_resolution.clone(),
self.sys.clone(),
self.root_node_modules_path().map(ToOwned::to_owned),
)),
self.npm_cache_dir.clone(),
self.npm_rc.clone(),
npm_resolution,
self.sys.clone(),
self.system_info.clone(),
))
}
fn as_inner(&self) -> InnerCliNpmResolverRef {
InnerCliNpmResolverRef::Managed(self)
}
fn root_node_modules_path(&self) -> Option<&Path> {
self.managed_npm_resolver.node_modules_path()
}
fn check_state_hash(&self) -> Option<u64> {
// We could go further and check all the individual
// npm packages, but that's probably overkill.
let mut package_reqs = self
.resolution
.package_reqs()
.into_iter()
.collect::<Vec<_>>();
package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism
let mut hasher = FastInsecureHasher::new_without_deno_version();
// ensure the cache gets busted when turning nodeModulesDir on or off
// as this could cause changes in resolution
hasher
.write_hashable(self.managed_npm_resolver.node_modules_path().is_some());
for (pkg_req, pkg_nv) in package_reqs {
hasher.write_hashable(&pkg_req);
hasher.write_hashable(&pkg_nv);
}
Some(hasher.finish())
}
fn resolve_pkg_folder_from_deno_module_req(
&self,
req: &PackageReq,
referrer: &Url,
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
self
.managed_npm_resolver
.resolve_pkg_folder_from_deno_module_req(req, referrer)
.map_err(ResolvePkgFolderFromDenoReqError::Managed)
}
}

View file

@ -5,8 +5,6 @@ pub mod installer;
mod managed;
mod permission_checker;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use dashmap::DashMap;
@ -15,21 +13,15 @@ use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo;
use deno_resolver::npm::ByonmNpmResolver;
use deno_resolver::npm::ByonmOrManagedNpmResolver;
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
use deno_runtime::ops::process::NpmProcessStateProvider;
use deno_runtime::ops::process::NpmProcessStateProviderRc;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use http::HeaderName;
use http::HeaderValue;
use node_resolver::NpmPackageFolderResolver;
pub use self::byonm::CliByonmNpmResolver;
pub use self::byonm::CliByonmNpmResolverCreateOptions;
pub use self::managed::CliManagedNpmResolverCreateOptions;
pub use self::managed::CliNpmResolverManagedSnapshotOption;
pub use self::managed::ManagedCliNpmResolver;
pub use self::managed::NpmResolutionInitializer;
pub use self::managed::ResolveSnapshotError;
pub use self::permission_checker::NpmRegistryReadPermissionChecker;
@ -44,6 +36,10 @@ pub type CliNpmTarballCache =
pub type CliNpmCache = deno_npm_cache::NpmCache<CliSys>;
pub type CliNpmRegistryInfoProvider =
deno_npm_cache::RegistryInfoProvider<CliNpmCacheHttpClient, CliSys>;
pub type CliNpmResolver = deno_resolver::npm::NpmResolver<CliSys>;
pub type CliManagedNpmResolver = deno_resolver::npm::ManagedNpmResolver<CliSys>;
pub type CliNpmResolverCreateOptions =
deno_resolver::npm::NpmResolverCreateOptions<CliSys>;
#[derive(Debug)]
pub struct CliNpmCacheHttpClient {
@ -63,6 +59,19 @@ impl CliNpmCacheHttpClient {
}
}
pub fn create_npm_process_state_provider(
npm_resolver: &CliNpmResolver,
) -> NpmProcessStateProviderRc {
match npm_resolver {
CliNpmResolver::Byonm(byonm_npm_resolver) => Arc::new(
byonm::CliByonmNpmProcessStateProvider(byonm_npm_resolver.clone()),
),
CliNpmResolver::Managed(managed_npm_resolver) => Arc::new(
managed::CliManagedNpmProcessStateProvider(managed_npm_resolver.clone()),
),
}
}
#[async_trait::async_trait(?Send)]
impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient {
async fn download_with_retries_on_any_tokio_runtime(
@ -104,70 +113,6 @@ impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient {
}
}
pub enum CliNpmResolverCreateOptions {
Managed(CliManagedNpmResolverCreateOptions),
Byonm(CliByonmNpmResolverCreateOptions),
}
pub fn create_cli_npm_resolver(
options: CliNpmResolverCreateOptions,
) -> Arc<dyn CliNpmResolver> {
use CliNpmResolverCreateOptions::*;
match options {
Managed(options) => managed::create_managed_npm_resolver(options),
Byonm(options) => Arc::new(ByonmNpmResolver::new(options)),
}
}
pub enum InnerCliNpmResolverRef<'a> {
Managed(&'a ManagedCliNpmResolver),
#[allow(dead_code)]
Byonm(&'a CliByonmNpmResolver),
}
// todo(dsherret): replace with an enum
pub trait CliNpmResolver: Send + Sync + std::fmt::Debug {
fn into_npm_pkg_folder_resolver(
self: Arc<Self>,
) -> Arc<dyn NpmPackageFolderResolver>;
fn into_process_state_provider(
self: Arc<Self>,
) -> Arc<dyn NpmProcessStateProvider>;
fn into_byonm_or_managed(
self: Arc<Self>,
) -> ByonmOrManagedNpmResolver<CliSys>;
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver>;
fn as_inner(&self) -> InnerCliNpmResolverRef;
fn as_managed(&self) -> Option<&ManagedCliNpmResolver> {
match self.as_inner() {
InnerCliNpmResolverRef::Managed(inner) => Some(inner),
InnerCliNpmResolverRef::Byonm(_) => None,
}
}
fn as_byonm(&self) -> Option<&CliByonmNpmResolver> {
match self.as_inner() {
InnerCliNpmResolverRef::Managed(_) => None,
InnerCliNpmResolverRef::Byonm(inner) => Some(inner),
}
}
fn resolve_pkg_folder_from_deno_module_req(
&self,
req: &PackageReq,
referrer: &Url,
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError>;
fn root_node_modules_path(&self) -> Option<&Path>;
/// Returns a hash returning the state of the npm resolver
/// or `None` if the state currently can't be determined.
fn check_state_hash(&self) -> Option<u64>;
}
#[derive(Debug)]
pub struct NpmFetchResolver {
nv_by_req: DashMap<PackageReq, Option<PackageNv>>,

View file

@ -19,6 +19,7 @@ use deno_graph::source::UnknownBuiltInNodeModuleError;
use deno_graph::NpmLoadError;
use deno_graph::NpmResolvePkgReqsResult;
use deno_npm::resolution::NpmResolutionError;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::sloppy_imports::SloppyImportsCachedFs;
use deno_resolver::sloppy_imports::SloppyImportsResolver;
use deno_runtime::colors;
@ -35,22 +36,31 @@ use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS;
use crate::node::CliNodeCodeTranslator;
use crate::npm::installer::NpmInstaller;
use crate::npm::installer::PackageCaching;
use crate::npm::CliNpmResolver;
use crate::sys::CliSys;
use crate::util::sync::AtomicFlag;
use crate::util::text_encoding::from_utf8_lossy_cow;
pub type CjsTracker = deno_resolver::cjs::CjsTracker<CliSys>;
pub type IsCjsResolver = deno_resolver::cjs::IsCjsResolver<CliSys>;
pub type CliCjsTracker =
deno_resolver::cjs::CjsTracker<DenoInNpmPackageChecker, CliSys>;
pub type CliIsCjsResolver =
deno_resolver::cjs::IsCjsResolver<DenoInNpmPackageChecker, CliSys>;
pub type CliSloppyImportsCachedFs = SloppyImportsCachedFs<CliSys>;
pub type CliSloppyImportsResolver =
SloppyImportsResolver<CliSloppyImportsCachedFs>;
pub type CliDenoResolver = deno_resolver::DenoResolver<
DenoInNpmPackageChecker,
RealIsBuiltInNodeModuleChecker,
CliNpmResolver,
CliSloppyImportsCachedFs,
CliSys,
>;
pub type CliNpmReqResolver =
deno_resolver::npm::NpmReqResolver<RealIsBuiltInNodeModuleChecker, CliSys>;
pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver<
DenoInNpmPackageChecker,
RealIsBuiltInNodeModuleChecker,
CliNpmResolver,
CliSys,
>;
pub struct ModuleCodeStringSource {
pub code: ModuleSourceCode,
@ -69,14 +79,14 @@ pub struct NotSupportedKindInNpmError {
// todo(dsherret): move to module_loader.rs (it seems to be here due to use in standalone)
#[derive(Clone)]
pub struct NpmModuleLoader {
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
fs: Arc<dyn deno_fs::FileSystem>,
node_code_translator: Arc<CliNodeCodeTranslator>,
}
impl NpmModuleLoader {
pub fn new(
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
fs: Arc<dyn deno_fs::FileSystem>,
node_code_translator: Arc<CliNodeCodeTranslator>,
) -> Self {

View file

@ -92,8 +92,7 @@ use crate::emit::Emitter;
use crate::file_fetcher::CliFileFetcher;
use crate::http_util::HttpClientProvider;
use crate::npm::CliNpmResolver;
use crate::npm::InnerCliNpmResolverRef;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
use crate::shared::ReleaseChannel;
use crate::standalone::virtual_fs::VfsEntry;
use crate::util::archive;
@ -410,13 +409,13 @@ pub struct WriteBinOptions<'a> {
}
pub struct DenoCompileBinaryWriter<'a> {
cjs_tracker: &'a CjsTracker,
cjs_tracker: &'a CliCjsTracker,
cli_options: &'a CliOptions,
deno_dir: &'a DenoDir,
emitter: &'a Emitter,
file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a dyn CliNpmResolver,
npm_resolver: &'a CliNpmResolver,
workspace_resolver: &'a WorkspaceResolver,
npm_system_info: NpmSystemInfo,
}
@ -424,13 +423,13 @@ pub struct DenoCompileBinaryWriter<'a> {
impl<'a> DenoCompileBinaryWriter<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new(
cjs_tracker: &'a CjsTracker,
cjs_tracker: &'a CliCjsTracker,
cli_options: &'a CliOptions,
deno_dir: &'a DenoDir,
emitter: &'a Emitter,
file_fetcher: &'a CliFileFetcher,
http_client_provider: &'a HttpClientProvider,
npm_resolver: &'a dyn CliNpmResolver,
npm_resolver: &'a CliNpmResolver,
workspace_resolver: &'a WorkspaceResolver,
npm_system_info: NpmSystemInfo,
) -> Self {
@ -599,10 +598,11 @@ impl<'a> DenoCompileBinaryWriter<'a> {
None => None,
};
let mut vfs = VfsBuilder::new();
let npm_snapshot = match self.npm_resolver.as_inner() {
InnerCliNpmResolverRef::Managed(managed) => {
let snapshot =
managed.serialized_valid_snapshot_for_system(&self.npm_system_info);
let npm_snapshot = match &self.npm_resolver {
CliNpmResolver::Managed(managed) => {
let snapshot = managed
.resolution()
.serialized_valid_snapshot_for_system(&self.npm_system_info);
if !snapshot.as_serialized().packages.is_empty() {
self.fill_npm_vfs(&mut vfs).context("Building npm vfs.")?;
Some(snapshot)
@ -610,7 +610,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
None
}
}
InnerCliNpmResolverRef::Byonm(_) => {
CliNpmResolver::Byonm(_) => {
self.fill_npm_vfs(&mut vfs)?;
None
}
@ -751,8 +751,8 @@ impl<'a> DenoCompileBinaryWriter<'a> {
);
}
let node_modules = match self.npm_resolver.as_inner() {
InnerCliNpmResolverRef::Managed(_) => {
let node_modules = match &self.npm_resolver {
CliNpmResolver::Managed(_) => {
npm_snapshot.as_ref().map(|_| NodeModules::Managed {
node_modules_dir: self.npm_resolver.root_node_modules_path().map(
|path| {
@ -765,7 +765,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
),
})
}
InnerCliNpmResolverRef::Byonm(resolver) => Some(NodeModules::Byonm {
CliNpmResolver::Byonm(resolver) => Some(NodeModules::Byonm {
root_node_modules_dir: resolver.root_node_modules_path().map(
|node_modules_dir| {
root_dir_url
@ -880,16 +880,17 @@ impl<'a> DenoCompileBinaryWriter<'a> {
}
}
match self.npm_resolver.as_inner() {
InnerCliNpmResolverRef::Managed(npm_resolver) => {
match &self.npm_resolver {
CliNpmResolver::Managed(npm_resolver) => {
if let Some(node_modules_path) = npm_resolver.root_node_modules_path() {
maybe_warn_different_system(&self.npm_system_info);
builder.add_dir_recursive(node_modules_path)?;
Ok(())
} else {
// we'll flatten to remove any custom registries later
let mut packages =
npm_resolver.all_system_packages(&self.npm_system_info);
let mut packages = npm_resolver
.resolution()
.all_system_packages(&self.npm_system_info);
packages.sort_by(|a, b| a.id.cmp(&b.id)); // determinism
for package in packages {
let folder =
@ -899,7 +900,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
Ok(())
}
}
InnerCliNpmResolverRef::Byonm(_) => {
CliNpmResolver::Byonm(_) => {
maybe_warn_different_system(&self.npm_system_info);
for pkg_json in self.cli_options.workspace().package_jsons() {
builder.add_file_at_path(&pkg_json.path)?;
@ -942,8 +943,8 @@ impl<'a> DenoCompileBinaryWriter<'a> {
&self,
mut vfs: VfsBuilder,
) -> BuiltVfs {
match self.npm_resolver.as_inner() {
InnerCliNpmResolverRef::Managed(npm_resolver) => {
match &self.npm_resolver {
CliNpmResolver::Managed(npm_resolver) => {
if npm_resolver.root_node_modules_path().is_some() {
return vfs.build();
}
@ -1007,8 +1008,16 @@ impl<'a> DenoCompileBinaryWriter<'a> {
// this is not as optimized as it could be
let mut last_name =
Cow::Borrowed(DENO_COMPILE_GLOBAL_NODE_MODULES_DIR_NAME);
for ancestor in parent.ancestors() {
let dir = vfs.get_dir_mut(ancestor).unwrap();
for ancestor in
parent.ancestors().map(Some).chain(std::iter::once(None))
{
let dir = if let Some(ancestor) = ancestor {
vfs.get_dir_mut(ancestor).unwrap()
} else if cfg!(windows) {
vfs.get_system_root_dir_mut()
} else {
break;
};
if let Ok(index) =
dir.entries.binary_search(&last_name, case_sensitivity)
{
@ -1027,7 +1036,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
.insert(npm_global_cache_dir_entry, case_sensitivity);
built_vfs
}
InnerCliNpmResolverRef::Byonm(_) => vfs.build(),
CliNpmResolver::Byonm(_) => vfs.build(),
}
}
}

View file

@ -40,10 +40,11 @@ use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_package_json::PackageJsonDepValue;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::create_in_npm_pkg_checker;
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmReqResolverOptions;
use deno_runtime::deno_fs;
use deno_runtime::deno_fs::FileSystem;
@ -85,7 +86,6 @@ use crate::node::CliCjsCodeAnalyzer;
use crate::node::CliNodeCodeTranslator;
use crate::node::CliNodeResolver;
use crate::node::CliPackageJsonResolver;
use crate::npm::create_cli_npm_resolver;
use crate::npm::CliByonmNpmResolverCreateOptions;
use crate::npm::CliManagedNpmResolverCreateOptions;
use crate::npm::CliNpmResolver;
@ -94,7 +94,7 @@ use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::NpmRegistryReadPermissionChecker;
use crate::npm::NpmRegistryReadPermissionCheckerMode;
use crate::npm::NpmResolutionInitializer;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::NpmModuleLoader;
use crate::sys::CliSys;
@ -122,7 +122,7 @@ use self::binary::Metadata;
pub use self::file_system::DenoCompileFileSystem;
struct SharedModuleLoaderState {
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
code_cache: Option<Arc<dyn CliCodeCache>>,
fs: Arc<dyn deno_fs::FileSystem>,
modules: StandaloneModules,
@ -131,7 +131,7 @@ struct SharedModuleLoaderState {
npm_module_loader: Arc<NpmModuleLoader>,
npm_registry_permission_checker: NpmRegistryReadPermissionChecker,
npm_req_resolver: Arc<CliNpmReqResolver>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
source_maps: SourceMapStore,
vfs: Arc<FileBackedVfs>,
workspace_resolver: WorkspaceResolver,
@ -734,7 +734,7 @@ pub async fn run(
let maybe_node_modules_path = node_modules_dir
.map(|node_modules_dir| root_path.join(node_modules_dir));
let in_npm_pkg_checker =
create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Managed(
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed(
ManagedInNpmPkgCheckerCreateOptions {
root_cache_dir_url: npm_cache_dir.root_dir_url(),
maybe_node_modules_path: maybe_node_modules_path.as_deref(),
@ -743,7 +743,7 @@ pub async fn run(
let npm_resolution =
Arc::new(NpmResolutionCell::new(NpmResolutionSnapshot::new(snapshot)));
let npm_resolver =
create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed(
CliNpmResolver::new(CliNpmResolverCreateOptions::Managed(
CliManagedNpmResolverCreateOptions {
npm_resolution,
npm_cache_dir,
@ -761,8 +761,8 @@ pub async fn run(
let root_node_modules_dir =
root_node_modules_dir.map(|p| vfs.root().join(p));
let in_npm_pkg_checker =
create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Byonm);
let npm_resolver = create_cli_npm_resolver(
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Byonm);
let npm_resolver = CliNpmResolver::new(
CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions {
sys: sys.clone(),
pkg_json_resolver: pkg_json_resolver.clone(),
@ -781,7 +781,7 @@ pub async fn run(
npmrc.get_all_known_registries_urls(),
));
let in_npm_pkg_checker =
create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Managed(
DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed(
ManagedInNpmPkgCheckerCreateOptions {
root_cache_dir_url: npm_cache_dir.root_dir_url(),
maybe_node_modules_path: None,
@ -789,7 +789,7 @@ pub async fn run(
));
let npm_resolution = Arc::new(NpmResolutionCell::default());
let npm_resolver =
create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed(
CliNpmResolver::new(CliNpmResolverCreateOptions::Managed(
CliManagedNpmResolverCreateOptions {
npm_resolution,
sys: sys.clone(),
@ -807,12 +807,12 @@ pub async fn run(
let node_resolver = Arc::new(NodeResolver::new(
in_npm_pkg_checker.clone(),
RealIsBuiltInNodeModuleChecker,
npm_resolver.clone().into_npm_pkg_folder_resolver(),
npm_resolver.clone(),
pkg_json_resolver.clone(),
sys.clone(),
node_resolver::ConditionsFromResolutionMode::default(),
));
let cjs_tracker = Arc::new(CjsTracker::new(
let cjs_tracker = Arc::new(CliCjsTracker::new(
in_npm_pkg_checker.clone(),
pkg_json_resolver.clone(),
if metadata.unstable_config.detect_cjs {
@ -830,7 +830,7 @@ pub async fn run(
sys: sys.clone(),
in_npm_pkg_checker: in_npm_pkg_checker.clone(),
node_resolver: node_resolver.clone(),
npm_resolver: npm_resolver.clone().into_byonm_or_managed(),
npm_resolver: npm_resolver.clone(),
}));
let cjs_esm_code_analyzer = CliCjsCodeAnalyzer::new(
node_analysis_cache,
@ -842,7 +842,7 @@ pub async fn run(
cjs_esm_code_analyzer,
in_npm_pkg_checker,
node_resolver.clone(),
npm_resolver.clone().into_npm_pkg_folder_resolver(),
npm_resolver.clone(),
pkg_json_resolver.clone(),
sys.clone(),
));

View file

@ -25,9 +25,8 @@ use tokio::task::LocalSet;
use tokio_util::sync::CancellationToken;
use crate::node::CliNodeResolver;
use crate::npm::CliManagedNpmResolver;
use crate::npm::CliNpmResolver;
use crate::npm::InnerCliNpmResolverRef;
use crate::npm::ManagedCliNpmResolver;
pub fn get_script_with_args(script: &str, argv: &[String]) -> String {
let additional_args = argv
@ -414,15 +413,15 @@ impl ShellCommand for NodeModulesFileRunCommand {
}
pub fn resolve_custom_commands(
npm_resolver: &dyn CliNpmResolver,
npm_resolver: &CliNpmResolver,
node_resolver: &CliNodeResolver,
) -> Result<HashMap<String, Rc<dyn ShellCommand>>, AnyError> {
let mut commands = match npm_resolver.as_inner() {
InnerCliNpmResolverRef::Byonm(npm_resolver) => {
let mut commands = match npm_resolver {
CliNpmResolver::Byonm(npm_resolver) => {
let node_modules_dir = npm_resolver.root_node_modules_path().unwrap();
resolve_npm_commands_from_bin_dir(node_modules_dir)
}
InnerCliNpmResolverRef::Managed(npm_resolver) => {
CliNpmResolver::Managed(npm_resolver) => {
resolve_managed_npm_commands(npm_resolver, node_resolver)?
}
};
@ -521,13 +520,12 @@ fn resolve_execution_path_from_npx_shim(
}
fn resolve_managed_npm_commands(
npm_resolver: &ManagedCliNpmResolver,
npm_resolver: &CliManagedNpmResolver,
node_resolver: &CliNodeResolver,
) -> 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 package_folder = npm_resolver.resolve_pkg_folder_from_pkg_id(id)?;
for id in npm_resolver.resolution().top_level_packages() {
let package_folder = npm_resolver.resolve_pkg_folder_from_pkg_id(&id)?;
let bin_commands =
node_resolver.resolve_binary_commands(&package_folder)?;
for bin_command in bin_commands {
@ -598,7 +596,7 @@ async fn listen_ctrl_c(kill_signal: KillSignal) {
#[cfg(unix)]
async fn listen_and_forward_all_signals(kill_signal: KillSignal) {
use deno_core::futures::FutureExt;
use deno_runtime::signal::SIGNAL_NUMS;
use deno_runtime::deno_os::signal::SIGNAL_NUMS;
// listen and forward every signal we support
let mut futures = Vec::with_capacity(SIGNAL_NUMS.len());

View file

@ -114,7 +114,7 @@ pub struct TypeChecker {
module_graph_builder: Arc<ModuleGraphBuilder>,
npm_installer: Option<Arc<NpmInstaller>>,
node_resolver: Arc<CliNodeResolver>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
sys: CliSys,
}
@ -148,7 +148,7 @@ impl TypeChecker {
module_graph_builder: Arc<ModuleGraphBuilder>,
node_resolver: Arc<CliNodeResolver>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
sys: CliSys,
) -> Self {
Self {
@ -191,6 +191,29 @@ impl TypeChecker {
mut graph: ModuleGraph,
options: CheckOptions,
) -> Result<(Arc<ModuleGraph>, Diagnostics), CheckError> {
fn check_state_hash(resolver: &CliNpmResolver) -> Option<u64> {
match resolver {
CliNpmResolver::Byonm(_) => {
// not feasible and probably slower to compute
None
}
CliNpmResolver::Managed(resolver) => {
// we should probably go further and check all the individual npm packages
let mut package_reqs = resolver.resolution().package_reqs();
package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism
let mut hasher = FastInsecureHasher::new_without_deno_version();
// ensure the cache gets busted when turning nodeModulesDir on or off
// as this could cause changes in resolution
hasher.write_hashable(resolver.root_node_modules_path().is_some());
for (pkg_req, pkg_nv) in package_reqs {
hasher.write_hashable(&pkg_req);
hasher.write_hashable(&pkg_nv);
}
Some(hasher.finish())
}
}
}
if !options.type_check_mode.is_true() || graph.roots.is_empty() {
return Ok((graph.into(), Default::default()));
}
@ -265,7 +288,7 @@ impl TypeChecker {
&self.sys,
&graph,
check_js,
self.npm_resolver.check_state_hash(),
check_state_hash(&self.npm_resolver),
type_check_mode,
&ts_config,
);

View file

@ -22,6 +22,7 @@ use deno_core::serde_json;
use deno_core::sourcemap::SourceMap;
use deno_core::url::Url;
use deno_core::LocalInspectorSession;
use deno_resolver::npm::DenoInNpmPackageChecker;
use node_resolver::InNpmPackageChecker;
use regex::Regex;
use text_lines::TextLines;
@ -464,7 +465,7 @@ fn filter_coverages(
coverages: Vec<cdp::ScriptCoverage>,
include: Vec<String>,
exclude: Vec<String>,
in_npm_pkg_checker: &dyn InNpmPackageChecker,
in_npm_pkg_checker: &DenoInNpmPackageChecker,
) -> Vec<cdp::ScriptCoverage> {
let include: Vec<Regex> =
include.iter().map(|e| Regex::new(e).unwrap()).collect();
@ -532,7 +533,7 @@ pub fn cover_files(
script_coverages,
coverage_flags.include,
coverage_flags.exclude,
in_npm_pkg_checker.as_ref(),
in_npm_pkg_checker,
);
if script_coverages.is_empty() {
return Err(anyhow!("No covered files included in the report"));

View file

@ -32,8 +32,7 @@ use crate::args::InfoFlags;
use crate::display;
use crate::factory::CliFactory;
use crate::graph_util::graph_exit_integrity_errors;
use crate::npm::CliNpmResolver;
use crate::npm::ManagedCliNpmResolver;
use crate::npm::CliManagedNpmResolver;
use crate::util::checksum;
use crate::util::display::DisplayTreeNode;
@ -138,6 +137,10 @@ pub async fn info(
lockfile.write_if_changed()?;
}
let maybe_npm_info = npm_resolver
.as_managed()
.map(|r| (r, r.resolution().snapshot()));
if info_flags.json {
let mut json_graph = serde_json::json!(graph);
if let Some(output) = json_graph.as_object_mut() {
@ -148,11 +151,19 @@ pub async fn info(
);
}
add_npm_packages_to_json(&mut json_graph, npm_resolver.as_ref(), npmrc);
add_npm_packages_to_json(
&mut json_graph,
maybe_npm_info.as_ref().map(|(_, s)| s),
npmrc,
);
display::write_json_to_stdout(&json_graph)?;
} else {
let mut output = String::new();
GraphDisplayContext::write(&graph, npm_resolver.as_ref(), &mut output)?;
GraphDisplayContext::write(
&graph,
maybe_npm_info.as_ref().map(|(r, s)| (*r, s)),
&mut output,
)?;
display::write_to_stdout_ignore_sigpipe(output.as_bytes())?;
}
} else {
@ -251,15 +262,14 @@ fn print_cache_info(
fn add_npm_packages_to_json(
json: &mut serde_json::Value,
npm_resolver: &dyn CliNpmResolver,
npm_snapshot: Option<&NpmResolutionSnapshot>,
npmrc: &ResolvedNpmRc,
) {
let Some(npm_resolver) = npm_resolver.as_managed() else {
let Some(npm_snapshot) = npm_snapshot else {
return; // does not include byonm to deno info's output
};
// ideally deno_graph could handle this, but for now we just modify the json here
let snapshot = npm_resolver.snapshot();
let json = json.as_object_mut().unwrap();
let modules = json.get_mut("modules").and_then(|m| m.as_array_mut());
if let Some(modules) = modules {
@ -273,7 +283,7 @@ fn add_npm_packages_to_json(
.and_then(|k| k.as_str())
.and_then(|specifier| NpmPackageNvReference::from_str(specifier).ok())
.and_then(|package_ref| {
snapshot
npm_snapshot
.resolve_package_from_deno_module(package_ref.nv())
.ok()
});
@ -295,7 +305,8 @@ fn add_npm_packages_to_json(
if let Some(specifier) = dep.get("specifier").and_then(|s| s.as_str())
{
if let Ok(npm_ref) = NpmPackageReqReference::from_str(specifier) {
if let Ok(pkg) = snapshot.resolve_pkg_from_pkg_req(npm_ref.req())
if let Ok(pkg) =
npm_snapshot.resolve_pkg_from_pkg_req(npm_ref.req())
{
dep.insert(
"npmPackage".to_string(),
@ -321,8 +332,9 @@ fn add_npm_packages_to_json(
}
}
let mut sorted_packages =
snapshot.all_packages_for_every_system().collect::<Vec<_>>();
let mut sorted_packages = npm_snapshot
.all_packages_for_every_system()
.collect::<Vec<_>>();
sorted_packages.sort_by(|a, b| a.id.cmp(&b.id));
let mut json_packages = serde_json::Map::with_capacity(sorted_packages.len());
for pkg in sorted_packages {
@ -356,7 +368,7 @@ struct NpmInfo {
impl NpmInfo {
pub fn build<'a>(
graph: &'a ModuleGraph,
npm_resolver: &'a ManagedCliNpmResolver,
npm_resolver: &'a CliManagedNpmResolver,
npm_snapshot: &'a NpmResolutionSnapshot,
) -> Self {
let mut info = NpmInfo::default();
@ -382,7 +394,7 @@ impl NpmInfo {
fn fill_package_info<'a>(
&mut self,
package: &NpmResolutionPackage,
npm_resolver: &'a ManagedCliNpmResolver,
npm_resolver: &'a CliManagedNpmResolver,
npm_snapshot: &'a NpmResolutionSnapshot,
) {
self.packages.insert(package.id.clone(), package.clone());
@ -419,13 +431,15 @@ struct GraphDisplayContext<'a> {
impl<'a> GraphDisplayContext<'a> {
pub fn write<TWrite: Write>(
graph: &'a ModuleGraph,
npm_resolver: &'a dyn CliNpmResolver,
managed_npm_info: Option<(
&'a CliManagedNpmResolver,
&'a NpmResolutionSnapshot,
)>,
writer: &mut TWrite,
) -> Result<(), AnyError> {
let npm_info = match npm_resolver.as_managed() {
Some(npm_resolver) => {
let npm_snapshot = npm_resolver.snapshot();
NpmInfo::build(graph, npm_resolver, &npm_snapshot)
let npm_info = match managed_npm_info {
Some((npm_resolver, npm_snapshot)) => {
NpmInfo::build(graph, npm_resolver, npm_snapshot)
}
None => NpmInfo::default(),
};

View file

@ -14,9 +14,14 @@ pub enum PropFlags {
Ref,
RefArr,
String,
Number,
Bool,
Null,
Undefined,
Object,
Regex,
BigInt,
Array,
}
impl From<PropFlags> for u8 {
@ -33,21 +38,29 @@ impl TryFrom<u8> for PropFlags {
0 => Ok(PropFlags::Ref),
1 => Ok(PropFlags::RefArr),
2 => Ok(PropFlags::String),
3 => Ok(PropFlags::Bool),
4 => Ok(PropFlags::Null),
5 => Ok(PropFlags::Undefined),
3 => Ok(PropFlags::Number),
4 => Ok(PropFlags::Bool),
5 => Ok(PropFlags::Null),
6 => Ok(PropFlags::Undefined),
7 => Ok(PropFlags::Object),
8 => Ok(PropFlags::Regex),
9 => Ok(PropFlags::BigInt),
10 => Ok(PropFlags::Array),
_ => Err("Unknown Prop flag"),
}
}
}
pub type Index = u32;
const GROUP_KIND: u8 = 1;
const MASK_U32_1: u32 = 0b11111111_00000000_00000000_00000000;
const MASK_U32_2: u32 = 0b00000000_11111111_00000000_00000000;
const MASK_U32_3: u32 = 0b00000000_00000000_11111111_00000000;
const MASK_U32_4: u32 = 0b00000000_00000000_00000000_11111111;
// TODO: There is probably a native Rust function to do this.
pub fn append_u32(result: &mut Vec<u8>, value: u32) {
#[inline]
fn append_u32(result: &mut Vec<u8>, value: u32) {
let v1: u8 = ((value & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((value & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((value & MASK_U32_3) >> 8) as u8;
@ -59,25 +72,11 @@ pub fn append_u32(result: &mut Vec<u8>, value: u32) {
result.push(v4);
}
pub fn append_usize(result: &mut Vec<u8>, value: usize) {
fn append_usize(result: &mut Vec<u8>, value: usize) {
let raw = u32::try_from(value).unwrap();
append_u32(result, raw);
}
pub fn write_usize(result: &mut [u8], value: usize, idx: usize) {
let raw = u32::try_from(value).unwrap();
let v1: u8 = ((raw & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((raw & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((raw & MASK_U32_3) >> 8) as u8;
let v4: u8 = (raw & MASK_U32_4) as u8;
result[idx] = v1;
result[idx + 1] = v2;
result[idx + 2] = v3;
result[idx + 3] = v4;
}
#[derive(Debug)]
pub struct StringTable {
id: usize,
@ -119,71 +118,47 @@ impl StringTable {
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NodeRef(pub usize);
/// Represents an offset to a node whose schema hasn't been committed yet
pub struct NodeRef(pub Index);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PendingNodeRef(pub NodeRef);
pub struct PendingRef(pub Index);
#[derive(Debug)]
pub struct BoolPos(pub usize);
#[derive(Debug)]
pub struct FieldPos(pub usize);
#[derive(Debug)]
pub struct FieldArrPos(pub usize);
#[derive(Debug)]
pub struct StrPos(pub usize);
#[derive(Debug)]
pub struct UndefPos(pub usize);
#[derive(Debug)]
pub struct NullPos(pub usize);
#[derive(Debug)]
pub enum NodePos {
Bool(BoolPos),
#[allow(dead_code)]
Field(FieldPos),
#[allow(dead_code)]
FieldArr(FieldArrPos),
Str(StrPos),
Undef(UndefPos),
#[allow(dead_code)]
Null(NullPos),
pub trait AstBufSerializer {
fn serialize(&mut self) -> Vec<u8>;
}
pub trait AstBufSerializer<K, P>
where
K: Into<u8> + Display,
P: Into<u8> + Display,
{
fn header(&mut self, kind: K, parent: NodeRef, span: &Span)
-> PendingNodeRef;
fn ref_field(&mut self, prop: P) -> FieldPos;
fn ref_vec_field(&mut self, prop: P, len: usize) -> FieldArrPos;
fn str_field(&mut self, prop: P) -> StrPos;
fn bool_field(&mut self, prop: P) -> BoolPos;
fn undefined_field(&mut self, prop: P) -> UndefPos;
#[allow(dead_code)]
fn null_field(&mut self, prop: P) -> NullPos;
fn commit_schema(&mut self, offset: PendingNodeRef) -> NodeRef;
fn write_ref(&mut self, pos: FieldPos, value: NodeRef);
fn write_maybe_ref(&mut self, pos: FieldPos, value: Option<NodeRef>);
fn write_refs(&mut self, pos: FieldArrPos, value: Vec<NodeRef>);
fn write_str(&mut self, pos: StrPos, value: &str);
fn write_bool(&mut self, pos: BoolPos, value: bool);
fn serialize(&mut self) -> Vec<u8>;
/// <type u8>
/// <prop offset u32>
/// <child idx u32>
/// <next idx u32>
/// <parent idx u32>
#[derive(Debug)]
struct Node {
kind: u8,
prop_offset: u32,
child: u32,
next: u32,
parent: u32,
}
#[derive(Debug)]
pub struct SerializeCtx {
buf: Vec<u8>,
start_buf: NodeRef,
root_idx: Index,
nodes: Vec<Node>,
prop_stack: Vec<Vec<u8>>,
field_count: Vec<usize>,
field_buf: Vec<u8>,
prev_sibling_stack: Vec<Index>,
/// Vec of spans
spans: Vec<u32>,
/// Maps string id to the actual string
str_table: StringTable,
kind_map: Vec<usize>,
prop_map: Vec<usize>,
field_count: u8,
/// Maps kind id to string id
kind_name_map: Vec<usize>,
/// Maps prop id to string id
prop_name_map: Vec<usize>,
}
/// This is the internal context used to allocate and fill the buffer. The point
@ -198,20 +173,24 @@ impl SerializeCtx {
let kind_size = kind_len as usize;
let prop_size = prop_len as usize;
let mut ctx = Self {
start_buf: NodeRef(0),
buf: vec![],
spans: Vec::with_capacity(512),
root_idx: 0,
nodes: Vec::with_capacity(512),
prop_stack: vec![vec![]],
prev_sibling_stack: vec![0],
field_count: vec![0],
field_buf: Vec::with_capacity(1024),
str_table: StringTable::new(),
kind_map: vec![0; kind_size],
prop_map: vec![0; prop_size],
field_count: 0,
kind_name_map: vec![0; kind_size],
prop_name_map: vec![0; prop_size],
};
let empty_str = ctx.str_table.insert("");
// Placeholder node is always 0
ctx.append_node(0, NodeRef(0), &DUMMY_SP, 0);
ctx.kind_map[0] = empty_str;
ctx.start_buf = NodeRef(ctx.buf.len());
ctx.append_node(0, &DUMMY_SP);
ctx.kind_name_map[0] = empty_str;
ctx.kind_name_map[1] = empty_str;
// Insert default props that are always present
let type_str = ctx.str_table.insert("type");
@ -220,258 +199,306 @@ impl SerializeCtx {
let length_str = ctx.str_table.insert("length");
// These values are expected to be in this order on the JS side
ctx.prop_map[0] = empty_str;
ctx.prop_map[1] = type_str;
ctx.prop_map[2] = parent_str;
ctx.prop_map[3] = range_str;
ctx.prop_map[4] = length_str;
ctx.prop_name_map[0] = empty_str;
ctx.prop_name_map[1] = type_str;
ctx.prop_name_map[2] = parent_str;
ctx.prop_name_map[3] = range_str;
ctx.prop_name_map[4] = length_str;
ctx
}
pub fn set_root_idx(&mut self, idx: Index) {
self.root_idx = idx;
}
/// Allocate a node's header
fn field_header<P>(&mut self, prop: P, prop_flags: PropFlags) -> usize
fn field_header<P>(&mut self, prop: P, prop_flags: PropFlags)
where
P: Into<u8> + Display + Clone,
{
self.field_count += 1;
let offset = self.buf.len();
let flags: u8 = prop_flags.into();
let n: u8 = prop.clone().into();
self.buf.push(n);
if let Some(v) = self.prop_map.get::<usize>(n.into()) {
if let Some(v) = self.prop_name_map.get::<usize>(n.into()) {
if *v == 0 {
let id = self.str_table.insert(&format!("{prop}"));
self.prop_map[n as usize] = id;
self.prop_name_map[n as usize] = id;
}
}
let flags: u8 = prop_flags.into();
self.buf.push(flags);
// Increment field counter
let idx = self.field_count.len() - 1;
let count = self.field_count[idx];
self.field_count[idx] = count + 1;
offset
let buf = self.prop_stack.last_mut().unwrap();
buf.push(n);
buf.push(flags);
}
/// Allocate a property pointing to another node.
fn field<P>(&mut self, prop: P, prop_flags: PropFlags) -> usize
fn get_node(&mut self, id: Index) -> &mut Node {
self.nodes.get_mut(id as usize).unwrap()
}
fn set_parent(&mut self, child_id: Index, parent_id: Index) {
let child = self.get_node(child_id);
child.parent = parent_id;
}
fn set_child(&mut self, parent_id: Index, child_id: Index) {
let parent = self.get_node(parent_id);
parent.child = child_id;
}
fn set_next(&mut self, node_id: Index, next_id: Index) {
let node = self.get_node(node_id);
node.next = next_id;
}
fn update_ref_links(&mut self, parent_id: Index, child_id: Index) {
let last_idx = self.prev_sibling_stack.len() - 1;
let parent = self.get_node(parent_id);
if parent.child == 0 {
parent.child = child_id;
} else {
let prev_id = self.prev_sibling_stack[last_idx];
self.set_next(prev_id, child_id);
}
self.prev_sibling_stack[last_idx] = child_id;
self.set_parent(child_id, parent_id);
}
pub fn append_node<K>(&mut self, kind: K, span: &Span) -> PendingRef
where
P: Into<u8> + Display + Clone,
K: Into<u8> + Display + Clone,
{
let offset = self.field_header(prop, prop_flags);
append_usize(&mut self.buf, 0);
offset
self.append_inner(kind, span.lo.0, span.hi.0)
}
fn append_node(
pub fn append_inner<K>(
&mut self,
kind: u8,
parent: NodeRef,
span: &Span,
prop_count: usize,
) -> PendingNodeRef {
let offset = self.buf.len();
// Node type fits in a u8
self.buf.push(kind);
// Offset to the parent node. Will be 0 if none exists
append_usize(&mut self.buf, parent.0);
// Span, the start and end location of this node
append_u32(&mut self.buf, span.lo.0);
append_u32(&mut self.buf, span.hi.0);
// No node has more than <10 properties
debug_assert!(prop_count < 10);
self.buf.push(prop_count as u8);
PendingNodeRef(NodeRef(offset))
}
pub fn commit_schema(&mut self, node_ref: PendingNodeRef) -> NodeRef {
let mut offset = node_ref.0 .0;
// type + parentId + span lo + span hi
offset += 1 + 4 + 4 + 4;
self.buf[offset] = self.field_count;
self.field_count = 0;
node_ref.0
}
/// Allocate the node header. It's always the same for every node.
/// <type u8>
/// <parent offset u32>
/// <span lo u32>
/// <span high u32>
/// <property count u8> (There is no node with more than 10 properties)
pub fn header<N>(
&mut self,
kind: N,
parent: NodeRef,
span: &Span,
) -> PendingNodeRef
kind: K,
span_lo: u32,
span_hi: u32,
) -> PendingRef
where
N: Into<u8> + Display + Clone,
K: Into<u8> + Display + Clone,
{
let n: u8 = kind.clone().into();
let kind_u8: u8 = kind.clone().into();
if let Some(v) = self.kind_map.get::<usize>(n.into()) {
let id: Index = self.nodes.len() as u32;
self.nodes.push(Node {
kind: kind_u8,
prop_offset: 0,
child: 0,
next: 0,
parent: 0,
});
if let Some(v) = self.kind_name_map.get::<usize>(kind_u8.into()) {
if *v == 0 {
let id = self.str_table.insert(&format!("{kind}"));
self.kind_map[n as usize] = id;
let s_id = self.str_table.insert(&format!("{kind}"));
self.kind_name_map[kind_u8 as usize] = s_id;
}
}
// Prop count will be filled with the actual value when the
// schema is committed.
self.append_node(n, parent, span, 0)
self.field_count.push(0);
self.prop_stack.push(vec![]);
self.prev_sibling_stack.push(0);
// write spans
self.spans.push(span_lo);
self.spans.push(span_hi);
PendingRef(id)
}
/// Allocate a reference property that will hold the offset of
/// another node.
pub fn ref_field<P>(&mut self, prop: P) -> usize
pub fn commit_node(&mut self, id: PendingRef) -> NodeRef {
let mut buf = self.prop_stack.pop().unwrap();
let count = self.field_count.pop().unwrap();
let offset = self.field_buf.len();
// All nodes have <10 fields
self.field_buf.push(count as u8);
self.field_buf.append(&mut buf);
let node = self.nodes.get_mut(id.0 as usize).unwrap();
node.prop_offset = offset as u32;
self.prev_sibling_stack.pop();
NodeRef(id.0)
}
// Allocate an object field
pub fn open_obj(&mut self) {
self.field_count.push(0);
self.prop_stack.push(vec![]);
}
pub fn commit_obj<P>(&mut self, prop: P)
where
P: Into<u8> + Display + Clone,
{
self.field(prop, PropFlags::Ref)
let mut buf = self.prop_stack.pop().unwrap();
let count = self.field_count.pop().unwrap();
let offset = self.field_buf.len();
append_usize(&mut self.field_buf, count);
self.field_buf.append(&mut buf);
self.field_header(prop, PropFlags::Object);
let buf = self.prop_stack.last_mut().unwrap();
append_usize(buf, offset);
}
/// Allocate a property that is a vec of node offsets pointing to other
/// nodes.
pub fn ref_vec_field<P>(&mut self, prop: P, len: usize) -> usize
/// Allocate an null field
pub fn write_null<P>(&mut self, prop: P)
where
P: Into<u8> + Display + Clone,
{
let offset = self.field(prop, PropFlags::RefArr);
self.field_header(prop, PropFlags::Null);
for _ in 0..len {
append_u32(&mut self.buf, 0);
}
offset
let buf = self.prop_stack.last_mut().unwrap();
append_u32(buf, 0);
}
// Allocate a property representing a string. Strings are deduplicated
// in the message and the property will only contain the string id.
pub fn str_field<P>(&mut self, prop: P) -> usize
/// Allocate an null field
pub fn write_undefined<P>(&mut self, prop: P)
where
P: Into<u8> + Display + Clone,
{
self.field(prop, PropFlags::String)
self.field_header(prop, PropFlags::Undefined);
let buf = self.prop_stack.last_mut().unwrap();
append_u32(buf, 0);
}
/// Allocate a bool field
pub fn bool_field<P>(&mut self, prop: P) -> usize
/// Allocate a number field
pub fn write_num<P>(&mut self, prop: P, value: &str)
where
P: Into<u8> + Display + Clone,
{
let offset = self.field_header(prop, PropFlags::Bool);
self.buf.push(0);
offset
self.field_header(prop, PropFlags::Number);
let id = self.str_table.insert(value);
let buf = self.prop_stack.last_mut().unwrap();
append_usize(buf, id);
}
/// Allocate an undefined field
pub fn undefined_field<P>(&mut self, prop: P) -> usize
/// Allocate a bigint field
pub fn write_bigint<P>(&mut self, prop: P, value: &str)
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::Undefined)
self.field_header(prop, PropFlags::BigInt);
let id = self.str_table.insert(value);
let buf = self.prop_stack.last_mut().unwrap();
append_usize(buf, id);
}
/// Allocate an undefined field
#[allow(dead_code)]
pub fn null_field<P>(&mut self, prop: P) -> usize
/// Allocate a RegExp field
pub fn write_regex<P>(&mut self, prop: P, value: &str)
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::Null)
}
self.field_header(prop, PropFlags::Regex);
/// Replace the placeholder of a reference field with the actual offset
/// to the node we want to point to.
pub fn write_ref(&mut self, field_offset: usize, value: NodeRef) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref {
panic!("Trying to write a ref into a non-ref field")
}
}
write_usize(&mut self.buf, value.0, field_offset + 2);
}
/// Helper for writing optional node offsets
pub fn write_maybe_ref(
&mut self,
field_offset: usize,
value: Option<NodeRef>,
) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Ref {
panic!("Trying to write a ref into a non-ref field")
}
}
let ref_value = if let Some(v) = value { v } else { NodeRef(0) };
write_usize(&mut self.buf, ref_value.0, field_offset + 2);
}
/// Write a vec of node offsets into the property. The necessary space
/// has been reserved earlier.
pub fn write_refs(&mut self, field_offset: usize, value: Vec<NodeRef>) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::RefArr {
panic!("Trying to write a ref into a non-ref array field")
}
}
let mut offset = field_offset + 2;
write_usize(&mut self.buf, value.len(), offset);
offset += 4;
for item in value {
write_usize(&mut self.buf, item.0, offset);
offset += 4;
}
let id = self.str_table.insert(value);
let buf = self.prop_stack.last_mut().unwrap();
append_usize(buf, id);
}
/// Store the string in our string table and save the id of the string
/// in the current field.
pub fn write_str(&mut self, field_offset: usize, value: &str) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::String {
panic!("Trying to write a ref into a non-string field")
}
}
pub fn write_str<P>(&mut self, prop: P, value: &str)
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::String);
let id = self.str_table.insert(value);
write_usize(&mut self.buf, id, field_offset + 2);
let buf = self.prop_stack.last_mut().unwrap();
append_usize(buf, id);
}
/// Write a bool to a field.
pub fn write_bool(&mut self, field_offset: usize, value: bool) {
#[cfg(debug_assertions)]
{
let value_kind = self.buf[field_offset + 1];
if PropFlags::try_from(value_kind).unwrap() != PropFlags::Bool {
panic!("Trying to write a ref into a non-bool field")
}
}
pub fn write_bool<P>(&mut self, prop: P, value: bool)
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::Bool);
self.buf[field_offset + 2] = if value { 1 } else { 0 };
let n = if value { 1 } else { 0 };
let buf = self.prop_stack.last_mut().unwrap();
append_u32(buf, n);
}
/// Replace the placeholder of a reference field with the actual offset
/// to the node we want to point to.
pub fn write_ref<P>(&mut self, prop: P, parent: &PendingRef, value: NodeRef)
where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::Ref);
let buf = self.prop_stack.last_mut().unwrap();
append_u32(buf, value.0);
if parent.0 > 0 {
self.update_ref_links(parent.0, value.0);
}
}
/// Helper for writing optional node offsets
pub fn write_maybe_ref<P>(
&mut self,
prop: P,
parent: &PendingRef,
value: Option<NodeRef>,
) where
P: Into<u8> + Display + Clone,
{
if let Some(v) = value {
self.write_ref(prop, parent, v);
} else {
self.write_null(prop);
};
}
/// Write a vec of node offsets into the property. The necessary space
/// has been reserved earlier.
pub fn write_ref_vec<P>(
&mut self,
prop: P,
parent_ref: &PendingRef,
value: Vec<NodeRef>,
) where
P: Into<u8> + Display + Clone,
{
self.field_header(prop, PropFlags::RefArr);
let group_id = self.append_node(GROUP_KIND, &DUMMY_SP);
let group_id = self.commit_node(group_id).0;
let buf = self.prop_stack.last_mut().unwrap();
append_u32(buf, group_id);
self.update_ref_links(parent_ref.0, group_id);
let mut prev_id = 0;
for (i, item) in value.iter().enumerate() {
self.set_parent(item.0, group_id);
if i == 0 {
self.set_child(group_id, item.0);
} else {
self.set_next(prev_id, item.0);
}
prev_id = item.0;
}
}
/// Serialize all information we have into a buffer that can be sent to JS.
@ -481,6 +508,8 @@ impl SerializeCtx {
/// <string table>
/// <node kind map> <- node kind id maps to string id
/// <node prop map> <- node property id maps to string id
/// <spans> <- List of spans, rarely needed
/// <offset spans>
/// <offset kind map>
/// <offset prop map>
/// <offset str table>
@ -490,7 +519,13 @@ impl SerializeCtx {
// The buffer starts with the serialized AST first, because that
// contains absolute offsets. By butting this at the start of the
// message we don't have to waste time updating any offsets.
buf.append(&mut self.buf);
for node in &self.nodes {
buf.push(node.kind);
append_u32(&mut buf, node.prop_offset);
append_u32(&mut buf, node.child);
append_u32(&mut buf, node.next);
append_u32(&mut buf, node.parent);
}
// Next follows the string table. We'll keep track of the offset
// in the message of where the string table begins
@ -507,8 +542,8 @@ impl SerializeCtx {
// Write the total number of entries in the kind -> str mapping table
// TODO: make this a u8
append_usize(&mut buf, self.kind_map.len());
for v in &self.kind_map {
append_usize(&mut buf, self.kind_name_map.len());
for v in &self.kind_name_map {
append_usize(&mut buf, *v);
}
@ -517,19 +552,35 @@ impl SerializeCtx {
// as u8.
let offset_prop_map = buf.len();
// Write the total number of entries in the kind -> str mapping table
append_usize(&mut buf, self.prop_map.len());
for v in &self.prop_map {
append_usize(&mut buf, self.prop_name_map.len());
for v in &self.prop_name_map {
append_usize(&mut buf, *v);
}
// Spans are rarely needed, so they're stored in a separate array.
// They're indexed by the node id.
let offset_spans = buf.len();
for v in &self.spans {
append_u32(&mut buf, *v);
}
// The field value table. They're detached from nodes as they're not
// as frequently needed as the nodes themselves. The most common
// operation is traversal and we can traverse nodes without knowing
// about the fields.
let offset_props = buf.len();
buf.append(&mut self.field_buf);
// Putting offsets of relevant parts of the buffer at the end. This
// allows us to hop to the relevant part by merely looking at the last
// for values in the message. Each value represents an offset into the
// buffer.
append_usize(&mut buf, offset_props);
append_usize(&mut buf, offset_spans);
append_usize(&mut buf, offset_kind_map);
append_usize(&mut buf, offset_prop_map);
append_usize(&mut buf, offset_str_table);
append_usize(&mut buf, self.start_buf.0);
append_u32(&mut buf, self.root_idx);
buf
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -451,7 +451,7 @@ pub struct DepManager {
// TODO(nathanwhit): probably shouldn't be pub
pub(crate) jsr_fetch_resolver: Arc<JsrFetchResolver>,
pub(crate) npm_fetch_resolver: Arc<NpmFetchResolver>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
npm_installer: Arc<NpmInstaller>,
permissions_container: PermissionsContainer,
main_module_graph_container: Arc<MainModuleGraphContainer>,
@ -463,7 +463,7 @@ pub struct DepManagerArgs {
pub jsr_fetch_resolver: Arc<JsrFetchResolver>,
pub npm_fetch_resolver: Arc<NpmFetchResolver>,
pub npm_installer: Arc<NpmInstaller>,
pub npm_resolver: Arc<dyn CliNpmResolver>,
pub npm_resolver: CliNpmResolver,
pub permissions_container: PermissionsContainer,
pub main_module_graph_container: Arc<MainModuleGraphContainer>,
pub lockfile: Option<Arc<CliLockfile>>,
@ -551,9 +551,10 @@ impl DepManager {
let npm_resolver = self.npm_resolver.as_managed().unwrap();
if self.deps.iter().all(|dep| match dep.kind {
DepKind::Npm => {
npm_resolver.resolve_pkg_id_from_pkg_req(&dep.req).is_ok()
}
DepKind::Npm => npm_resolver
.resolution()
.resolve_pkg_id_from_pkg_req(&dep.req)
.is_ok(),
DepKind::Jsr => graph.packages.mappings().contains_key(&dep.req),
}) {
self.dependencies_resolved.raise();
@ -630,7 +631,12 @@ impl DepManager {
let graph = self.main_module_graph_container.graph();
let mut resolved = Vec::with_capacity(self.deps.len());
let snapshot = self.npm_resolver.as_managed().unwrap().snapshot();
let snapshot = self
.npm_resolver
.as_managed()
.unwrap()
.resolution()
.snapshot();
let resolved_npm = snapshot.package_reqs();
let resolved_jsr = graph.packages.mappings();
for dep in &self.deps {

View file

@ -220,7 +220,7 @@ pub async fn execute_script(
let task_runner = TaskRunner {
task_flags: &task_flags,
npm_installer: npm_installer.map(|n| n.as_ref()),
npm_resolver: npm_resolver.as_ref(),
npm_resolver,
node_resolver: node_resolver.as_ref(),
env_vars,
cli_options,
@ -271,7 +271,7 @@ struct RunSingleOptions<'a> {
struct TaskRunner<'a> {
task_flags: &'a TaskFlags,
npm_installer: Option<&'a NpmInstaller>,
npm_resolver: &'a dyn CliNpmResolver,
npm_resolver: &'a CliNpmResolver,
node_resolver: &'a CliNodeResolver,
env_vars: HashMap<String, String>,
cli_options: &'a CliOptions,

View file

@ -46,7 +46,7 @@ use crate::cache::FastInsecureHasher;
use crate::cache::ModuleInfoCache;
use crate::node::CliNodeResolver;
use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker;
use crate::resolver::CliCjsTracker;
use crate::sys::CliSys;
use crate::util::checksum;
use crate::util::path::mapped_specifier_for_tsc;
@ -300,13 +300,13 @@ pub fn into_specifier_and_media_type(
#[derive(Debug)]
pub struct TypeCheckingCjsTracker {
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
module_info_cache: Arc<ModuleInfoCache>,
}
impl TypeCheckingCjsTracker {
pub fn new(
cjs_tracker: Arc<CjsTracker>,
cjs_tracker: Arc<CliCjsTracker>,
module_info_cache: Arc<ModuleInfoCache>,
) -> Self {
Self {
@ -358,7 +358,7 @@ impl TypeCheckingCjsTracker {
pub struct RequestNpmState {
pub cjs_tracker: Arc<TypeCheckingCjsTracker>,
pub node_resolver: Arc<CliNodeResolver>,
pub npm_resolver: Arc<dyn CliNpmResolver>,
pub npm_resolver: CliNpmResolver,
}
/// A structure representing a request to be sent to the tsc runtime.

View file

@ -19,6 +19,7 @@ use deno_core::ModuleLoader;
use deno_core::PollEventLoopOptions;
use deno_core::SharedArrayBufferStore;
use deno_error::JsErrorBox;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_runtime::code_cache;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_fs;
@ -151,7 +152,7 @@ struct SharedWorkerState {
module_loader_factory: Box<dyn ModuleLoaderFactory>,
node_resolver: Arc<CliNodeResolver>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
pkg_json_resolver: Arc<CliPackageJsonResolver>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
root_permissions: PermissionsContainer,
@ -168,18 +169,17 @@ impl SharedWorkerState {
pub fn create_node_init_services(
&self,
node_require_loader: NodeRequireLoaderRc,
) -> NodeExtInitServices<CliSys> {
) -> NodeExtInitServices<DenoInNpmPackageChecker, CliNpmResolver, CliSys> {
NodeExtInitServices {
node_require_loader,
node_resolver: self.node_resolver.clone(),
npm_resolver: self.npm_resolver.clone().into_npm_pkg_folder_resolver(),
pkg_json_resolver: self.pkg_json_resolver.clone(),
sys: self.sys.clone(),
}
}
pub fn npm_process_state_provider(&self) -> NpmProcessStateProviderRc {
self.npm_resolver.clone().into_process_state_provider()
crate::npm::create_npm_process_state_provider(&self.npm_resolver)
}
}
@ -427,7 +427,7 @@ impl CliMainWorkerFactory {
module_loader_factory: Box<dyn ModuleLoaderFactory>,
node_resolver: Arc<CliNodeResolver>,
npm_installer: Option<Arc<NpmInstaller>>,
npm_resolver: Arc<dyn CliNpmResolver>,
npm_resolver: CliNpmResolver,
pkg_json_resolver: Arc<CliPackageJsonResolver>,
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
root_permissions: PermissionsContainer,
@ -855,7 +855,7 @@ fn create_web_worker_callback(
/// Instead probe for the total memory on the system and use it instead
/// as a default.
pub fn create_isolate_create_params() -> Option<v8::CreateParams> {
let maybe_mem_info = deno_runtime::sys_info::mem_info();
let maybe_mem_info = deno_runtime::deno_os::sys_info::mem_info();
maybe_mem_info.map(|mem_info| {
v8::CreateParams::default()
.heap_limits_from_system_memory(mem_info.total, 0)
@ -886,7 +886,11 @@ mod tests {
..Default::default()
};
MainWorker::bootstrap_from_options::<CliSys>(
MainWorker::bootstrap_from_options::<
DenoInNpmPackageChecker,
CliNpmResolver,
CliSys,
>(
main_module,
WorkerServiceOptions {
module_loader: Rc::new(FsModuleLoader),

View file

@ -15,8 +15,9 @@ use deno_core::v8;
use deno_core::v8::ExternalReference;
use deno_error::JsErrorBox;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker;
use node_resolver::IsBuiltInNodeModuleChecker;
use node_resolver::NpmPackageFolderResolverRc;
use node_resolver::NpmPackageFolderResolver;
use node_resolver::PackageJsonResolverRc;
use once_cell::sync::Lazy;
@ -185,17 +186,21 @@ fn op_node_build_os() -> String {
}
#[derive(Clone)]
pub struct NodeExtInitServices<TSys: ExtNodeSys> {
pub struct NodeExtInitServices<
TInNpmPackageChecker: InNpmPackageChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: ExtNodeSys,
> {
pub node_require_loader: NodeRequireLoaderRc,
pub node_resolver: NodeResolverRc<TSys>,
pub npm_resolver: NpmPackageFolderResolverRc,
pub node_resolver:
NodeResolverRc<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
pub pkg_json_resolver: PackageJsonResolverRc<TSys>,
pub sys: TSys,
}
deno_core::extension!(deno_node,
deps = [ deno_io, deno_fs ],
parameters = [P: NodePermissions, TSys: ExtNodeSys],
parameters = [P: NodePermissions, TInNpmPackageChecker: InNpmPackageChecker, TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: ExtNodeSys],
ops = [
ops::blocklist::op_socket_address_parse,
ops::blocklist::op_socket_address_get_serialization,
@ -395,13 +400,13 @@ deno_core::extension!(deno_node,
ops::require::op_require_init_paths,
ops::require::op_require_node_module_paths<P, TSys>,
ops::require::op_require_proxy_path,
ops::require::op_require_is_deno_dir_package<TSys>,
ops::require::op_require_resolve_deno_dir,
ops::require::op_require_is_deno_dir_package<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
ops::require::op_require_resolve_deno_dir<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
ops::require::op_require_is_maybe_cjs,
ops::require::op_require_is_request_relative,
ops::require::op_require_resolve_lookup_paths,
ops::require::op_require_try_self_parent_path<P, TSys>,
ops::require::op_require_try_self<P, TSys>,
ops::require::op_require_try_self<P, TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
ops::require::op_require_real_path<P, TSys>,
ops::require::op_require_path_is_absolute,
ops::require::op_require_path_dirname,
@ -410,9 +415,9 @@ deno_core::extension!(deno_node,
ops::require::op_require_path_basename,
ops::require::op_require_read_file<P>,
ops::require::op_require_as_file_path,
ops::require::op_require_resolve_exports<P, TSys>,
ops::require::op_require_resolve_exports<P, TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
ops::require::op_require_read_package_scope<P, TSys>,
ops::require::op_require_package_imports_resolve<P, TSys>,
ops::require::op_require_package_imports_resolve<P, TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
ops::require::op_require_break_on_next_statement,
ops::util::op_node_guess_handle_type,
ops::worker_threads::op_worker_threads_filename<P, TSys>,
@ -487,7 +492,7 @@ deno_core::extension!(deno_node,
"_fs/_fs_watch.ts",
"_fs/_fs_write.mjs",
"_fs/_fs_writeFile.ts",
"_fs/_fs_writev.mjs",
"_fs/_fs_writev.ts",
"_next_tick.ts",
"_process/exiting.ts",
"_process/process.ts",
@ -681,7 +686,7 @@ deno_core::extension!(deno_node,
"node:zlib" = "zlib.ts",
],
options = {
maybe_init: Option<NodeExtInitServices<TSys>>,
maybe_init: Option<NodeExtInitServices<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>>,
fs: deno_fs::FileSystemRc,
},
state = |state, options| {
@ -691,7 +696,6 @@ deno_core::extension!(deno_node,
state.put(init.sys.clone());
state.put(init.node_require_loader.clone());
state.put(init.node_resolver.clone());
state.put(init.npm_resolver.clone());
state.put(init.pkg_json_resolver.clone());
}
},
@ -833,10 +837,18 @@ pub trait ExtNodeSys:
impl ExtNodeSys for sys_traits::impls::RealSys {}
pub type NodeResolver<TSys> =
node_resolver::NodeResolver<RealIsBuiltInNodeModuleChecker, TSys>;
pub type NodeResolver<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys> =
node_resolver::NodeResolver<
TInNpmPackageChecker,
RealIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>;
#[allow(clippy::disallowed_types)]
pub type NodeResolverRc<TSys> = deno_fs::sync::MaybeArc<NodeResolver<TSys>>;
pub type NodeResolverRc<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys> =
deno_fs::sync::MaybeArc<
NodeResolver<TInNpmPackageChecker, TNpmPackageFolderResolver, TSys>,
>;
#[allow(clippy::disallowed_types)]
pub fn create_host_defined_options<'s>(

View file

@ -19,7 +19,9 @@ use deno_path_util::normalize_path;
use deno_path_util::url_from_file_path;
use deno_path_util::url_to_file_path;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionKind;
use node_resolver::NpmPackageFolderResolver;
use node_resolver::ResolutionMode;
use node_resolver::REQUIRE_CONDITIONS;
use sys_traits::FsCanonicalize;
@ -30,7 +32,6 @@ use crate::ExtNodeSys;
use crate::NodePermissions;
use crate::NodeRequireLoaderRc;
use crate::NodeResolverRc;
use crate::NpmPackageFolderResolverRc;
use crate::PackageJsonResolverRc;
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
@ -256,12 +257,20 @@ pub fn op_require_is_request_relative(#[string] request: String) -> bool {
#[op2]
#[string]
pub fn op_require_resolve_deno_dir(
pub fn op_require_resolve_deno_dir<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TSys: ExtNodeSys + 'static,
>(
state: &mut OpState,
#[string] request: String,
#[string] parent_filename: String,
) -> Result<Option<String>, deno_path_util::PathToUrlError> {
let resolver = state.borrow::<NpmPackageFolderResolverRc>();
let resolver = state.borrow::<NodeResolverRc<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TSys,
>>();
Ok(
resolver
@ -275,11 +284,19 @@ pub fn op_require_resolve_deno_dir(
}
#[op2(fast)]
pub fn op_require_is_deno_dir_package<TSys: ExtNodeSys + 'static>(
pub fn op_require_is_deno_dir_package<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TSys: ExtNodeSys + 'static,
>(
state: &mut OpState,
#[string] path: String,
) -> bool {
let resolver = state.borrow::<NodeResolverRc<TSys>>();
let resolver = state.borrow::<NodeResolverRc<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TSys,
>>();
match deno_path_util::url_from_file_path(&PathBuf::from(path)) {
Ok(specifier) => resolver.in_npm_package(&specifier),
Err(_) => false,
@ -451,6 +468,8 @@ pub fn op_require_try_self_parent_path<
#[string]
pub fn op_require_try_self<
P: NodePermissions + 'static,
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TSys: ExtNodeSys + 'static,
>(
state: &mut OpState,
@ -493,7 +512,11 @@ pub fn op_require_try_self<
let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap();
if let Some(exports) = &pkg.exports {
let node_resolver = state.borrow::<NodeResolverRc<TSys>>();
let node_resolver = state.borrow::<NodeResolverRc<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TSys,
>>();
let r = node_resolver.package_exports_resolve(
&pkg.path,
&expansion,
@ -552,6 +575,8 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
#[string]
pub fn op_require_resolve_exports<
P: NodePermissions + 'static,
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TSys: ExtNodeSys + 'static,
>(
state: &mut OpState,
@ -563,7 +588,11 @@ pub fn op_require_resolve_exports<
#[string] parent_path: String,
) -> Result<Option<String>, RequireError> {
let sys = state.borrow::<TSys>();
let node_resolver = state.borrow::<NodeResolverRc<TSys>>();
let node_resolver = state.borrow::<NodeResolverRc<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TSys,
>>();
let pkg_json_resolver = state.borrow::<PackageJsonResolverRc<TSys>>();
let modules_path = PathBuf::from(&modules_path_str);
@ -655,6 +684,8 @@ pub fn op_require_read_package_scope<
#[string]
pub fn op_require_package_imports_resolve<
P: NodePermissions + 'static,
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TSys: ExtNodeSys + 'static,
>(
state: &mut OpState,
@ -672,7 +703,11 @@ pub fn op_require_package_imports_resolve<
};
if pkg.imports.is_some() {
let node_resolver = state.borrow::<NodeResolverRc<TSys>>();
let node_resolver = state.borrow::<NodeResolverRc<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TSys,
>>();
let referrer_url = Url::from_file_path(&referrer_filename).unwrap();
let url = node_resolver.package_imports_resolve(
&request,

View file

@ -1,65 +0,0 @@
// Copyright 2018-2025 the Deno authors. MIT license.
// Forked from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d9df51e34526f48bef4e2546a006157b391ad96c/types/node/fs.d.ts
import { ErrnoException } from "ext:deno_node/_global.d.ts";
/**
* Write an array of `ArrayBufferView`s to the file specified by `fd` using`writev()`.
*
* `position` is the offset from the beginning of the file where this data
* should be written. If `typeof position !== 'number'`, the data will be written
* at the current position.
*
* The callback will be given three arguments: `err`, `bytesWritten`, and`buffers`. `bytesWritten` is how many bytes were written from `buffers`.
*
* If this method is `util.promisify()` ed, it returns a promise for an`Object` with `bytesWritten` and `buffers` properties.
*
* It is unsafe to use `fs.writev()` multiple times on the same file without
* waiting for the callback. For this scenario, use {@link createWriteStream}.
*
* On Linux, positional writes don't work when the file is opened in append mode.
* The kernel ignores the position argument and always appends the data to
* the end of the file.
* @since v12.9.0
*/
export function writev(
fd: number,
buffers: ReadonlyArray<ArrayBufferView>,
cb: (
err: ErrnoException | null,
bytesWritten: number,
buffers: ArrayBufferView[],
) => void,
): void;
export function writev(
fd: number,
buffers: ReadonlyArray<ArrayBufferView>,
position: number | null,
cb: (
err: ErrnoException | null,
bytesWritten: number,
buffers: ArrayBufferView[],
) => void,
): void;
export interface WriteVResult {
bytesWritten: number;
buffers: ArrayBufferView[];
}
export namespace writev {
function __promisify__(
fd: number,
buffers: ReadonlyArray<ArrayBufferView>,
position?: number,
): Promise<WriteVResult>;
}
/**
* For detailed information, see the documentation of the asynchronous version of
* this API: {@link writev}.
* @since v12.9.0
* @return The number of bytes written.
*/
export function writevSync(
fd: number,
buffers: ReadonlyArray<ArrayBufferView>,
position?: number,
): number;

View file

@ -5,15 +5,53 @@
// deno-lint-ignore-file prefer-primordials
import { Buffer } from "node:buffer";
import process from "node:process";
import { ErrnoException } from "ext:deno_node/_global.d.ts";
import { validateBufferArray } from "ext:deno_node/internal/fs/utils.mjs";
import { getValidatedFd } from "ext:deno_node/internal/fs/utils.mjs";
import { WriteVResult } from "ext:deno_node/internal/fs/handle.ts";
import { maybeCallback } from "ext:deno_node/_fs/_fs_common.ts";
import * as io from "ext:deno_io/12_io.js";
import { op_fs_seek_async, op_fs_seek_sync } from "ext:core/ops";
export function writev(fd, buffers, position, callback) {
export interface WriteVResult {
bytesWritten: number;
buffers: ReadonlyArray<ArrayBufferView>;
}
type writeVCallback = (
err: ErrnoException | null,
bytesWritten: number,
buffers: ReadonlyArray<ArrayBufferView>,
) => void;
/**
* Write an array of `ArrayBufferView`s to the file specified by `fd` using`writev()`.
*
* `position` is the offset from the beginning of the file where this data
* should be written. If `typeof position !== 'number'`, the data will be written
* at the current position.
*
* The callback will be given three arguments: `err`, `bytesWritten`, and`buffers`. `bytesWritten` is how many bytes were written from `buffers`.
*
* If this method is `util.promisify()` ed, it returns a promise for an`Object` with `bytesWritten` and `buffers` properties.
*
* It is unsafe to use `fs.writev()` multiple times on the same file without
* waiting for the callback. For this scenario, use {@link createWriteStream}.
*
* On Linux, positional writes don't work when the file is opened in append mode.
* The kernel ignores the position argument and always appends the data to
* the end of the file.
* @since v12.9.0
*/
export function writev(
fd: number,
buffers: ReadonlyArray<ArrayBufferView>,
position?: number | null,
callback?: writeVCallback,
): void {
const innerWritev = async (fd, buffers, position) => {
const chunks = [];
const chunks: Buffer[] = [];
const offset = 0;
for (let i = 0; i < buffers.length; i++) {
if (Buffer.isBuffer(buffers[i])) {
@ -45,16 +83,24 @@ export function writev(fd, buffers, position, callback) {
if (typeof position !== "number") position = null;
innerWritev(fd, buffers, position).then(
(nwritten) => {
callback(null, nwritten, buffers);
},
(nwritten) => callback(null, nwritten, buffers),
(err) => callback(err),
);
}
export function writevSync(fd, buffers, position) {
/**
* For detailed information, see the documentation of the asynchronous version of
* this API: {@link writev}.
* @since v12.9.0
* @return The number of bytes written.
*/
export function writevSync(
fd: number,
buffers: ArrayBufferView[],
position?: number | null,
): number {
const innerWritev = (fd, buffers, position) => {
const chunks = [];
const chunks: Buffer[] = [];
const offset = 0;
for (let i = 0; i < buffers.length; i++) {
if (Buffer.isBuffer(buffers[i])) {
@ -85,3 +131,16 @@ export function writevSync(fd, buffers, position) {
return innerWritev(fd, buffers, position);
}
export function writevPromise(
fd: number,
buffers: ArrayBufferView[],
position?: number,
): Promise<WriteVResult> {
return new Promise((resolve, reject) => {
writev(fd, buffers, position, (err, bytesWritten, buffers) => {
if (err) reject(err);
else resolve({ bytesWritten, buffers });
});
});
}

View file

@ -154,7 +154,7 @@ export class TLSSocket extends net.Socket {
const afterConnect = handle.afterConnect;
handle.afterConnect = async (req: any, status: number) => {
options.hostname ??= undefined; // coerce to undefined if null, startTls expects hostname to be undefined
if (tlssock._isNpmAgent) {
if (tlssock._needsSockInitWorkaround) {
// skips the TLS handshake for @npmcli/agent as it's handled by
// onSocket handler of ClientRequest object.
tlssock.emit("secure");

View file

@ -119,7 +119,7 @@ import {
// @deno-types="./_fs/_fs_write.d.ts"
import { write, writeSync } from "ext:deno_node/_fs/_fs_write.mjs";
// @deno-types="./_fs/_fs_writev.d.ts"
import { writev, writevSync } from "ext:deno_node/_fs/_fs_writev.mjs";
import { writev, writevSync } from "ext:deno_node/_fs/_fs_writev.ts";
import { readv, readvSync } from "ext:deno_node/_fs/_fs_readv.ts";
import {
writeFile,

View file

@ -6,7 +6,7 @@
import { EventEmitter } from "node:events";
import { Buffer } from "node:buffer";
import { Mode, promises, read, write } from "node:fs";
export type { BigIntStats, Stats } from "ext:deno_node/_fs/_fs_stat.ts";
import { core } from "ext:core/mod.js";
import {
BinaryOptionsArgument,
FileOptionsArgument,
@ -14,7 +14,8 @@ import {
TextOptionsArgument,
} from "ext:deno_node/_fs/_fs_common.ts";
import { ftruncatePromise } from "ext:deno_node/_fs/_fs_ftruncate.ts";
import { core } from "ext:core/mod.js";
export type { BigIntStats, Stats } from "ext:deno_node/_fs/_fs_stat.ts";
import { writevPromise, WriteVResult } from "ext:deno_node/_fs/_fs_writev.ts";
interface WriteResult {
bytesWritten: number;
@ -64,7 +65,7 @@ export class FileHandle extends EventEmitter {
position,
(err, bytesRead, buffer) => {
if (err) reject(err);
else resolve({ buffer: buffer, bytesRead: bytesRead });
else resolve({ buffer, bytesRead });
},
);
});
@ -72,7 +73,7 @@ export class FileHandle extends EventEmitter {
return new Promise((resolve, reject) => {
read(this.fd, bufferOrOpt, (err, bytesRead, buffer) => {
if (err) reject(err);
else resolve({ buffer: buffer, bytesRead: bytesRead });
else resolve({ buffer, bytesRead });
});
});
}
@ -137,6 +138,10 @@ export class FileHandle extends EventEmitter {
return fsCall(promises.writeFile, this, data, options);
}
writev(buffers: ArrayBufferView[], position?: number): Promise<WriteVResult> {
return fsCall(writevPromise, this, buffers, position);
}
close(): Promise<void> {
// Note that Deno.close is not async
return Promise.resolve(core.close(this.fd));
@ -152,6 +157,14 @@ export class FileHandle extends EventEmitter {
assertNotClosed(this, promises.chmod.name);
return promises.chmod(this.#path, mode);
}
utimes(
atime: number | string | Date,
mtime: number | string | Date,
): Promise<void> {
assertNotClosed(this, promises.utimes.name);
return promises.utimes(this.#path, atime, mtime);
}
}
function assertNotClosed(handle: FileHandle, syscall: string) {

View file

@ -18,7 +18,7 @@ import { errorOrDestroy } from "ext:deno_node/internal/streams/destroy.mjs";
import { open as fsOpen } from "ext:deno_node/_fs/_fs_open.ts";
import { read as fsRead } from "ext:deno_node/_fs/_fs_read.ts";
import { write as fsWrite } from "ext:deno_node/_fs/_fs_write.mjs";
import { writev as fsWritev } from "ext:deno_node/_fs/_fs_writev.mjs";
import { writev as fsWritev } from "ext:deno_node/_fs/_fs_writev.ts";
import { close as fsClose } from "ext:deno_node/_fs/_fs_close.ts";
import { Buffer } from "node:buffer";
import {

View file

@ -1157,6 +1157,13 @@ function _emitCloseNT(s: Socket | Server) {
s.emit("close");
}
// The packages that need socket initialization workaround
const pkgsNeedsSockInitWorkaround = [
"@npmcli/agent",
"npm-check-updates",
"playwright-core",
];
/**
* This class is an abstraction of a TCP socket or a streaming `IPC` endpoint
* (uses named pipes on Windows, and Unix domain sockets otherwise). It is also
@ -1201,9 +1208,11 @@ export class Socket extends Duplex {
_host: string | null = null;
// deno-lint-ignore no-explicit-any
_parent: any = null;
// The flag for detecting if it's called in @npmcli/agent
// Skip some initialization (initial read and tls handshake if it's tls socket).
// If this flag is true, it's used as connection for http(s) request, and
// the reading and TLS handshake is done by the http client.
// See discussions in https://github.com/denoland/deno/pull/25470 for more details.
_isNpmAgent = false;
_needsSockInitWorkaround = false;
autoSelectFamilyAttemptedAddresses: AddressInfo[] | undefined = undefined;
constructor(options: SocketOptions | number) {
@ -1224,21 +1233,20 @@ export class Socket extends Duplex {
super(options);
// Note: If the socket is created from one of:
// - @npmcli/agent
// - npm-check-updates (bundles @npmcli/agent as a dependency)
// Note: If the socket is created from one of `pkgNeedsSockInitWorkaround`,
// the 'socket' event on ClientRequest object happens after 'connect' event on Socket object.
// That swaps the sequence of op_node_http_request_with_conn() call and
// initial socket read. That causes op_node_http_request_with_conn() not
// working.
// To avoid the above situation, we detect the socket created from
// @npmcli/agent and pause the socket (and also skips the startTls call
// if it's TLSSocket)
// one of those packages using stack trace and pause the socket
// (and also skips the startTls call if it's TLSSocket)
// TODO(kt3k): Remove this workaround
const errorStack = new Error().stack;
this._isNpmAgent = errorStack?.includes("@npmcli/agent") ||
errorStack?.includes("npm-check-updates") || false;
if (this._isNpmAgent) {
this._needsSockInitWorkaround = pkgsNeedsSockInitWorkaround.some((pkg) =>
errorStack?.includes(pkg)
);
if (this._needsSockInitWorkaround) {
this.pause();
}

View file

@ -35,7 +35,7 @@ import { validateIntegerRange } from "ext:deno_node/_utils.ts";
import process from "node:process";
import { isWindows } from "ext:deno_node/_util/os.ts";
import { os } from "ext:deno_node/internal_binding/constants.ts";
import { osUptime } from "ext:runtime/30_os.js";
import { osUptime } from "ext:deno_os/30_os.js";
import { Buffer } from "ext:deno_node/internal/buffer.mjs";
import { primordials } from "ext:core/mod.js";
const { StringPrototypeEndsWith, StringPrototypeSlice } = primordials;

View file

@ -58,7 +58,7 @@ import {
} from "ext:deno_node/_next_tick.ts";
import { isWindows } from "ext:deno_node/_util/os.ts";
import * as io from "ext:deno_io/12_io.js";
import * as denoOs from "ext:runtime/30_os.js";
import * as denoOs from "ext:deno_os/30_os.js";
export let argv0 = "";

33
ext/os/Cargo.toml Normal file
View file

@ -0,0 +1,33 @@
# Copyright 2018-2025 the Deno authors. MIT license.
[package]
name = "deno_os"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
readme = "README.md"
repository.workspace = true
description = "OS specific APIs for Deno"
[lib]
path = "lib.rs"
[dependencies]
deno_core.workspace = true
deno_error.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_telemetry.workspace = true
libc.workspace = true
netif = "0.1.6"
once_cell.workspace = true
serde.workspace = true
signal-hook = "0.3.17"
signal-hook-registry = "1.4.0"
thiserror.workspace = true
tokio.workspace = true
[target.'cfg(windows)'.dependencies]
winapi = { workspace = true, features = ["commapi", "knownfolders", "mswsock", "objbase", "psapi", "shlobj", "tlhelp32", "winbase", "winerror", "winuser", "winsock2"] }
ntapi = "0.4.0"

View file

@ -1,4 +1,6 @@
## `os` ops
# deno_os
This crate implements OS specific APIs for Deno
`loadavg`

View file

@ -1,19 +1,54 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::collections::HashMap;
use std::collections::HashSet;
use std::env;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use deno_core::op2;
use deno_core::v8;
use deno_core::OpState;
use deno_node::NODE_ENV_VAR_ALLOWLIST;
use deno_path_util::normalize_path;
use deno_permissions::PermissionCheckError;
use deno_permissions::PermissionsContainer;
use once_cell::sync::Lazy;
use serde::Serialize;
use crate::sys_info;
use crate::worker::ExitCode;
mod ops;
pub mod signal;
pub mod sys_info;
pub use ops::signal::SignalError;
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
// The full list of environment variables supported by Node.js is available
// at https://nodejs.org/api/cli.html#environment-variables
let mut set = HashSet::new();
set.insert("NODE_DEBUG".to_string());
set.insert("NODE_OPTIONS".to_string());
set
});
#[derive(Clone, Default)]
pub struct ExitCode(Arc<AtomicI32>);
impl ExitCode {
pub fn get(&self) -> i32 {
self.0.load(Ordering::Relaxed)
}
pub fn set(&mut self, code: i32) {
self.0.store(code, Ordering::Relaxed);
}
}
pub fn exit(code: i32) -> ! {
deno_telemetry::flush();
#[allow(clippy::disallowed_methods)]
std::process::exit(code);
}
deno_core::extension!(
deno_os,
@ -35,13 +70,21 @@ deno_core::extension!(
op_system_memory_info,
op_uid,
op_runtime_memory_usage,
ops::signal::op_signal_bind,
ops::signal::op_signal_unbind,
ops::signal::op_signal_poll,
],
esm = ["30_os.js", "40_signals.js"],
options = {
exit_code: ExitCode,
},
state = |state, options| {
state.put::<ExitCode>(options.exit_code);
},
#[cfg(unix)]
{
state.put(ops::signal::SignalState::default());
}
}
);
deno_core::extension!(
@ -64,12 +107,16 @@ deno_core::extension!(
op_system_memory_info,
op_uid,
op_runtime_memory_usage,
ops::signal::op_signal_bind,
ops::signal::op_signal_unbind,
ops::signal::op_signal_poll,
],
esm = ["30_os.js", "40_signals.js"],
middleware = |op| match op.name {
"op_exit" | "op_set_exit_code" | "op_get_exit_code" =>
op.with_implementation_from(&deno_core::op_void_sync()),
_ => op,
},
}
);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
@ -196,7 +243,7 @@ fn op_get_exit_code(state: &mut OpState) -> i32 {
#[op2(fast)]
fn op_exit(state: &mut OpState) {
let code = state.borrow::<ExitCode>().get();
crate::exit(code)
exit(code)
}
#[op2(stack_trace)]
@ -239,7 +286,7 @@ fn op_network_interfaces(
Ok(netif::up()?.map(NetworkInterface::from).collect())
}
#[derive(serde::Serialize)]
#[derive(Serialize)]
struct NetworkInterface {
family: &'static str,
name: String,

3
ext/os/ops/mod.rs Normal file
View file

@ -0,0 +1,3 @@
// Copyright 2018-2025 the Deno authors. MIT license.
pub mod signal;

View file

@ -33,17 +33,6 @@ use tokio::signal::windows::CtrlBreak;
#[cfg(windows)]
use tokio::signal::windows::CtrlC;
deno_core::extension!(
deno_signal,
ops = [op_signal_bind, op_signal_unbind, op_signal_poll],
state = |state| {
#[cfg(unix)]
{
state.put(SignalState::default());
}
}
);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum SignalError {
#[class(type)]
@ -62,7 +51,7 @@ pub enum SignalError {
#[cfg(unix)]
#[derive(Default)]
struct SignalState {
pub struct SignalState {
enable_default_handlers: BTreeMap<libc::c_int, Arc<AtomicBool>>,
}
@ -164,7 +153,7 @@ impl Resource for SignalStreamResource {
#[cfg(unix)]
#[op2(fast)]
#[smi]
fn op_signal_bind(
pub fn op_signal_bind(
state: &mut OpState,
#[string] sig: &str,
) -> Result<ResourceId, SignalError> {
@ -201,7 +190,7 @@ fn op_signal_bind(
#[cfg(windows)]
#[op2(fast)]
#[smi]
fn op_signal_bind(
pub fn op_signal_bind(
state: &mut OpState,
#[string] sig: &str,
) -> Result<ResourceId, SignalError> {
@ -225,7 +214,7 @@ fn op_signal_bind(
}
#[op2(async)]
async fn op_signal_poll(
pub async fn op_signal_poll(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
) -> Result<bool, ResourceError> {

View file

@ -2,7 +2,7 @@
use deno_media_type::MediaType;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageCheckerRc;
use node_resolver::InNpmPackageChecker;
use node_resolver::PackageJsonResolverRc;
use node_resolver::ResolutionMode;
use sys_traits::FsRead;
@ -16,14 +16,16 @@ use crate::sync::MaybeDashMap;
/// be CJS or ESM after they're loaded based on their contents. So these
/// files will be "maybe CJS" until they're loaded.
#[derive(Debug)]
pub struct CjsTracker<TSys: FsRead> {
is_cjs_resolver: IsCjsResolver<TSys>,
pub struct CjsTracker<TInNpmPackageChecker: InNpmPackageChecker, TSys: FsRead> {
is_cjs_resolver: IsCjsResolver<TInNpmPackageChecker, TSys>,
known: MaybeDashMap<Url, ResolutionMode>,
}
impl<TSys: FsRead> CjsTracker<TSys> {
impl<TInNpmPackageChecker: InNpmPackageChecker, TSys: FsRead>
CjsTracker<TInNpmPackageChecker, TSys>
{
pub fn new(
in_npm_pkg_checker: InNpmPackageCheckerRc,
in_npm_pkg_checker: TInNpmPackageChecker,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
mode: IsCjsResolutionMode,
) -> Self {
@ -125,15 +127,20 @@ pub enum IsCjsResolutionMode {
/// Resolves whether a module is CJS or ESM.
#[derive(Debug)]
pub struct IsCjsResolver<TSys: FsRead> {
in_npm_pkg_checker: InNpmPackageCheckerRc,
pub struct IsCjsResolver<
TInNpmPackageChecker: InNpmPackageChecker,
TSys: FsRead,
> {
in_npm_pkg_checker: TInNpmPackageChecker,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
mode: IsCjsResolutionMode,
}
impl<TSys: FsRead> IsCjsResolver<TSys> {
impl<TInNpmPackageChecker: InNpmPackageChecker, TSys: FsRead>
IsCjsResolver<TInNpmPackageChecker, TSys>
{
pub fn new(
in_npm_pkg_checker: InNpmPackageCheckerRc,
in_npm_pkg_checker: TInNpmPackageChecker,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
mode: IsCjsResolutionMode,
) -> Self {

View file

@ -19,11 +19,12 @@ use deno_package_json::PackageJsonDepValueParseError;
use deno_semver::npm::NpmPackageReqReference;
use node_resolver::errors::NodeResolveError;
use node_resolver::errors::PackageSubpathResolveError;
use node_resolver::InNpmPackageCheckerRc;
use node_resolver::InNpmPackageChecker;
use node_resolver::IsBuiltInNodeModuleChecker;
use node_resolver::NodeResolution;
use node_resolver::NodeResolutionKind;
use node_resolver::NodeResolverRc;
use node_resolver::NpmPackageFolderResolver;
use node_resolver::ResolutionMode;
use npm::MissingPackageNodeModulesFolderError;
use npm::NodeModulesOutOfDateError;
@ -101,22 +102,42 @@ pub enum DenoResolveErrorKind {
#[derive(Debug)]
pub struct NodeAndNpmReqResolver<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> {
pub node_resolver: NodeResolverRc<TIsBuiltInNodeModuleChecker, TSys>,
pub npm_req_resolver: NpmReqResolverRc<TIsBuiltInNodeModuleChecker, TSys>,
pub node_resolver: NodeResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
pub npm_req_resolver: NpmReqResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
}
pub struct DenoResolverOptions<
'a,
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSloppyImportResolverFs: SloppyImportResolverFs,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> {
pub in_npm_pkg_checker: InNpmPackageCheckerRc,
pub node_and_req_resolver:
Option<NodeAndNpmReqResolver<TIsBuiltInNodeModuleChecker, TSys>>,
pub in_npm_pkg_checker: TInNpmPackageChecker,
pub node_and_req_resolver: Option<
NodeAndNpmReqResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
>,
pub sloppy_imports_resolver:
Option<SloppyImportsResolverRc<TSloppyImportResolverFs>>,
pub workspace_resolver: WorkspaceResolverRc,
@ -131,13 +152,21 @@ pub struct DenoResolverOptions<
/// import map, JSX settings.
#[derive(Debug)]
pub struct DenoResolver<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSloppyImportResolverFs: SloppyImportResolverFs,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> {
in_npm_pkg_checker: InNpmPackageCheckerRc,
node_and_npm_resolver:
Option<NodeAndNpmReqResolver<TIsBuiltInNodeModuleChecker, TSys>>,
in_npm_pkg_checker: TInNpmPackageChecker,
node_and_npm_resolver: Option<
NodeAndNpmReqResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
>,
sloppy_imports_resolver:
Option<SloppyImportsResolverRc<TSloppyImportResolverFs>>,
workspace_resolver: WorkspaceResolverRc,
@ -146,14 +175,25 @@ pub struct DenoResolver<
}
impl<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSloppyImportResolverFs: SloppyImportResolverFs,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> DenoResolver<TIsBuiltInNodeModuleChecker, TSloppyImportResolverFs, TSys>
>
DenoResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSloppyImportResolverFs,
TSys,
>
{
pub fn new(
options: DenoResolverOptions<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSloppyImportResolverFs,
TSys,
>,

View file

@ -27,8 +27,6 @@ use thiserror::Error;
use url::Url;
use super::local::normalize_pkg_name_for_node_modules_deno_folder;
use crate::sync::MaybeSend;
use crate::sync::MaybeSync;
#[derive(Debug, Error, deno_error::JsError)]
pub enum ByonmResolvePkgFolderFromDenoReqError {
@ -89,7 +87,7 @@ impl<TSys: FsCanonicalize + FsRead + FsMetadata + FsReadDir>
}
}
pub fn root_node_modules_dir(&self) -> Option<&Path> {
pub fn root_node_modules_path(&self) -> Option<&Path> {
self.root_node_modules_dir.as_deref()
}
@ -377,15 +375,8 @@ impl<TSys: FsCanonicalize + FsRead + FsMetadata + FsReadDir>
}
}
impl<
TSys: FsCanonicalize
+ FsMetadata
+ FsRead
+ FsReadDir
+ MaybeSend
+ MaybeSync
+ std::fmt::Debug,
> NpmPackageFolderResolver for ByonmNpmResolver<TSys>
impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
NpmPackageFolderResolver for ByonmNpmResolver<TSys>
{
fn resolve_package_folder_from_package(
&self,
@ -438,7 +429,7 @@ impl<
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ByonmInNpmPackageChecker;
impl InNpmPackageChecker for ByonmInNpmPackageChecker {

View file

@ -6,26 +6,69 @@ use std::path::PathBuf;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use node_resolver::NpmPackageFolderResolver;
use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata;
use url::Url;
use crate::sync::MaybeSend;
use crate::sync::MaybeSync;
#[derive(Debug)]
pub enum NpmPackageFsResolver<TSys: FsCanonicalize + FsMetadata> {
Local(super::local::LocalNpmPackageResolver<TSys>),
Global(super::global::GlobalNpmPackageResolver),
}
#[allow(clippy::disallowed_types)]
pub type NpmPackageFsResolverRc =
crate::sync::MaybeArc<dyn NpmPackageFsResolver>;
impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFsResolver<TSys> {
/// The local node_modules folder (only for the local resolver).
pub fn node_modules_path(&self) -> Option<&Path> {
match self {
NpmPackageFsResolver::Local(resolver) => resolver.node_modules_path(),
NpmPackageFsResolver::Global(_) => None,
}
}
/// Part of the resolution that interacts with the file system.
pub trait NpmPackageFsResolver:
NpmPackageFolderResolver + MaybeSend + MaybeSync
{
/// The local node_modules folder if it is applicable to the implementation.
fn node_modules_path(&self) -> Option<&Path>;
pub fn maybe_package_folder(
&self,
package_id: &NpmPackageId,
) -> Option<PathBuf> {
match self {
NpmPackageFsResolver::Local(resolver) => {
resolver.maybe_package_folder(package_id)
}
NpmPackageFsResolver::Global(resolver) => {
resolver.maybe_package_folder(package_id)
}
}
}
fn maybe_package_folder(&self, package_id: &NpmPackageId) -> Option<PathBuf>;
fn resolve_package_cache_folder_id_from_specifier(
pub fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &Url,
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error>;
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
match self {
NpmPackageFsResolver::Local(resolver) => {
resolver.resolve_package_cache_folder_id_from_specifier(specifier)
}
NpmPackageFsResolver::Global(resolver) => {
resolver.resolve_package_cache_folder_id_from_specifier(specifier)
}
}
}
}
impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
for NpmPackageFsResolver<TSys>
{
fn resolve_package_folder_from_package(
&self,
specifier: &str,
referrer: &Url,
) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> {
match self {
NpmPackageFsResolver::Local(r) => {
r.resolve_package_folder_from_package(specifier, referrer)
}
NpmPackageFsResolver::Global(r) => {
r.resolve_package_folder_from_package(specifier, referrer)
}
}
}
}

View file

@ -2,7 +2,6 @@
//! Code for global npm cache resolution.
use std::path::Path;
use std::path::PathBuf;
use deno_npm::NpmPackageCacheFolderId;
@ -18,7 +17,6 @@ use url::Url;
use super::resolution::NpmResolutionCellRc;
use super::NpmCacheDirRc;
use super::NpmPackageFsResolver;
use crate::ResolvedNpmRcRc;
/// Resolves packages from the global npm cache.
@ -42,6 +40,26 @@ impl GlobalNpmPackageResolver {
}
}
pub fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
let folder_copy_index = self
.resolution
.resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?;
let registry_url = self.npm_rc.get_registry_url(&id.nv.name);
Some(self.cache.package_folder_for_id(
&id.nv.name,
&id.nv.version.to_string(),
folder_copy_index,
registry_url,
))
}
pub fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &Url,
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
Ok(self.resolve_package_cache_folder_id_from_specifier_inner(specifier))
}
fn resolve_package_cache_folder_id_from_specifier_inner(
&self,
specifier: &Url,
@ -121,29 +139,3 @@ impl NpmPackageFolderResolver for GlobalNpmPackageResolver {
}
}
}
impl NpmPackageFsResolver for GlobalNpmPackageResolver {
fn node_modules_path(&self) -> Option<&Path> {
None
}
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
let folder_copy_index = self
.resolution
.resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?;
let registry_url = self.npm_rc.get_registry_url(&id.nv.name);
Some(self.cache.package_folder_for_id(
&id.nv.name,
&id.nv.version.to_string(),
folder_copy_index,
registry_url,
))
}
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &Url,
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
Ok(self.resolve_package_cache_folder_id_from_specifier_inner(specifier))
}
}

View file

@ -20,27 +20,20 @@ use sys_traits::FsMetadata;
use url::Url;
use super::resolution::NpmResolutionCellRc;
use super::NpmPackageFsResolver;
use crate::npm::local::get_package_folder_id_folder_name_from_parts;
use crate::npm::local::get_package_folder_id_from_folder_name;
use crate::sync::MaybeSend;
use crate::sync::MaybeSync;
/// Resolver that creates a local node_modules directory
/// and resolves packages from it.
#[derive(Debug)]
pub struct LocalNpmPackageResolver<
TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync,
> {
pub struct LocalNpmPackageResolver<TSys: FsCanonicalize + FsMetadata> {
resolution: NpmResolutionCellRc,
sys: TSys,
root_node_modules_path: PathBuf,
root_node_modules_url: Url,
}
impl<TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync>
LocalNpmPackageResolver<TSys>
{
impl<TSys: FsCanonicalize + FsMetadata> LocalNpmPackageResolver<TSys> {
#[allow(clippy::too_many_arguments)]
pub fn new(
resolution: NpmResolutionCellRc,
@ -56,6 +49,55 @@ impl<TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync>
}
}
pub fn node_modules_path(&self) -> Option<&Path> {
Some(self.root_node_modules_path.as_ref())
}
pub fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
let folder_copy_index = self
.resolution
.resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?;
// package is stored at:
// node_modules/.deno/<package_cache_folder_id_folder_name>/node_modules/<package_name>
Some(
self
.root_node_modules_path
.join(".deno")
.join(get_package_folder_id_folder_name_from_parts(
&id.nv,
folder_copy_index,
))
.join("node_modules")
.join(&id.nv.name),
)
}
pub fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &Url,
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
let Some(folder_path) =
self.resolve_package_folder_from_specifier(specifier)?
else {
return Ok(None);
};
// ex. project/node_modules/.deno/preact@10.24.3/node_modules/preact/
let Some(node_modules_ancestor) = folder_path
.ancestors()
.find(|ancestor| ancestor.ends_with("node_modules"))
else {
return Ok(None);
};
let Some(folder_name) =
node_modules_ancestor.parent().and_then(|p| p.file_name())
else {
return Ok(None);
};
Ok(get_package_folder_id_from_folder_name(
&folder_name.to_string_lossy(),
))
}
fn resolve_package_root(&self, path: &Path) -> PathBuf {
let mut last_found = path;
loop {
@ -101,9 +143,8 @@ impl<TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync>
}
}
impl<
TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync + std::fmt::Debug,
> NpmPackageFolderResolver for LocalNpmPackageResolver<TSys>
impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
for LocalNpmPackageResolver<TSys>
{
fn resolve_package_folder_from_package(
&self,
@ -163,60 +204,6 @@ impl<
}
}
impl<
TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync + std::fmt::Debug,
> NpmPackageFsResolver for LocalNpmPackageResolver<TSys>
{
fn node_modules_path(&self) -> Option<&Path> {
Some(self.root_node_modules_path.as_ref())
}
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
let folder_copy_index = self
.resolution
.resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?;
// package is stored at:
// node_modules/.deno/<package_cache_folder_id_folder_name>/node_modules/<package_name>
Some(
self
.root_node_modules_path
.join(".deno")
.join(get_package_folder_id_folder_name_from_parts(
&id.nv,
folder_copy_index,
))
.join("node_modules")
.join(&id.nv.name),
)
}
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &Url,
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
let Some(folder_path) =
self.resolve_package_folder_from_specifier(specifier)?
else {
return Ok(None);
};
// ex. project/node_modules/.deno/preact@10.24.3/node_modules/preact/
let Some(node_modules_ancestor) = folder_path
.ancestors()
.find(|ancestor| ancestor.ends_with("node_modules"))
else {
return Ok(None);
};
let Some(folder_name) =
node_modules_ancestor.parent().and_then(|p| p.file_name())
else {
return Ok(None);
};
Ok(get_package_folder_id_from_folder_name(
&folder_name.to_string_lossy(),
))
}
}
fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
let mut path = path.to_path_buf();
// ensure backslashes are used on windows

View file

@ -13,6 +13,7 @@ use deno_npm::resolution::PackageNvNotFoundError;
use deno_npm::resolution::PackageReqNotFoundError;
use deno_npm::NpmPackageCacheFolderId;
use deno_npm::NpmPackageId;
use deno_npm::NpmSystemInfo;
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
@ -23,14 +24,10 @@ use sys_traits::FsMetadata;
use url::Url;
use self::common::NpmPackageFsResolver;
use self::common::NpmPackageFsResolverRc;
use self::global::GlobalNpmPackageResolver;
use self::local::LocalNpmPackageResolver;
pub use self::resolution::NpmResolutionCell;
pub use self::resolution::NpmResolutionCellRc;
use crate::sync::new_rc;
use crate::sync::MaybeSend;
use crate::sync::MaybeSync;
use crate::NpmCacheDirRc;
use crate::ResolvedNpmRcRc;
@ -89,58 +86,84 @@ pub enum ResolvePkgIdFromSpecifierError {
NotFound(#[from] PackageCacheFolderIdNotFoundError),
}
pub struct ManagedNpmResolverCreateOptions<
TSys: FsCanonicalize + FsMetadata + Clone,
> {
pub npm_cache_dir: NpmCacheDirRc,
pub sys: TSys,
pub maybe_node_modules_path: Option<PathBuf>,
pub npm_system_info: NpmSystemInfo,
pub npmrc: ResolvedNpmRcRc,
pub npm_resolution: NpmResolutionCellRc,
}
#[allow(clippy::disallowed_types)]
pub type ManagedNpmResolverRc<TSys> =
crate::sync::MaybeArc<ManagedNpmResolver<TSys>>;
#[derive(Debug)]
pub struct ManagedNpmResolver<TSys: FsCanonicalize> {
fs_resolver: NpmPackageFsResolverRc,
pub struct ManagedNpmResolver<TSys: FsCanonicalize + FsMetadata> {
fs_resolver: NpmPackageFsResolver<TSys>,
npm_cache_dir: NpmCacheDirRc,
resolution: NpmResolutionCellRc,
sys: TSys,
}
impl<TSys: FsCanonicalize> ManagedNpmResolver<TSys> {
pub fn new<
TCreateSys: FsCanonicalize
+ FsMetadata
+ std::fmt::Debug
+ MaybeSend
+ MaybeSync
+ Clone
+ 'static,
>(
npm_cache_dir: &NpmCacheDirRc,
npm_rc: &ResolvedNpmRcRc,
resolution: NpmResolutionCellRc,
sys: TCreateSys,
maybe_node_modules_path: Option<PathBuf>,
impl<TSys: FsCanonicalize + FsMetadata> ManagedNpmResolver<TSys> {
pub fn new<TCreateSys: FsCanonicalize + FsMetadata + Clone>(
options: ManagedNpmResolverCreateOptions<TCreateSys>,
) -> ManagedNpmResolver<TCreateSys> {
let fs_resolver: NpmPackageFsResolverRc = match maybe_node_modules_path {
Some(node_modules_folder) => new_rc(LocalNpmPackageResolver::new(
resolution.clone(),
sys.clone(),
node_modules_folder,
)),
None => new_rc(GlobalNpmPackageResolver::new(
npm_cache_dir.clone(),
npm_rc.clone(),
resolution.clone(),
let fs_resolver = match options.maybe_node_modules_path {
Some(node_modules_folder) => {
NpmPackageFsResolver::Local(LocalNpmPackageResolver::new(
options.npm_resolution.clone(),
options.sys.clone(),
node_modules_folder,
))
}
None => NpmPackageFsResolver::Global(GlobalNpmPackageResolver::new(
options.npm_cache_dir.clone(),
options.npmrc.clone(),
options.npm_resolution.clone(),
)),
};
ManagedNpmResolver {
fs_resolver,
sys,
resolution,
npm_cache_dir: options.npm_cache_dir,
sys: options.sys,
resolution: options.npm_resolution,
}
}
#[inline]
pub fn node_modules_path(&self) -> Option<&Path> {
pub fn root_node_modules_path(&self) -> Option<&Path> {
self.fs_resolver.node_modules_path()
}
pub fn global_cache_root_path(&self) -> &Path {
self.npm_cache_dir.root_dir()
}
pub fn global_cache_root_url(&self) -> &Url {
self.npm_cache_dir.root_dir_url()
}
pub fn resolution(&self) -> &NpmResolutionCell {
self.resolution.as_ref()
}
/// Checks if the provided package req's folder is cached.
pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool {
self
.resolution
.resolve_pkg_id_from_pkg_req(req)
.ok()
.and_then(|id| self.resolve_pkg_folder_from_pkg_id(&id).ok())
.map(|folder| self.sys.fs_exists_no_err(folder))
.unwrap_or(false)
}
pub fn resolve_pkg_folder_from_pkg_id(
&self,
package_id: &NpmPackageId,
@ -213,8 +236,8 @@ impl<TSys: FsCanonicalize> ManagedNpmResolver<TSys> {
}
}
impl<TSys: FsCanonicalize + std::fmt::Debug + MaybeSend + MaybeSync>
NpmPackageFolderResolver for ManagedNpmResolver<TSys>
impl<TSys: FsCanonicalize + FsMetadata> NpmPackageFolderResolver
for ManagedNpmResolver<TSys>
{
fn resolve_package_folder_from_package(
&self,
@ -234,7 +257,7 @@ impl<TSys: FsCanonicalize + std::fmt::Debug + MaybeSend + MaybeSync>
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ManagedInNpmPackageChecker {
root_dir: Url,
}

View file

@ -1,7 +1,5 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::collections::HashMap;
use deno_npm::resolution::NpmPackagesPartitioned;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::resolution::PackageCacheFolderIdNotFoundError;
@ -124,8 +122,23 @@ impl NpmResolutionCell {
.map(|pkg| pkg.id.clone())
}
pub fn package_reqs(&self) -> HashMap<PackageReq, PackageNv> {
self.snapshot.read().package_reqs().clone()
pub fn package_reqs(&self) -> Vec<(PackageReq, PackageNv)> {
self
.snapshot
.read()
.package_reqs()
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
}
pub fn top_level_packages(&self) -> Vec<NpmPackageId> {
self
.snapshot
.read()
.top_level_packages()
.cloned()
.collect::<Vec<_>>()
}
pub fn all_system_packages(

View file

@ -1,6 +1,7 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::fmt::Debug;
use std::path::Path;
use std::path::PathBuf;
use boxed_error::Boxed;
@ -14,11 +15,12 @@ use node_resolver::errors::PackageFolderResolveIoError;
use node_resolver::errors::PackageNotFoundError;
use node_resolver::errors::PackageResolveErrorKind;
use node_resolver::errors::PackageSubpathResolveError;
use node_resolver::InNpmPackageCheckerRc;
use node_resolver::InNpmPackageChecker;
use node_resolver::IsBuiltInNodeModuleChecker;
use node_resolver::NodeResolution;
use node_resolver::NodeResolutionKind;
use node_resolver::NodeResolverRc;
use node_resolver::NpmPackageFolderResolver;
use node_resolver::ResolutionMode;
use sys_traits::FsCanonicalize;
use sys_traits::FsMetadata;
@ -35,10 +37,14 @@ pub use self::byonm::ByonmResolvePkgFolderFromDenoReqError;
pub use self::local::get_package_folder_id_folder_name;
pub use self::local::normalize_pkg_name_for_node_modules_deno_folder;
use self::managed::create_managed_in_npm_pkg_checker;
use self::managed::ManagedInNpmPackageChecker;
use self::managed::ManagedInNpmPkgCheckerCreateOptions;
pub use self::managed::ManagedNpmResolver;
use self::managed::ManagedNpmResolverCreateOptions;
pub use self::managed::ManagedNpmResolverRc;
use crate::sync::new_rc;
use crate::sync::MaybeSend;
use crate::sync::MaybeSync;
mod byonm;
mod local;
@ -49,14 +55,33 @@ pub enum CreateInNpmPkgCheckerOptions<'a> {
Byonm,
}
pub fn create_in_npm_pkg_checker(
options: CreateInNpmPkgCheckerOptions,
) -> InNpmPackageCheckerRc {
match options {
CreateInNpmPkgCheckerOptions::Managed(options) => {
new_rc(create_managed_in_npm_pkg_checker(options))
#[derive(Debug, Clone)]
pub enum DenoInNpmPackageChecker {
Managed(ManagedInNpmPackageChecker),
Byonm(ByonmInNpmPackageChecker),
}
impl DenoInNpmPackageChecker {
pub fn new(options: CreateInNpmPkgCheckerOptions) -> Self {
match options {
CreateInNpmPkgCheckerOptions::Managed(options) => {
DenoInNpmPackageChecker::Managed(create_managed_in_npm_pkg_checker(
options,
))
}
CreateInNpmPkgCheckerOptions::Byonm => {
DenoInNpmPackageChecker::Byonm(ByonmInNpmPackageChecker)
}
}
}
}
impl InNpmPackageChecker for DenoInNpmPackageChecker {
fn in_npm_package(&self, specifier: &Url) -> bool {
match self {
DenoInNpmPackageChecker::Managed(c) => c.in_npm_package(specifier),
DenoInNpmPackageChecker::Byonm(c) => c.in_npm_package(specifier),
}
CreateInNpmPkgCheckerOptions::Byonm => new_rc(ByonmInNpmPackageChecker),
}
}
@ -115,10 +140,22 @@ pub enum ResolvePkgFolderFromDenoReqError {
Byonm(byonm::ByonmResolvePkgFolderFromDenoReqError),
}
#[derive(Debug, Clone)]
pub enum ByonmOrManagedNpmResolver<
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
pub enum NpmResolverCreateOptions<
TSys: FsRead
+ FsCanonicalize
+ FsMetadata
+ std::fmt::Debug
+ MaybeSend
+ MaybeSync
+ Clone
+ 'static,
> {
Managed(ManagedNpmResolverCreateOptions<TSys>),
Byonm(ByonmNpmResolverCreateOptions<TSys>),
}
#[derive(Debug, Clone)]
pub enum NpmResolver<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir> {
/// The resolver when "bring your own node_modules" is enabled where Deno
/// does not setup the node_modules directories automatically, but instead
/// uses what already exists on the file system.
@ -126,57 +163,158 @@ pub enum ByonmOrManagedNpmResolver<
Managed(ManagedNpmResolverRc<TSys>),
}
impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
ByonmOrManagedNpmResolver<TSys>
{
impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir> NpmResolver<TSys> {
pub fn new<
TCreateSys: FsCanonicalize
+ FsMetadata
+ FsRead
+ FsReadDir
+ std::fmt::Debug
+ MaybeSend
+ MaybeSync
+ Clone
+ 'static,
>(
options: NpmResolverCreateOptions<TCreateSys>,
) -> NpmResolver<TCreateSys> {
match options {
NpmResolverCreateOptions::Managed(options) => {
NpmResolver::Managed(new_rc(ManagedNpmResolver::<TCreateSys>::new::<
TCreateSys,
>(options)))
}
NpmResolverCreateOptions::Byonm(options) => {
NpmResolver::Byonm(new_rc(ByonmNpmResolver::new(options)))
}
}
}
pub fn is_byonm(&self) -> bool {
matches!(self, NpmResolver::Byonm(_))
}
pub fn is_managed(&self) -> bool {
matches!(self, NpmResolver::Managed(_))
}
pub fn as_managed(&self) -> Option<&ManagedNpmResolver<TSys>> {
match self {
NpmResolver::Managed(resolver) => Some(resolver),
NpmResolver::Byonm(_) => None,
}
}
pub fn root_node_modules_path(&self) -> Option<&Path> {
match self {
NpmResolver::Byonm(resolver) => resolver.root_node_modules_path(),
NpmResolver::Managed(resolver) => resolver.root_node_modules_path(),
}
}
pub fn resolve_pkg_folder_from_deno_module_req(
&self,
req: &PackageReq,
referrer: &Url,
) -> Result<PathBuf, ResolvePkgFolderFromDenoReqError> {
match self {
ByonmOrManagedNpmResolver::Byonm(byonm_resolver) => byonm_resolver
NpmResolver::Byonm(byonm_resolver) => byonm_resolver
.resolve_pkg_folder_from_deno_module_req(req, referrer)
.map_err(ResolvePkgFolderFromDenoReqError::Byonm),
ByonmOrManagedNpmResolver::Managed(managed_resolver) => managed_resolver
NpmResolver::Managed(managed_resolver) => managed_resolver
.resolve_pkg_folder_from_deno_module_req(req, referrer)
.map_err(ResolvePkgFolderFromDenoReqError::Managed),
}
}
}
impl<TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir>
NpmPackageFolderResolver for NpmResolver<TSys>
{
fn resolve_package_folder_from_package(
&self,
specifier: &str,
referrer: &Url,
) -> Result<PathBuf, node_resolver::errors::PackageFolderResolveError> {
match self {
NpmResolver::Byonm(byonm_resolver) => {
byonm_resolver.resolve_package_folder_from_package(specifier, referrer)
}
NpmResolver::Managed(managed_resolver) => managed_resolver
.resolve_package_folder_from_package(specifier, referrer),
}
}
}
pub struct NpmReqResolverOptions<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> {
pub in_npm_pkg_checker: InNpmPackageCheckerRc,
pub node_resolver: NodeResolverRc<TIsBuiltInNodeModuleChecker, TSys>,
pub npm_resolver: ByonmOrManagedNpmResolver<TSys>,
pub in_npm_pkg_checker: TInNpmPackageChecker,
pub node_resolver: NodeResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
pub npm_resolver: NpmResolver<TSys>,
pub sys: TSys,
}
#[allow(clippy::disallowed_types)]
pub type NpmReqResolverRc<TIsBuiltInNodeModuleChecker, TSys> =
crate::sync::MaybeArc<NpmReqResolver<TIsBuiltInNodeModuleChecker, TSys>>;
pub type NpmReqResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
> = crate::sync::MaybeArc<
NpmReqResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
>;
#[derive(Debug)]
pub struct NpmReqResolver<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> {
sys: TSys,
in_npm_pkg_checker: InNpmPackageCheckerRc,
node_resolver: NodeResolverRc<TIsBuiltInNodeModuleChecker, TSys>,
npm_resolver: ByonmOrManagedNpmResolver<TSys>,
in_npm_pkg_checker: TInNpmPackageChecker,
node_resolver: NodeResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
npm_resolver: NpmResolver<TSys>,
}
impl<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
> NpmReqResolver<TIsBuiltInNodeModuleChecker, TSys>
>
NpmReqResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>
{
pub fn new(
options: NpmReqResolverOptions<TIsBuiltInNodeModuleChecker, TSys>,
options: NpmReqResolverOptions<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
) -> Self {
Self {
sys: options.sys,
@ -224,7 +362,7 @@ impl<
match resolution_result {
Ok(url) => Ok(url),
Err(err) => {
if matches!(self.npm_resolver, ByonmOrManagedNpmResolver::Byonm(_)) {
if matches!(self.npm_resolver, NpmResolver::Byonm(_)) {
let package_json_path = package_folder.join("package.json");
if !self.sys.fs_exists_no_err(&package_json_path) {
return Err(
@ -292,9 +430,8 @@ impl<
.into_box(),
);
}
if let ByonmOrManagedNpmResolver::Byonm(
byonm_npm_resolver,
) = &self.npm_resolver
if let NpmResolver::Byonm(byonm_npm_resolver) =
&self.npm_resolver
{
if byonm_npm_resolver
.find_ancestor_package_json_with_dep(

View file

@ -20,11 +20,11 @@ use sys_traits::FsMetadata;
use sys_traits::FsRead;
use url::Url;
use crate::npm::InNpmPackageCheckerRc;
use crate::resolution::NodeResolverRc;
use crate::InNpmPackageChecker;
use crate::IsBuiltInNodeModuleChecker;
use crate::NodeResolutionKind;
use crate::NpmPackageFolderResolverRc;
use crate::NpmPackageFolderResolver;
use crate::PackageJsonResolverRc;
use crate::PathClean;
use crate::ResolutionMode;
@ -62,28 +62,49 @@ pub trait CjsCodeAnalyzer {
pub struct NodeCodeTranslator<
TCjsCodeAnalyzer: CjsCodeAnalyzer,
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead,
> {
cjs_code_analyzer: TCjsCodeAnalyzer,
in_npm_pkg_checker: InNpmPackageCheckerRc,
node_resolver: NodeResolverRc<TIsBuiltInNodeModuleChecker, TSys>,
npm_resolver: NpmPackageFolderResolverRc,
in_npm_pkg_checker: TInNpmPackageChecker,
node_resolver: NodeResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
npm_resolver: TNpmPackageFolderResolver,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
sys: TSys,
}
impl<
TCjsCodeAnalyzer: CjsCodeAnalyzer,
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead,
> NodeCodeTranslator<TCjsCodeAnalyzer, TIsBuiltInNodeModuleChecker, TSys>
>
NodeCodeTranslator<
TCjsCodeAnalyzer,
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>
{
pub fn new(
cjs_code_analyzer: TCjsCodeAnalyzer,
in_npm_pkg_checker: InNpmPackageCheckerRc,
node_resolver: NodeResolverRc<TIsBuiltInNodeModuleChecker, TSys>,
npm_resolver: NpmPackageFolderResolverRc,
in_npm_pkg_checker: TInNpmPackageChecker,
node_resolver: NodeResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
npm_resolver: TNpmPackageFolderResolver,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
sys: TSys,
) -> Self {

View file

@ -14,9 +14,7 @@ mod sync;
pub use deno_package_json::PackageJson;
pub use npm::InNpmPackageChecker;
pub use npm::InNpmPackageCheckerRc;
pub use npm::NpmPackageFolderResolver;
pub use npm::NpmPackageFolderResolverRc;
pub use package_json::PackageJsonResolver;
pub use package_json::PackageJsonResolverRc;
pub use package_json::PackageJsonThreadLocalCache;

View file

@ -9,16 +9,8 @@ use url::Url;
use crate::errors;
use crate::path::PathClean;
use crate::sync::MaybeSend;
use crate::sync::MaybeSync;
#[allow(clippy::disallowed_types)]
pub type NpmPackageFolderResolverRc =
crate::sync::MaybeArc<dyn NpmPackageFolderResolver>;
pub trait NpmPackageFolderResolver:
std::fmt::Debug + MaybeSend + MaybeSync
{
pub trait NpmPackageFolderResolver {
/// Resolves an npm package folder path from the specified referrer.
fn resolve_package_folder_from_package(
&self,
@ -27,11 +19,8 @@ pub trait NpmPackageFolderResolver:
) -> Result<PathBuf, errors::PackageFolderResolveError>;
}
#[allow(clippy::disallowed_types)]
pub type InNpmPackageCheckerRc = crate::sync::MaybeArc<dyn InNpmPackageChecker>;
/// Checks if a provided specifier is in an npm package.
pub trait InNpmPackageChecker: std::fmt::Debug + MaybeSend + MaybeSync {
pub trait InNpmPackageChecker {
fn in_npm_package(&self, specifier: &Url) -> bool;
fn in_npm_package_at_dir_path(&self, path: &Path) -> bool {

View file

@ -46,8 +46,8 @@ use crate::errors::TypesNotFoundError;
use crate::errors::TypesNotFoundErrorData;
use crate::errors::UnsupportedDirImportError;
use crate::errors::UnsupportedEsmUrlSchemeError;
use crate::npm::InNpmPackageCheckerRc;
use crate::NpmPackageFolderResolverRc;
use crate::InNpmPackageChecker;
use crate::NpmPackageFolderResolver;
use crate::PackageJsonResolverRc;
use crate::PathClean;
@ -137,31 +137,52 @@ pub trait IsBuiltInNodeModuleChecker: std::fmt::Debug {
}
#[allow(clippy::disallowed_types)]
pub type NodeResolverRc<TIsBuiltInNodeModuleChecker, TSys> =
crate::sync::MaybeArc<NodeResolver<TIsBuiltInNodeModuleChecker, TSys>>;
pub type NodeResolverRc<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
> = crate::sync::MaybeArc<
NodeResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>,
>;
#[derive(Debug)]
pub struct NodeResolver<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead,
> {
in_npm_pkg_checker: InNpmPackageCheckerRc,
in_npm_pkg_checker: TInNpmPackageChecker,
is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker,
npm_pkg_folder_resolver: NpmPackageFolderResolverRc,
npm_pkg_folder_resolver: TNpmPackageFolderResolver,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
sys: TSys,
conditions_from_resolution_mode: ConditionsFromResolutionMode,
}
impl<
TInNpmPackageChecker: InNpmPackageChecker,
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TSys: FsCanonicalize + FsMetadata + FsRead,
> NodeResolver<TIsBuiltInNodeModuleChecker, TSys>
>
NodeResolver<
TInNpmPackageChecker,
TIsBuiltInNodeModuleChecker,
TNpmPackageFolderResolver,
TSys,
>
{
pub fn new(
in_npm_pkg_checker: InNpmPackageCheckerRc,
in_npm_pkg_checker: TInNpmPackageChecker,
is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker,
npm_pkg_folder_resolver: NpmPackageFolderResolverRc,
npm_pkg_folder_resolver: TNpmPackageFolderResolver,
pkg_json_resolver: PackageJsonResolverRc<TSys>,
sys: TSys,
conditions_from_resolution_mode: ConditionsFromResolutionMode,
@ -444,6 +465,17 @@ impl<
Ok(url)
}
/// Resolves an npm package folder path from the specified referrer.
pub fn resolve_package_folder_from_package(
&self,
specifier: &str,
referrer: &Url,
) -> Result<PathBuf, errors::PackageFolderResolveError> {
self
.npm_pkg_folder_resolver
.resolve_package_folder_from_package(specifier, referrer)
}
/// Checks if the resolved file has a corresponding declaration file.
fn path_to_declaration_url(
&self,

View file

@ -6,17 +6,10 @@ pub use inner::*;
mod inner {
#![allow(clippy::disallowed_types)]
pub use core::marker::Send as MaybeSend;
pub use core::marker::Sync as MaybeSync;
pub use std::sync::Arc as MaybeArc;
}
#[cfg(not(feature = "sync"))]
mod inner {
pub use std::rc::Rc as MaybeArc;
pub trait MaybeSync {}
impl<T> MaybeSync for T where T: ?Sized {}
pub trait MaybeSend {}
impl<T> MaybeSend for T where T: ?Sized {}
}

View file

@ -49,6 +49,7 @@ deno_core.workspace = true
deno_cron.workspace = true
deno_crypto.workspace = true
deno_fetch.workspace = true
deno_os.workspace = true
deno_ffi.workspace = true
deno_fs = { workspace = true, features = ["sync_fs"] }
deno_http.workspace = true
@ -89,8 +90,10 @@ deno_kv.workspace = true
deno_napi.workspace = true
deno_net.workspace = true
deno_node.workspace = true
deno_os.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_resolver.workspace = true
deno_telemetry.workspace = true
deno_terminal.workspace = true
deno_tls.workspace = true
@ -113,7 +116,6 @@ hyper-util.workspace = true
hyper_v014 = { workspace = true, features = ["server", "stream", "http1", "http2", "runtime"] }
libc.workspace = true
log.workspace = true
netif = "0.1.6"
notify.workspace = true
once_cell.workspace = true
percent-encoding.workspace = true
@ -121,8 +123,6 @@ regex.workspace = true
rustyline = { workspace = true, features = ["custom-bindings"] }
same-file = "1.0.6"
serde.workspace = true
signal-hook = "0.3.17"
signal-hook-registry = "1.4.0"
sys_traits.workspace = true
tempfile.workspace = true
thiserror.workspace = true

View file

@ -12,6 +12,8 @@ use deno_core::op2;
use deno_core::FsModuleLoader;
use deno_core::ModuleSpecifier;
use deno_fs::RealFs;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmResolver;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_runtime::permissions::RuntimePermissionDescriptorParser;
use deno_runtime::worker::MainWorker;
@ -42,7 +44,11 @@ async fn main() -> Result<(), AnyError> {
);
let mut worker = MainWorker::bootstrap_from_options(
main_module.clone(),
WorkerServiceOptions::<sys_traits::impls::RealSys> {
WorkerServiceOptions::<
DenoInNpmPackageChecker,
NpmResolver<sys_traits::impls::RealSys>,
sys_traits::impls::RealSys,
> {
module_loader: Rc::new(FsModuleLoader),
permissions: PermissionsContainer::allow_all(permission_desc_parser),
blob_store: Default::default(),

View file

@ -21,10 +21,10 @@ import * as version from "ext:runtime/01_version.ts";
import * as permissions from "ext:runtime/10_permissions.js";
import * as io from "ext:deno_io/12_io.js";
import * as fs from "ext:deno_fs/30_fs.js";
import * as os from "ext:runtime/30_os.js";
import * as os from "ext:deno_os/30_os.js";
import * as fsEvents from "ext:runtime/40_fs_events.js";
import * as process from "ext:runtime/40_process.js";
import * as signals from "ext:runtime/40_signals.js";
import * as signals from "ext:deno_os/40_signals.js";
import * as tty from "ext:runtime/40_tty.js";
import * as kv from "ext:deno_kv/01_db.ts";
import * as cron from "ext:deno_cron/01_cron.ts";

View file

@ -55,7 +55,7 @@ import { registerDeclarativeServer } from "ext:deno_http/00_serve.ts";
import * as event from "ext:deno_web/02_event.js";
import * as location from "ext:deno_web/12_location.js";
import * as version from "ext:runtime/01_version.ts";
import * as os from "ext:runtime/30_os.js";
import * as os from "ext:deno_os/30_os.js";
import * as timers from "ext:deno_web/02_timers.js";
import {
getDefaultInspectOptions,

View file

@ -16,6 +16,7 @@ pub use deno_kv;
pub use deno_napi;
pub use deno_net;
pub use deno_node;
pub use deno_os;
pub use deno_permissions;
pub use deno_terminal::colors;
pub use deno_tls;
@ -33,9 +34,7 @@ pub mod inspector_server;
pub mod js;
pub mod ops;
pub mod permissions;
pub mod signal;
pub mod snapshot;
pub mod sys_info;
pub mod tokio_util;
pub mod web_worker;
pub mod worker;
@ -46,6 +45,7 @@ pub use worker_bootstrap::WorkerExecutionMode;
pub use worker_bootstrap::WorkerLogLevel;
pub mod shared;
pub use deno_os::exit;
pub use shared::runtime;
pub struct UnstableGranularFlag {
@ -147,12 +147,6 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[
},
];
pub fn exit(code: i32) -> ! {
deno_telemetry::flush();
#[allow(clippy::disallowed_methods)]
std::process::exit(code);
}
#[cfg(test)]
mod test {
use super::*;

View file

@ -3,11 +3,9 @@
pub mod bootstrap;
pub mod fs_events;
pub mod http;
pub mod os;
pub mod permissions;
pub mod process;
pub mod runtime;
pub mod signal;
pub mod tty;
pub mod web_worker;
pub mod worker_host;

View file

@ -31,14 +31,13 @@ use deno_io::ChildStderrResource;
use deno_io::ChildStdinResource;
use deno_io::ChildStdoutResource;
use deno_io::IntoRawIoHandle;
use deno_os::SignalError;
use deno_permissions::PermissionsContainer;
use deno_permissions::RunQueryDescriptor;
use serde::Deserialize;
use serde::Serialize;
use tokio::process::Command;
use crate::ops::signal::SignalError;
pub const UNSTABLE_FEATURE_NAME: &str = "process";
#[derive(Copy, Clone, Eq, PartialEq, Deserialize)]
@ -296,7 +295,7 @@ impl TryFrom<ExitStatus> for ChildStatus {
success: false,
code: 128 + signal,
#[cfg(unix)]
signal: Some(crate::signal::signal_int_to_str(signal)?.to_string()),
signal: Some(deno_os::signal::signal_int_to_str(signal)?.to_string()),
#[cfg(not(unix))]
signal: None,
}
@ -1116,7 +1115,7 @@ mod deprecated {
#[cfg(unix)]
pub fn kill(pid: i32, signal: &str) -> Result<(), ProcessError> {
let signo = crate::signal::signal_str_to_int(signal)
let signo = deno_os::signal::signal_str_to_int(signal)
.map_err(SignalError::InvalidSignalStr)?;
use nix::sys::signal::kill as unix_kill;
use nix::sys::signal::Signal;
@ -1144,7 +1143,7 @@ mod deprecated {
if !matches!(signal, "SIGKILL" | "SIGTERM") {
Err(
SignalError::InvalidSignalStr(crate::signal::InvalidSignalStrError(
SignalError::InvalidSignalStr(deno_os::signal::InvalidSignalStrError(
signal.to_string(),
))
.into(),

View file

@ -42,10 +42,8 @@ extension!(runtime,
"06_util.js",
"10_permissions.js",
"11_workers.js",
"30_os.js",
"40_fs_events.js",
"40_process.js",
"40_signals.js",
"40_tty.js",
"41_prompt.js",
"90_deno_ns.js",

View file

@ -14,6 +14,8 @@ use deno_core::Extension;
use deno_http::DefaultHttpPropertyExtractor;
use deno_io::fs::FsError;
use deno_permissions::PermissionCheckError;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmResolver;
use crate::ops;
use crate::ops::bootstrap::SnapshotOptions;
@ -308,8 +310,11 @@ pub fn create_runtime_snapshot(
),
deno_io::deno_io::init_ops_and_esm(Default::default()),
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
deno_os::deno_os::init_ops_and_esm(Default::default()),
deno_node::deno_node::init_ops_and_esm::<
Permissions,
DenoInNpmPackageChecker,
NpmResolver<sys_traits::impls::RealSys>,
sys_traits::impls::RealSys,
>(None, fs.clone()),
runtime::init_ops_and_esm(),
@ -319,10 +324,8 @@ pub fn create_runtime_snapshot(
None,
),
ops::fs_events::deno_fs_events::init_ops(),
ops::os::deno_os::init_ops(Default::default()),
ops::permissions::deno_permissions::init_ops(),
ops::process::deno_process::init_ops(None),
ops::signal::deno_signal::init_ops(),
ops::tty::deno_tty::init_ops(),
ops::http::deno_http_runtime::init_ops(),
ops::bootstrap::deno_bootstrap::init_ops(Some(snapshot_options)),

View file

@ -54,6 +54,8 @@ use deno_web::JsMessageData;
use deno_web::MessagePort;
use deno_web::Transferable;
use log::debug;
use node_resolver::InNpmPackageChecker;
use node_resolver::NpmPackageFolderResolver;
use crate::inspector_server::InspectorServer;
use crate::ops;
@ -334,7 +336,11 @@ fn create_handles(
(internal_handle, external_handle)
}
pub struct WebWorkerServiceOptions<TExtNodeSys: ExtNodeSys + 'static> {
pub struct WebWorkerServiceOptions<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TExtNodeSys: ExtNodeSys + 'static,
> {
pub blob_store: Arc<BlobStore>,
pub broadcast_channel: InMemoryBroadcastChannel,
pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
@ -342,7 +348,13 @@ pub struct WebWorkerServiceOptions<TExtNodeSys: ExtNodeSys + 'static> {
pub fs: Arc<dyn FileSystem>,
pub maybe_inspector_server: Option<Arc<InspectorServer>>,
pub module_loader: Rc<dyn ModuleLoader>,
pub node_services: Option<NodeExtInitServices<TExtNodeSys>>,
pub node_services: Option<
NodeExtInitServices<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>,
>,
pub npm_process_state_provider: Option<NpmProcessStateProviderRc>,
pub permissions: PermissionsContainer,
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
@ -398,8 +410,16 @@ impl Drop for WebWorker {
}
impl WebWorker {
pub fn bootstrap_from_options<TExtNodeSys: ExtNodeSys + 'static>(
services: WebWorkerServiceOptions<TExtNodeSys>,
pub fn bootstrap_from_options<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TExtNodeSys: ExtNodeSys + 'static,
>(
services: WebWorkerServiceOptions<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>,
options: WebWorkerOptions,
) -> (Self, SendableWebWorkerHandle) {
let (mut worker, handle, bootstrap_options) =
@ -408,8 +428,16 @@ impl WebWorker {
(worker, handle)
}
fn from_options<TExtNodeSys: ExtNodeSys + 'static>(
services: WebWorkerServiceOptions<TExtNodeSys>,
fn from_options<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TExtNodeSys: ExtNodeSys + 'static,
>(
services: WebWorkerServiceOptions<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>,
mut options: WebWorkerOptions,
) -> (Self, SendableWebWorkerHandle, BootstrapOptions) {
deno_core::extension!(deno_permissions_web_worker,
@ -500,10 +528,13 @@ impl WebWorker {
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
services.fs.clone(),
),
deno_node::deno_node::init_ops_and_esm::<PermissionsContainer, TExtNodeSys>(
services.node_services,
services.fs,
),
deno_os::deno_os_worker::init_ops_and_esm(),
deno_node::deno_node::init_ops_and_esm::<
PermissionsContainer,
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>(services.node_services, services.fs),
// Runtime ops that are always initialized for WebWorkers
ops::runtime::deno_runtime::init_ops_and_esm(options.main_module.clone()),
ops::worker_host::deno_worker_host::init_ops_and_esm(
@ -511,12 +542,10 @@ impl WebWorker {
options.format_js_error_fn,
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::os::deno_os_worker::init_ops_and_esm(),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
ops::signal::deno_signal::init_ops_and_esm(),
ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(

View file

@ -3,8 +3,6 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
@ -40,11 +38,14 @@ use deno_io::Stdio;
use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::ExtNodeSys;
use deno_node::NodeExtInitServices;
use deno_os::ExitCode;
use deno_permissions::PermissionsContainer;
use deno_tls::RootCertStoreProvider;
use deno_tls::TlsKeys;
use deno_web::BlobStore;
use log::debug;
use node_resolver::InNpmPackageChecker;
use node_resolver::NpmPackageFolderResolver;
use crate::code_cache::CodeCache;
use crate::code_cache::CodeCacheType;
@ -95,19 +96,6 @@ pub fn validate_import_attributes_callback(
}
}
#[derive(Clone, Default)]
pub struct ExitCode(Arc<AtomicI32>);
impl ExitCode {
pub fn get(&self) -> i32 {
self.0.load(Relaxed)
}
pub fn set(&mut self, code: i32) {
self.0.store(code, Relaxed);
}
}
/// This worker is created and used by almost all
/// subcommands in Deno executable.
///
@ -128,7 +116,11 @@ pub struct MainWorker {
dispatch_process_exit_event_fn_global: v8::Global<v8::Function>,
}
pub struct WorkerServiceOptions<TExtNodeSys: ExtNodeSys> {
pub struct WorkerServiceOptions<
TInNpmPackageChecker: InNpmPackageChecker,
TNpmPackageFolderResolver: NpmPackageFolderResolver,
TExtNodeSys: ExtNodeSys,
> {
pub blob_store: Arc<BlobStore>,
pub broadcast_channel: InMemoryBroadcastChannel,
pub feature_checker: Arc<FeatureChecker>,
@ -139,7 +131,13 @@ pub struct WorkerServiceOptions<TExtNodeSys: ExtNodeSys> {
/// If not provided runtime will error if code being
/// executed tries to load modules.
pub module_loader: Rc<dyn ModuleLoader>,
pub node_services: Option<NodeExtInitServices<TExtNodeSys>>,
pub node_services: Option<
NodeExtInitServices<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>,
>,
pub npm_process_state_provider: Option<NpmProcessStateProviderRc>,
pub permissions: PermissionsContainer,
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
@ -300,9 +298,17 @@ pub fn create_op_metrics(
}
impl MainWorker {
pub fn bootstrap_from_options<TExtNodeSys: ExtNodeSys + 'static>(
pub fn bootstrap_from_options<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TExtNodeSys: ExtNodeSys + 'static,
>(
main_module: ModuleSpecifier,
services: WorkerServiceOptions<TExtNodeSys>,
services: WorkerServiceOptions<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>,
options: WorkerOptions,
) -> Self {
let (mut worker, bootstrap_options) =
@ -311,9 +317,17 @@ impl MainWorker {
worker
}
fn from_options<TExtNodeSys: ExtNodeSys + 'static>(
fn from_options<
TInNpmPackageChecker: InNpmPackageChecker + 'static,
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
TExtNodeSys: ExtNodeSys + 'static,
>(
main_module: ModuleSpecifier,
services: WorkerServiceOptions<TExtNodeSys>,
services: WorkerServiceOptions<
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>,
mut options: WorkerOptions,
) -> (Self, BootstrapOptions) {
deno_core::extension!(deno_permissions_worker,
@ -335,7 +349,7 @@ impl MainWorker {
// Permissions: many ops depend on this
let enable_testing_features = options.bootstrap.enable_testing_features;
let exit_code = ExitCode(Arc::new(AtomicI32::new(0)));
let exit_code = ExitCode::default();
let create_cache = options.cache_storage_dir.map(|storage_dir| {
let create_cache_fn = move || SqliteBackedCache::new(storage_dir.clone());
CreateCache(Arc::new(create_cache_fn))
@ -413,10 +427,13 @@ impl MainWorker {
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
services.fs.clone(),
),
deno_node::deno_node::init_ops_and_esm::<PermissionsContainer, TExtNodeSys>(
services.node_services,
services.fs,
),
deno_os::deno_os::init_ops_and_esm(exit_code.clone()),
deno_node::deno_node::init_ops_and_esm::<
PermissionsContainer,
TInNpmPackageChecker,
TNpmPackageFolderResolver,
TExtNodeSys,
>(services.node_services, services.fs),
// Ops from this crate
ops::runtime::deno_runtime::init_ops_and_esm(main_module.clone()),
ops::worker_host::deno_worker_host::init_ops_and_esm(
@ -424,12 +441,10 @@ impl MainWorker {
options.format_js_error_fn.clone(),
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::os::deno_os::init_ops_and_esm(exit_code.clone()),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
ops::signal::deno_signal::init_ops_and_esm(),
ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(

View file

@ -445,7 +445,7 @@ fn permissions_trace() {
test_util::assertions::assert_wildcard_match(&text, concat!(
"┏ ⚠️ Deno requests sys access to \"hostname\".\r\n",
"┠─ Requested by `Deno.hostname()` API.\r\n",
"┃ ├─ Object.hostname (ext:runtime/30_os.js:43:10)\r\n",
"┃ ├─ Object.hostname (ext:deno_os/30_os.js:43:10)\r\n",
"┃ ├─ foo (file://[WILDCARD]/run/permissions_trace.ts:2:8)\r\n",
"┃ ├─ bar (file://[WILDCARD]/run/permissions_trace.ts:6:3)\r\n",
"┃ └─ file://[WILDCARD]/run/permissions_trace.ts:9:1\r\n",

View file

@ -1,4 +1,4 @@
error: Failed to parse "lint" configuration
Caused by:
unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`
unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`, `plugins`

View file

@ -1,4 +1,4 @@
error: Failed to parse "lint" configuration
Caused by:
unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`
unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`, `plugins`

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -118,6 +118,45 @@ Deno.test("[node/fs filehandle.writeFile] Write to file", async function () {
assertEquals(decoder.decode(data), "hello world");
});
Deno.test(
"[node/fs filehandle.writev] Write array of buffers to file",
async function () {
const tempFile: string = await Deno.makeTempFile();
const fileHandle = await fs.open(tempFile, "w");
const buffer1 = Buffer.from("hello ");
const buffer2 = Buffer.from("world");
const res = await fileHandle.writev([buffer1, buffer2]);
const data = Deno.readFileSync(tempFile);
await Deno.remove(tempFile);
await fileHandle.close();
assertEquals(res.bytesWritten, 11);
assertEquals(decoder.decode(data), "hello world");
},
);
Deno.test(
"[node/fs filehandle.writev] Write array of buffers to file with position",
async function () {
const tempFile: string = await Deno.makeTempFile();
const fileHandle = await fs.open(tempFile, "w");
const buffer1 = Buffer.from("hello ");
const buffer2 = Buffer.from("world");
await fileHandle.writev([buffer1, buffer2], 0);
const buffer3 = Buffer.from("lorem ipsum");
await fileHandle.writev([buffer3], 6);
const data = Deno.readFileSync(tempFile);
await Deno.remove(tempFile);
await fileHandle.close();
assertEquals(decoder.decode(data), "hello lorem ipsum");
},
);
Deno.test(
"[node/fs filehandle.truncate] Truncate file with length",
async function () {
@ -217,3 +256,20 @@ Deno.test({
await fileHandle.close();
},
});
Deno.test({
name:
"[node/fs filehandle.utimes] Change the file system timestamps of the file",
async fn() {
const fileHandle = await fs.open(testData);
const atime = new Date();
const mtime = new Date(0);
await fileHandle.utimes(atime, mtime);
assertEquals(Deno.statSync(testData).atime!, atime);
assertEquals(Deno.statSync(testData).mtime!, mtime);
await fileHandle.close();
},
});

View file

@ -38,7 +38,7 @@
"ext:deno_node/_fs/_fs_stat.ts": "../ext/node/polyfills/_fs/_fs_stat.ts",
"ext:deno_node/_fs/_fs_watch.ts": "../ext/node/polyfills/_fs/_fs_watch.ts",
"ext:deno_node/_fs/_fs_write.mjs": "../ext/node/polyfills/_fs/_fs_write.mjs",
"ext:deno_node/_fs/_fs_writev.mjs": "../ext/node/polyfills/_fs/_fs_writev.mjs",
"ext:deno_node/_fs/_fs_writev.ts": "../ext/node/polyfills/_fs/_fs_writev.ts",
"ext:deno_node/_global.d.ts": "../ext/node/polyfills/_global.d.ts",
"node:_http_agent": "../ext/node/polyfills/_http_agent.mjs",
"node:_http_common": "../ext/node/polyfills/_http_common.ts",
@ -239,10 +239,10 @@
"ext:runtime/06_util.js": "../runtime/js/06_util.js",
"ext:runtime/10_permissions.js": "../runtime/js/10_permissions.js",
"ext:runtime/11_workers.js": "../runtime/js/11_workers.js",
"ext:runtime/30_os.js": "../runtime/js/30_os.js",
"ext:deno_os/30_os.js": "../ext/os/30_os.js",
"ext:runtime/40_fs_events.js": "../runtime/js/40_fs_events.js",
"ext:runtime/40_process.js": "../runtime/js/40_process.js",
"ext:runtime/40_signals.js": "../runtime/js/40_signals.js",
"ext:deno_os/40_signals.js": "../ext/os/40_signals.js",
"ext:runtime/40_tty.js": "../runtime/js/40_tty.js",
"ext:runtime/41_prompt.js": "../runtime/js/41_prompt.js",
"ext:runtime/90_deno_ns.js": "../runtime/js/90_deno_ns.js",