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 2024-12-11 09:54:01 +00:00
commit f8be309def
54 changed files with 639 additions and 129 deletions

View file

@ -245,7 +245,7 @@ pub struct InstallFlagsGlobal {
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum InstallKind {
pub enum InstallFlags {
Local(InstallFlagsLocal),
Global(InstallFlagsGlobal),
}
@ -257,11 +257,6 @@ pub enum InstallFlagsLocal {
Entrypoints(Vec<String>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InstallFlags {
pub kind: InstallKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct JSONReferenceFlags {
pub json: deno_core::serde_json::Value,
@ -600,6 +595,7 @@ pub struct UnstableConfig {
pub bare_node_builtins: bool,
pub detect_cjs: bool,
pub sloppy_imports: bool,
pub npm_lazy_caching: bool,
pub features: Vec<String>, // --unstabe-kv --unstable-cron
}
@ -2912,6 +2908,7 @@ To ignore linting on an entire file, you can add an ignore comment at the top of
.arg(watch_arg(false))
.arg(watch_exclude_arg())
.arg(no_clear_screen_arg())
.arg(allow_import_arg())
})
}
@ -4414,6 +4411,16 @@ impl CommandExt for Command {
})
.help_heading(UNSTABLE_HEADING)
.display_order(next_display_order())
).arg(
Arg::new("unstable-npm-lazy-caching")
.long("unstable-npm-lazy-caching")
.help("Enable unstable lazy caching of npm dependencies, downloading them only as needed (disabled: all npm packages in package.json are installed on startup; enabled: only npm packages that are actually referenced in an import are installed")
.env("DENO_UNSTABLE_NPM_LAZY_CACHING")
.value_parser(FalseyValueParser::new())
.action(ArgAction::SetTrue)
.hide(true)
.help_heading(UNSTABLE_HEADING)
.display_order(next_display_order()),
);
for granular_flag in crate::UNSTABLE_GRANULAR_FLAGS.iter() {
@ -4927,15 +4934,14 @@ fn install_parse(
let module_url = cmd_values.next().unwrap();
let args = cmd_values.collect();
flags.subcommand = DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Global(InstallFlagsGlobal {
flags.subcommand =
DenoSubcommand::Install(InstallFlags::Global(InstallFlagsGlobal {
name,
module_url,
args,
root,
force,
}),
});
}));
return Ok(());
}
@ -4944,22 +4950,19 @@ fn install_parse(
allow_scripts_arg_parse(flags, matches)?;
if matches.get_flag("entrypoint") {
let entrypoints = matches.remove_many::<String>("cmd").unwrap_or_default();
flags.subcommand = DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Local(InstallFlagsLocal::Entrypoints(
entrypoints.collect(),
)),
});
flags.subcommand = DenoSubcommand::Install(InstallFlags::Local(
InstallFlagsLocal::Entrypoints(entrypoints.collect()),
));
} else if let Some(add_files) = matches
.remove_many("cmd")
.map(|packages| add_parse_inner(matches, Some(packages)))
{
flags.subcommand = DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Local(InstallFlagsLocal::Add(add_files)),
})
flags.subcommand = DenoSubcommand::Install(InstallFlags::Local(
InstallFlagsLocal::Add(add_files),
))
} else {
flags.subcommand = DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Local(InstallFlagsLocal::TopLevel),
});
flags.subcommand =
DenoSubcommand::Install(InstallFlags::Local(InstallFlagsLocal::TopLevel));
}
Ok(())
}
@ -5091,6 +5094,7 @@ fn lint_parse(
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly);
ext_arg_parse(flags, matches);
config_args_parse(flags, matches);
allow_import_parse(flags, matches);
let files = match matches.remove_many::<String>("files") {
Some(f) => f.collect(),
@ -6004,6 +6008,8 @@ fn unstable_args_parse(
flags.unstable_config.detect_cjs = matches.get_flag("unstable-detect-cjs");
flags.unstable_config.sloppy_imports =
matches.get_flag("unstable-sloppy-imports");
flags.unstable_config.npm_lazy_caching =
matches.get_flag("unstable-npm-lazy-caching");
if matches!(cfg, UnstableArgsConfig::ResolutionAndRuntime) {
for granular_flag in crate::UNSTABLE_GRANULAR_FLAGS {
@ -7149,6 +7155,7 @@ mod tests {
let r = flags_from_vec(svec![
"deno",
"lint",
"--allow-import",
"--watch",
"script_1.ts",
"script_2.ts"
@ -7170,6 +7177,10 @@ mod tests {
compact: false,
watch: Some(Default::default()),
}),
permissions: PermissionFlags {
allow_import: Some(vec![]),
..Default::default()
},
..Flags::default()
}
);
@ -8607,15 +8618,15 @@ mod tests {
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Global(InstallFlagsGlobal {
subcommand: DenoSubcommand::Install(InstallFlags::Global(
InstallFlagsGlobal {
name: None,
module_url: "jsr:@std/http/file-server".to_string(),
args: vec![],
root: None,
force: false,
}),
}),
}
),),
..Flags::default()
}
);
@ -8629,15 +8640,15 @@ mod tests {
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Global(InstallFlagsGlobal {
subcommand: DenoSubcommand::Install(InstallFlags::Global(
InstallFlagsGlobal {
name: None,
module_url: "jsr:@std/http/file-server".to_string(),
args: vec![],
root: None,
force: false,
}),
}),
}
),),
..Flags::default()
}
);
@ -8650,15 +8661,15 @@ mod tests {
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Global(InstallFlagsGlobal {
subcommand: DenoSubcommand::Install(InstallFlags::Global(
InstallFlagsGlobal {
name: Some("file_server".to_string()),
module_url: "jsr:@std/http/file-server".to_string(),
args: svec!["foo", "bar"],
root: Some("/foo".to_string()),
force: true,
}),
}),
}
),),
import_map_path: Some("import_map.json".to_string()),
no_remote: true,
config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
@ -11212,9 +11223,9 @@ mod tests {
..Flags::default()
},
"install" => Flags {
subcommand: DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Local(InstallFlagsLocal::Add(flags)),
}),
subcommand: DenoSubcommand::Install(InstallFlags::Local(
InstallFlagsLocal::Add(flags),
)),
..Flags::default()
},
_ => unreachable!(),

View file

@ -20,7 +20,6 @@ use crate::Flags;
use crate::args::DenoSubcommand;
use crate::args::InstallFlags;
use crate::args::InstallKind;
use deno_lockfile::Lockfile;
@ -136,10 +135,8 @@ impl CliLockfile {
if flags.no_lock
|| matches!(
flags.subcommand,
DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Global(..),
..
}) | DenoSubcommand::Uninstall(_)
DenoSubcommand::Install(InstallFlags::Global(..))
| DenoSubcommand::Uninstall(_)
)
{
return Ok(None);

View file

@ -984,9 +984,7 @@ impl CliOptions {
match self.sub_command() {
DenoSubcommand::Cache(_) => GraphKind::All,
DenoSubcommand::Check(_) => GraphKind::TypesOnly,
DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Local(_),
}) => GraphKind::All,
DenoSubcommand::Install(InstallFlags::Local(_)) => GraphKind::All,
_ => self.type_check_mode().as_graph_kind(),
}
}
@ -1578,11 +1576,11 @@ impl CliOptions {
DenoSubcommand::Check(check_flags) => {
Some(files_to_urls(&check_flags.files))
}
DenoSubcommand::Install(InstallFlags {
kind: InstallKind::Global(flags),
}) => Url::parse(&flags.module_url)
.ok()
.map(|url| vec![Cow::Owned(url)]),
DenoSubcommand::Install(InstallFlags::Global(flags)) => {
Url::parse(&flags.module_url)
.ok()
.map(|url| vec![Cow::Owned(url)])
}
DenoSubcommand::Doc(DocFlags {
source_files: DocSourceFileFlag::Paths(paths),
..
@ -1718,6 +1716,7 @@ impl CliOptions {
"detect-cjs",
"fmt-component",
"fmt-sql",
"lazy-npm-caching",
])
.collect();
@ -1796,6 +1795,19 @@ impl CliOptions {
),
}
}
pub fn unstable_npm_lazy_caching(&self) -> bool {
self.flags.unstable_config.npm_lazy_caching
|| self.workspace().has_unstable("npm-lazy-caching")
}
pub fn default_npm_caching_strategy(&self) -> NpmCachingStrategy {
if self.flags.unstable_config.npm_lazy_caching {
NpmCachingStrategy::Lazy
} else {
NpmCachingStrategy::Eager
}
}
}
/// Resolves the path to use for a local node_modules folder.
@ -2010,6 +2022,13 @@ fn load_env_variables_from_env_file(filename: Option<&Vec<String>>) {
}
}
#[derive(Debug, Clone, Copy)]
pub enum NpmCachingStrategy {
Eager,
Lazy,
Manual,
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;

View file

@ -998,6 +998,7 @@ impl CliFactory {
cli_options.sub_command().clone(),
self.create_cli_main_worker_options()?,
self.cli_options()?.otel_config(),
self.cli_options()?.default_npm_caching_strategy(),
))
}
@ -1258,7 +1259,11 @@ impl WorkspaceFileContainer {
let module_graph_creator = entry.factory.module_graph_creator().await?;
let specifiers = entry.checked_specifiers().cloned().collect::<Vec<_>>();
let graph = module_graph_creator
.create_graph(graph_kind, specifiers.clone())
.create_graph(
graph_kind,
specifiers.clone(),
crate::graph_util::NpmCachingStrategy::Eager,
)
.await?;
module_graph_creator.graph_valid(&graph)?;
let dependent_specifiers = specifiers

View file

@ -4,6 +4,7 @@ use crate::args::config_to_deno_graph_workspace_member;
use crate::args::jsr_url;
use crate::args::CliLockfile;
use crate::args::CliOptions;
pub use crate::args::NpmCachingStrategy;
use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS;
use crate::cache;
use crate::cache::FetchCacher;
@ -215,6 +216,7 @@ pub struct CreateGraphOptions<'a> {
pub is_dynamic: bool,
/// Specify `None` to use the default CLI loader.
pub loader: Option<&'a mut dyn Loader>,
pub npm_caching: NpmCachingStrategy,
}
pub struct ModuleGraphCreator {
@ -243,10 +245,11 @@ impl ModuleGraphCreator {
&self,
graph_kind: GraphKind,
roots: Vec<ModuleSpecifier>,
npm_caching: NpmCachingStrategy,
) -> Result<deno_graph::ModuleGraph, AnyError> {
let mut cache = self.module_graph_builder.create_graph_loader();
self
.create_graph_with_loader(graph_kind, roots, &mut cache)
.create_graph_with_loader(graph_kind, roots, &mut cache, npm_caching)
.await
}
@ -255,6 +258,7 @@ impl ModuleGraphCreator {
graph_kind: GraphKind,
roots: Vec<ModuleSpecifier>,
loader: &mut dyn Loader,
npm_caching: NpmCachingStrategy,
) -> Result<ModuleGraph, AnyError> {
self
.create_graph_with_options(CreateGraphOptions {
@ -262,6 +266,7 @@ impl ModuleGraphCreator {
graph_kind,
roots,
loader: Some(loader),
npm_caching,
})
.await
}
@ -314,6 +319,7 @@ impl ModuleGraphCreator {
graph_kind: deno_graph::GraphKind::All,
roots,
loader: Some(&mut publish_loader),
npm_caching: self.options.default_npm_caching_strategy(),
})
.await?;
self.graph_valid(&graph)?;
@ -373,6 +379,7 @@ impl ModuleGraphCreator {
graph_kind,
roots,
loader: None,
npm_caching: self.options.default_npm_caching_strategy(),
})
.await?;
@ -563,7 +570,8 @@ impl ModuleGraphBuilder {
};
let cli_resolver = &self.resolver;
let graph_resolver = self.create_graph_resolver()?;
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver();
let graph_npm_resolver =
cli_resolver.create_graph_npm_resolver(options.npm_caching);
let maybe_file_watcher_reporter = self
.maybe_file_watcher_reporter
.as_ref()
@ -590,6 +598,7 @@ impl ModuleGraphBuilder {
resolver: Some(&graph_resolver),
locker: locker.as_mut().map(|l| l as _),
},
options.npm_caching,
)
.await
}
@ -600,6 +609,7 @@ impl ModuleGraphBuilder {
roots: Vec<ModuleSpecifier>,
loader: &'a mut dyn deno_graph::source::Loader,
options: deno_graph::BuildOptions<'a>,
npm_caching: NpmCachingStrategy,
) -> Result<(), AnyError> {
// ensure an "npm install" is done if the user has explicitly
// opted into using a node_modules directory
@ -610,7 +620,13 @@ impl ModuleGraphBuilder {
.unwrap_or(false)
{
if let Some(npm_resolver) = self.npm_resolver.as_managed() {
npm_resolver.ensure_top_level_package_json_install().await?;
let already_done =
npm_resolver.ensure_top_level_package_json_install().await?;
if !already_done && matches!(npm_caching, NpmCachingStrategy::Eager) {
npm_resolver
.cache_packages(crate::npm::PackageCaching::All)
.await?;
}
}
}
@ -699,7 +715,9 @@ impl ModuleGraphBuilder {
let parser = self.parsed_source_cache.as_capturing_parser();
let cli_resolver = &self.resolver;
let graph_resolver = self.create_graph_resolver()?;
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver();
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver(
self.cli_options.default_npm_caching_strategy(),
);
graph.build_fast_check_type_graph(
deno_graph::BuildFastCheckTypeGraphOptions {

View file

@ -270,7 +270,12 @@ impl LanguageServer {
open_docs: &open_docs,
};
let graph = module_graph_creator
.create_graph_with_loader(GraphKind::All, roots.clone(), &mut loader)
.create_graph_with_loader(
GraphKind::All,
roots.clone(),
&mut loader,
graph_util::NpmCachingStrategy::Eager,
)
.await?;
graph_util::graph_valid(
&graph,

View file

@ -133,7 +133,8 @@ impl LspScopeResolver {
cache.for_specifier(config_data.map(|d| d.scope.as_ref())),
config_data.and_then(|d| d.lockfile.clone()),
)));
let npm_graph_resolver = cli_resolver.create_graph_npm_resolver();
let npm_graph_resolver = cli_resolver
.create_graph_npm_resolver(crate::graph_util::NpmCachingStrategy::Eager);
let maybe_jsx_import_source_config =
config_data.and_then(|d| d.maybe_jsx_import_source_config());
let graph_imports = config_data
@ -343,7 +344,9 @@ impl LspResolver {
file_referrer: Option<&ModuleSpecifier>,
) -> WorkerCliNpmGraphResolver {
let resolver = self.get_scope_resolver(file_referrer);
resolver.resolver.create_graph_npm_resolver()
resolver
.resolver
.create_graph_npm_resolver(crate::graph_util::NpmCachingStrategy::Eager)
}
pub fn as_is_cjs_resolver(

View file

@ -157,6 +157,7 @@ impl ModuleLoadPreparer {
graph_kind: graph.graph_kind(),
roots: roots.to_vec(),
loader: Some(&mut cache),
npm_caching: self.options.default_npm_caching_strategy(),
},
)
.await?;

View file

@ -296,6 +296,12 @@ pub fn create_managed_in_npm_pkg_checker(
Arc::new(ManagedInNpmPackageChecker { root_dir })
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PackageCaching<'a> {
Only(Cow<'a, [PackageReq]>),
All,
}
/// 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 {
@ -420,19 +426,44 @@ impl ManagedCliNpmResolver {
/// Adds package requirements to the resolver and ensures everything is setup.
/// This includes setting up the `node_modules` directory, if applicable.
pub async fn add_package_reqs(
pub async fn add_and_cache_package_reqs(
&self,
packages: &[PackageReq],
) -> Result<(), AnyError> {
self
.add_package_reqs_raw(packages)
.add_package_reqs_raw(
packages,
Some(PackageCaching::Only(packages.into())),
)
.await
.dependencies_result
}
pub async fn add_package_reqs_raw(
pub async fn add_package_reqs_no_cache(
&self,
packages: &[PackageReq],
) -> Result<(), AnyError> {
self
.add_package_reqs_raw(packages, None)
.await
.dependencies_result
}
pub async fn add_package_reqs(
&self,
packages: &[PackageReq],
caching: PackageCaching<'_>,
) -> Result<(), AnyError> {
self
.add_package_reqs_raw(packages, Some(caching))
.await
.dependencies_result
}
pub async fn add_package_reqs_raw<'a>(
&self,
packages: &[PackageReq],
caching: Option<PackageCaching<'a>>,
) -> AddPkgReqsResult {
if packages.is_empty() {
return AddPkgReqsResult {
@ -449,7 +480,9 @@ impl ManagedCliNpmResolver {
}
}
if result.dependencies_result.is_ok() {
result.dependencies_result = self.cache_packages().await;
if let Some(caching) = caching {
result.dependencies_result = self.cache_packages(caching).await;
}
}
result
@ -491,16 +524,20 @@ impl ManagedCliNpmResolver {
pub async fn inject_synthetic_types_node_package(
&self,
) -> Result<(), AnyError> {
let reqs = &[PackageReq::from_str("@types/node").unwrap()];
// add and ensure this isn't added to the lockfile
self
.add_package_reqs(&[PackageReq::from_str("@types/node").unwrap()])
.add_package_reqs(reqs, PackageCaching::Only(reqs.into()))
.await?;
Ok(())
}
pub async fn cache_packages(&self) -> Result<(), AnyError> {
self.fs_resolver.cache_packages().await
pub async fn cache_packages(
&self,
caching: PackageCaching<'_>,
) -> Result<(), AnyError> {
self.fs_resolver.cache_packages(caching).await
}
pub fn resolve_pkg_folder_from_deno_module(
@ -545,18 +582,18 @@ impl ManagedCliNpmResolver {
/// Ensures that the top level `package.json` dependencies are installed.
/// This may set up the `node_modules` directory.
///
/// Returns `true` if any changes (such as caching packages) were made.
/// If this returns `false`, `node_modules` has _not_ been set up.
/// Returns `true` if the top level packages are already installed. A
/// return value of `false` means that new packages were added to the NPM resolution.
pub async fn ensure_top_level_package_json_install(
&self,
) -> Result<bool, AnyError> {
if !self.top_level_install_flag.raise() {
return Ok(false); // already did this
return Ok(true); // already did this
}
let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs();
if pkg_json_remote_pkgs.is_empty() {
return Ok(false);
return Ok(true);
}
// check if something needs resolving before bothering to load all
@ -570,14 +607,16 @@ impl ManagedCliNpmResolver {
log::debug!(
"All package.json deps resolvable. Skipping top level install."
);
return Ok(false); // everything is already resolvable
return Ok(true); // everything is already resolvable
}
let pkg_reqs = pkg_json_remote_pkgs
.iter()
.map(|pkg| pkg.req.clone())
.collect::<Vec<_>>();
self.add_package_reqs(&pkg_reqs).await.map(|_| true)
self.add_package_reqs_no_cache(&pkg_reqs).await?;
Ok(false)
}
pub async fn cache_package_info(

View file

@ -255,6 +255,10 @@ impl NpmResolution {
.read()
.as_valid_serialized_for_system(system_info)
}
pub fn subset(&self, package_reqs: &[PackageReq]) -> NpmResolutionSnapshot {
self.snapshot.read().subset(package_reqs)
}
}
async fn add_package_reqs_to_snapshot(

View file

@ -11,6 +11,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use std::sync::Mutex;
use super::super::PackageCaching;
use async_trait::async_trait;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::Context;
@ -57,7 +58,10 @@ pub trait NpmPackageFsResolver: Send + Sync {
specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageCacheFolderId>, AnyError>;
async fn cache_packages(&self) -> Result<(), AnyError>;
async fn cache_packages<'a>(
&self,
caching: PackageCaching<'a>,
) -> Result<(), AnyError>;
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
fn ensure_read_permission<'a>(

View file

@ -8,6 +8,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use crate::colors;
use crate::npm::managed::PackageCaching;
use crate::npm::CliNpmCache;
use crate::npm::CliNpmTarballCache;
use async_trait::async_trait;
@ -150,10 +151,19 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
)
}
async fn cache_packages(&self) -> Result<(), AnyError> {
let package_partitions = self
.resolution
.all_system_packages_partitioned(&self.system_info);
async fn cache_packages<'a>(
&self,
caching: PackageCaching<'a>,
) -> Result<(), AnyError> {
let package_partitions = match caching {
PackageCaching::All => self
.resolution
.all_system_packages_partitioned(&self.system_info),
PackageCaching::Only(reqs) => self
.resolution
.subset(&reqs)
.all_system_packages_partitioned(&self.system_info),
};
cache_packages(&package_partitions.packages, &self.tarball_cache).await?;
// create the copy package folders

View file

@ -17,6 +17,7 @@ use std::sync::Arc;
use crate::args::LifecycleScriptsConfig;
use crate::colors;
use crate::npm::managed::PackageCaching;
use crate::npm::CliNpmCache;
use crate::npm::CliNpmTarballCache;
use async_trait::async_trait;
@ -253,9 +254,16 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
))
}
async fn cache_packages(&self) -> Result<(), AnyError> {
async fn cache_packages<'a>(
&self,
caching: PackageCaching<'a>,
) -> Result<(), AnyError> {
let snapshot = match caching {
PackageCaching::All => self.resolution.snapshot(),
PackageCaching::Only(reqs) => self.resolution.subset(&reqs),
};
sync_resolution_with_fs(
&self.resolution.snapshot(),
&snapshot,
&self.cache,
&self.npm_install_deps_provider,
&self.progress_bar,

View file

@ -41,6 +41,7 @@ pub use self::managed::CliManagedInNpmPkgCheckerCreateOptions;
pub use self::managed::CliManagedNpmResolverCreateOptions;
pub use self::managed::CliNpmResolverManagedSnapshotOption;
pub use self::managed::ManagedCliNpmResolver;
pub use self::managed::PackageCaching;
pub type CliNpmTarballCache = deno_npm_cache::TarballCache<CliNpmCacheEnv>;
pub type CliNpmCache = deno_npm_cache::NpmCache<CliNpmCacheEnv>;

View file

@ -32,6 +32,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use thiserror::Error;
use crate::args::NpmCachingStrategy;
use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS;
use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver;
@ -240,11 +241,15 @@ impl CliResolver {
// todo(dsherret): move this off CliResolver as CliResolver is acting
// like a factory by doing this (it's beyond its responsibility)
pub fn create_graph_npm_resolver(&self) -> WorkerCliNpmGraphResolver {
pub fn create_graph_npm_resolver(
&self,
npm_caching: NpmCachingStrategy,
) -> WorkerCliNpmGraphResolver {
WorkerCliNpmGraphResolver {
npm_resolver: self.npm_resolver.as_ref(),
found_package_json_dep_flag: &self.found_package_json_dep_flag,
bare_node_builtins_enabled: self.bare_node_builtins_enabled,
npm_caching,
}
}
@ -304,6 +309,7 @@ pub struct WorkerCliNpmGraphResolver<'a> {
npm_resolver: Option<&'a Arc<dyn CliNpmResolver>>,
found_package_json_dep_flag: &'a AtomicFlag,
bare_node_builtins_enabled: bool,
npm_caching: NpmCachingStrategy,
}
#[async_trait(?Send)]
@ -373,7 +379,20 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> {
Ok(())
};
let result = npm_resolver.add_package_reqs_raw(package_reqs).await;
let result = npm_resolver
.add_package_reqs_raw(
package_reqs,
match self.npm_caching {
NpmCachingStrategy::Eager => {
Some(crate::npm::PackageCaching::All)
}
NpmCachingStrategy::Lazy => {
Some(crate::npm::PackageCaching::Only(package_reqs.into()))
}
NpmCachingStrategy::Manual => None,
},
)
.await;
NpmResolvePkgReqsResult {
results: result

View file

@ -291,7 +291,7 @@
"type": "array",
"description": "List of tag names that will be run. Empty list disables all tags and will only use rules from `include`.",
"items": {
"$ref": "https://raw.githubusercontent.com/denoland/deno_lint/main/schemas/tags.v1.json"
"$ref": "lint-tags.v1.json"
},
"minItems": 0,
"uniqueItems": true
@ -300,7 +300,7 @@
"type": "array",
"description": "List of rule names that will be excluded from configured tag sets. If the same rule is in `include` it will be run.",
"items": {
"$ref": "https://raw.githubusercontent.com/denoland/deno_lint/main/schemas/rules.v1.json"
"$ref": "lint-rules.v1.json"
},
"minItems": 0,
"uniqueItems": true
@ -309,7 +309,7 @@
"type": "array",
"description": "List of rule names that will be run. Even if the same rule is in `exclude` it will be run.",
"items": {
"$ref": "https://raw.githubusercontent.com/denoland/deno_lint/main/schemas/rules.v1.json"
"$ref": "lint-rules.v1.json"
},
"minItems": 0,
"uniqueItems": true

View file

@ -0,0 +1,112 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"enum": [
"adjacent-overload-signatures",
"ban-ts-comment",
"ban-types",
"ban-unknown-rule-code",
"ban-untagged-ignore",
"ban-untagged-todo",
"ban-unused-ignore",
"camelcase",
"constructor-super",
"default-param-last",
"eqeqeq",
"explicit-function-return-type",
"explicit-module-boundary-types",
"for-direction",
"fresh-handler-export",
"fresh-server-event-handlers",
"getter-return",
"guard-for-in",
"no-array-constructor",
"no-async-promise-executor",
"no-await-in-loop",
"no-await-in-sync-fn",
"no-boolean-literal-for-arguments",
"no-case-declarations",
"no-class-assign",
"no-compare-neg-zero",
"no-cond-assign",
"no-console",
"no-const-assign",
"no-constant-condition",
"no-control-regex",
"no-debugger",
"no-delete-var",
"no-deprecated-deno-api",
"no-dupe-args",
"no-dupe-class-members",
"no-dupe-else-if",
"no-dupe-keys",
"no-duplicate-case",
"no-empty",
"no-empty-character-class",
"no-empty-enum",
"no-empty-interface",
"no-empty-pattern",
"no-eval",
"no-ex-assign",
"no-explicit-any",
"no-external-import",
"no-extra-boolean-cast",
"no-extra-non-null-assertion",
"no-fallthrough",
"no-func-assign",
"no-global-assign",
"no-implicit-declare-namespace-export",
"no-import-assertions",
"no-import-assign",
"no-inferrable-types",
"no-inner-declarations",
"no-invalid-regexp",
"no-invalid-triple-slash-reference",
"no-irregular-whitespace",
"no-misused-new",
"no-namespace",
"no-new-symbol",
"no-node-globals",
"no-non-null-asserted-optional-chain",
"no-non-null-assertion",
"no-obj-calls",
"no-octal",
"no-process-globals",
"no-prototype-builtins",
"no-redeclare",
"no-regex-spaces",
"no-self-assign",
"no-self-compare",
"no-setter-return",
"no-shadow-restricted-names",
"no-sloppy-imports",
"no-slow-types",
"no-sparse-arrays",
"no-sync-fn-in-async-fn",
"no-this-alias",
"no-this-before-super",
"no-throw-literal",
"no-top-level-await",
"no-undef",
"no-unreachable",
"no-unsafe-finally",
"no-unsafe-negation",
"no-unused-labels",
"no-unused-vars",
"no-var",
"no-window",
"no-window-prefix",
"no-with",
"prefer-as-const",
"prefer-ascii",
"prefer-const",
"prefer-namespace-keyword",
"prefer-primordials",
"require-await",
"require-yield",
"single-var-declarator",
"triple-slash-reference",
"use-isnan",
"valid-typeof",
"verbatim-module-syntax"
]
}

View file

@ -0,0 +1,4 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"enum": ["fresh", "jsr", "jsx", "react", "recommended"]
}

View file

@ -779,6 +779,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
detect_cjs: self.cli_options.unstable_detect_cjs(),
sloppy_imports: self.cli_options.unstable_sloppy_imports(),
features: self.cli_options.unstable_features(),
npm_lazy_caching: self.cli_options.unstable_npm_lazy_caching(),
},
otel_config: self.cli_options.otel_config(),
};

View file

@ -924,6 +924,7 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
serve_host: None,
},
metadata.otel_config,
crate::args::NpmCachingStrategy::Lazy,
);
// Initialize v8 once from the main thread.

View file

@ -69,7 +69,11 @@ pub async fn compile(
// create a module graph with types information in it. We don't want to
// store that in the binary so create a code only module graph from scratch.
module_graph_creator
.create_graph(GraphKind::CodeOnly, module_roots)
.create_graph(
GraphKind::CodeOnly,
module_roots,
crate::graph_util::NpmCachingStrategy::Eager,
)
.await?
} else {
graph

View file

@ -131,7 +131,11 @@ pub async fn doc(
|_| true,
)?;
let graph = module_graph_creator
.create_graph(GraphKind::TypesOnly, module_specifiers.clone())
.create_graph(
GraphKind::TypesOnly,
module_specifiers.clone(),
crate::graph_util::NpmCachingStrategy::Eager,
)
.await?;
graph_exit_integrity_errors(&graph);

View file

@ -123,7 +123,12 @@ pub async fn info(
let mut loader = module_graph_builder.create_graph_loader();
loader.enable_loading_cache_info(); // for displaying the cache information
let graph = module_graph_creator
.create_graph_with_loader(GraphKind::All, vec![specifier], &mut loader)
.create_graph_with_loader(
GraphKind::All,
vec![specifier],
&mut loader,
crate::graph_util::NpmCachingStrategy::Eager,
)
.await?;
// write out the lockfile if there is one

View file

@ -9,7 +9,6 @@ use crate::args::Flags;
use crate::args::InstallFlags;
use crate::args::InstallFlagsGlobal;
use crate::args::InstallFlagsLocal;
use crate::args::InstallKind;
use crate::args::TypeCheckMode;
use crate::args::UninstallFlags;
use crate::args::UninstallKind;
@ -339,11 +338,11 @@ pub async fn install_command(
flags: Arc<Flags>,
install_flags: InstallFlags,
) -> Result<(), AnyError> {
match install_flags.kind {
InstallKind::Global(global_flags) => {
match install_flags {
InstallFlags::Global(global_flags) => {
install_global(flags, global_flags).await
}
InstallKind::Local(local_flags) => {
InstallFlags::Local(local_flags) => {
if let InstallFlagsLocal::Add(add_flags) = &local_flags {
check_if_installs_a_single_package_globally(Some(add_flags))?;
}

View file

@ -556,3 +556,68 @@ struct LintError {
file_path: String,
message: String,
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use serde::Deserialize;
use test_util as util;
#[derive(Serialize, Deserialize)]
struct RulesSchema {
#[serde(rename = "$schema")]
schema: String,
#[serde(rename = "enum")]
rules: Vec<String>,
}
fn get_all_rules() -> Vec<String> {
let rule_provider = LintRuleProvider::new(None, None);
let configured_rules =
rule_provider.resolve_lint_rules(Default::default(), None);
let mut all_rules = configured_rules
.all_rule_codes
.into_iter()
.map(|s| s.to_string())
.collect::<Vec<String>>();
all_rules.sort();
all_rules
}
// TODO(bartlomieju): do the same for tags, once https://github.com/denoland/deno/pull/27162 lands
#[test]
fn all_lint_rules_are_listed_in_schema_file() {
let all_rules = get_all_rules();
let rules_schema_path =
util::root_path().join("cli/schemas/lint-rules.v1.json");
let rules_schema_file =
std::fs::read_to_string(&rules_schema_path).unwrap();
let schema: RulesSchema = serde_json::from_str(&rules_schema_file).unwrap();
const UPDATE_ENV_VAR_NAME: &str = "UPDATE_EXPECTED";
if std::env::var(UPDATE_ENV_VAR_NAME).ok().is_none() {
assert_eq!(
schema.rules, all_rules,
"Lint rules schema file not up to date. Run again with {}=1 to update the expected output",
UPDATE_ENV_VAR_NAME
);
return;
}
std::fs::write(
&rules_schema_path,
serde_json::to_string_pretty(&RulesSchema {
schema: schema.schema,
rules: all_rules,
})
.unwrap(),
)
.unwrap();
}
}

View file

@ -6,6 +6,7 @@ use std::sync::Arc;
use crate::factory::CliFactory;
use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
use crate::graph_util::CreateGraphOptions;
use deno_core::error::AnyError;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::futures::StreamExt;
@ -18,18 +19,16 @@ pub async fn cache_top_level_deps(
) -> Result<(), AnyError> {
let npm_resolver = factory.npm_resolver().await?;
let cli_options = factory.cli_options()?;
let root_permissions = factory.root_permissions_container()?;
if let Some(npm_resolver) = npm_resolver.as_managed() {
if !npm_resolver.ensure_top_level_package_json_install().await? {
if let Some(lockfile) = cli_options.maybe_lockfile() {
lockfile.error_if_changed()?;
}
npm_resolver.cache_packages().await?;
npm_resolver.ensure_top_level_package_json_install().await?;
if let Some(lockfile) = cli_options.maybe_lockfile() {
lockfile.error_if_changed()?;
}
}
// cache as many entries in the import map as we can
let resolver = factory.workspace_resolver().await?;
let mut maybe_graph_error = Ok(());
if let Some(import_map) = resolver.maybe_import_map() {
let jsr_resolver = if let Some(resolver) = jsr_resolver {
resolver
@ -122,19 +121,29 @@ pub async fn cache_top_level_deps(
}
drop(info_futures);
factory
.module_load_preparer()
.await?
.prepare_module_load(
let graph_builder = factory.module_graph_builder().await?;
graph_builder
.build_graph_with_npm_resolution(
graph,
&roots,
false,
deno_config::deno_json::TsTypeLib::DenoWorker,
root_permissions.clone(),
None,
CreateGraphOptions {
loader: None,
graph_kind: graph.graph_kind(),
is_dynamic: false,
roots: roots.clone(),
npm_caching: crate::graph_util::NpmCachingStrategy::Manual,
},
)
.await?;
maybe_graph_error = graph_builder.graph_roots_valid(graph, &roots);
}
if let Some(npm_resolver) = npm_resolver.as_managed() {
npm_resolver
.cache_packages(crate::npm::PackageCaching::All)
.await?;
}
maybe_graph_error?;
Ok(())
}

View file

@ -3,6 +3,7 @@
use std::collections::HashSet;
use std::sync::Arc;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
@ -100,15 +101,14 @@ fn print_outdated_table(packages: &[OutdatedPackage]) {
println!("{package_fill}{current_fill}{update_fill}{latest_fill}",);
}
#[allow(clippy::print_stdout)]
fn print_suggestion(compatible: bool) {
println!();
log::info!("");
let (cmd, txt) = if compatible {
("", "compatible")
} else {
(" --latest", "available")
};
println!(
log::info!(
"{}",
color_print::cformat!(
"<p(245)>Run</> <u>deno outdated --update{}</> <p(245)>to update to the latest {} versions,</>\n<p(245)>or</> <u>deno outdated --help</> <p(245)>for more information.</>",
@ -198,6 +198,15 @@ pub async fn outdated(
let jsr_fetch_resolver =
Arc::new(JsrFetchResolver::new(file_fetcher.clone()));
if !cli_options.start_dir.has_deno_json()
&& !cli_options.start_dir.has_pkg_json()
{
bail!(
"No deno.json or package.json in \"{}\".",
cli_options.initial_cwd().display(),
);
}
let args = dep_manager_args(
&factory,
cli_options,

View file

@ -727,7 +727,9 @@ impl ReplSession {
let has_node_specifier =
resolved_imports.iter().any(|url| url.scheme() == "node");
if !npm_imports.is_empty() || has_node_specifier {
npm_resolver.add_package_reqs(&npm_imports).await?;
npm_resolver
.add_and_cache_package_reqs(&npm_imports)
.await?;
// prevent messages in the repl about @types/node not being cached
if has_node_specifier {

View file

@ -198,13 +198,23 @@ pub async fn eval_command(
}
pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> {
let cli_options = factory.cli_options()?;
// ensure an "npm install" is done if the user has explicitly
// opted into using a managed node_modules directory
if factory.cli_options()?.node_modules_dir()?
== Some(NodeModulesDirMode::Auto)
{
if cli_options.node_modules_dir()? == Some(NodeModulesDirMode::Auto) {
if let Some(npm_resolver) = factory.npm_resolver().await?.as_managed() {
npm_resolver.ensure_top_level_package_json_install().await?;
let already_done =
npm_resolver.ensure_top_level_package_json_install().await?;
if !already_done
&& matches!(
cli_options.default_npm_caching_strategy(),
crate::graph_util::NpmCachingStrategy::Eager
)
{
npm_resolver
.cache_packages(crate::npm::PackageCaching::All)
.await?;
}
}
}
Ok(())

View file

@ -440,6 +440,13 @@ impl<'a> TaskRunner<'a> {
kill_signal: KillSignal,
argv: &'a [String],
) -> Result<i32, deno_core::anyhow::Error> {
if let Some(npm_resolver) = self.npm_resolver.as_managed() {
npm_resolver.ensure_top_level_package_json_install().await?;
npm_resolver
.cache_packages(crate::npm::PackageCaching::All)
.await?;
}
let cwd = match &self.task_flags.cwd {
Some(path) => canonicalize_path(&PathBuf::from(path))
.context("failed canonicalizing --cwd")?,
@ -450,6 +457,7 @@ impl<'a> TaskRunner<'a> {
self.npm_resolver,
self.node_resolver,
)?;
self
.run_single(RunSingleOptions {
task_name,
@ -473,6 +481,9 @@ impl<'a> TaskRunner<'a> {
// ensure the npm packages are installed if using a managed resolver
if let Some(npm_resolver) = self.npm_resolver.as_managed() {
npm_resolver.ensure_top_level_package_json_install().await?;
npm_resolver
.cache_packages(crate::npm::PackageCaching::All)
.await?;
}
let cwd = match &self.task_flags.cwd {
@ -492,6 +503,7 @@ impl<'a> TaskRunner<'a> {
self.npm_resolver,
self.node_resolver,
)?;
for task_name in &task_names {
if let Some(script) = scripts.get(task_name) {
let exit_code = self

View file

@ -50,6 +50,7 @@ use tokio::select;
use crate::args::CliLockfile;
use crate::args::DenoSubcommand;
use crate::args::NpmCachingStrategy;
use crate::args::StorageKeyResolver;
use crate::errors;
use crate::npm::CliNpmResolver;
@ -154,6 +155,7 @@ struct SharedWorkerState {
options: CliMainWorkerOptions,
subcommand: DenoSubcommand,
otel_config: Option<OtelConfig>, // `None` means OpenTelemetry is disabled.
default_npm_caching_strategy: NpmCachingStrategy,
}
impl SharedWorkerState {
@ -425,6 +427,7 @@ impl CliMainWorkerFactory {
subcommand: DenoSubcommand,
options: CliMainWorkerOptions,
otel_config: Option<OtelConfig>,
default_npm_caching_strategy: NpmCachingStrategy,
) -> Self {
Self {
shared: Arc::new(SharedWorkerState {
@ -448,6 +451,7 @@ impl CliMainWorkerFactory {
options,
subcommand,
otel_config,
default_npm_caching_strategy,
}),
}
}
@ -487,8 +491,19 @@ impl CliMainWorkerFactory {
NpmPackageReqReference::from_specifier(&main_module)
{
if let Some(npm_resolver) = shared.npm_resolver.as_managed() {
let reqs = &[package_ref.req().clone()];
npm_resolver
.add_package_reqs(&[package_ref.req().clone()])
.add_package_reqs(
reqs,
if matches!(
shared.default_npm_caching_strategy,
NpmCachingStrategy::Lazy
) {
crate::npm::PackageCaching::Only(reqs.into())
} else {
crate::npm::PackageCaching::All
},
)
.await?;
}

View file

@ -3,23 +3,9 @@
use deno_lockfile::NewLockfileOptions;
use deno_semver::jsr::JsrDepPackageReq;
use test_util as util;
use test_util::itest;
use util::TestContext;
use util::TestContextBuilder;
itest!(check_all {
args: "check --allow-import --quiet --all check/all/check_all.ts",
output: "check/all/check_all.out",
http_server: true,
exit_code: 1,
});
itest!(check_all_local {
args: "check --allow-import --quiet check/all/check_all.ts",
output_str: Some(""),
http_server: true,
});
#[test]
fn cache_switching_config_then_no_config() {
let context = TestContext::default();

View file

@ -0,0 +1,5 @@
{
"args": "check --allow-import --quiet --all check_all.ts",
"output": "check_all.out",
"exitCode": 1
}

View file

@ -0,0 +1,5 @@
{
"args": "check --allow-import --quiet check_all_local.ts",
"output": "",
"exitCode": 0
}

View file

@ -0,0 +1,3 @@
import * as a from "http://localhost:4545/subdir/type_error.ts";
console.log(a.a);

View file

@ -0,0 +1,13 @@
{
"tempDir": true,
"steps": [
{
"args": "install --unstable-npm-lazy-caching --entrypoint main.ts",
"output": "install-entrypoint.out"
},
{
"args": "install",
"output": "install.out"
}
]
}

View file

@ -0,0 +1,6 @@
[UNORDERED_START]
Download http://localhost:4260/@denotest%2fadd
Download http://localhost:4260/@denotest%2fsay-hello
Download http://localhost:4260/@denotest/add/1.0.0.tgz
[UNORDERED_END]
Initialize @denotest/add@1.0.0

View file

@ -0,0 +1,2 @@
Download http://localhost:4260/@denotest/say-hello/1.0.0.tgz
Initialize @denotest/say-hello@1.0.0

View file

@ -0,0 +1,3 @@
import { add } from "@denotest/add";
console.log(add(1, 2));

View file

@ -0,0 +1,6 @@
{
"dependencies": {
"@denotest/add": "1.0.0",
"@denotest/say-hello": "1.0.0"
}
}

View file

@ -1,4 +1,5 @@
{
"tempDir": true,
"tests": {
"jsx_import_source_error": {
"args": "run --config jsx/deno-jsx-error.jsonc --check jsx_import_source_no_pragma.tsx",

View file

@ -0,0 +1,9 @@
{
"tempDir": true,
"steps": [
{
"args": "run --unstable-npm-lazy-caching -A main.ts",
"output": "main.out"
}
]
}

View file

@ -0,0 +1,3 @@
{
"nodeModulesDir": "auto"
}

View file

@ -0,0 +1,7 @@
[UNORDERED_START]
Download http://localhost:4260/@denotest%2fadd
Download http://localhost:4260/@denotest%2fsay-hello
Download http://localhost:4260/@denotest/add/1.0.0.tgz
[UNORDERED_END]
Initialize @denotest/add@1.0.0
3

View file

@ -0,0 +1,3 @@
import { add } from "@denotest/add";
console.log(add(1, 2));

View file

@ -0,0 +1,6 @@
{
"dependencies": {
"@denotest/add": "1.0.0",
"@denotest/say-hello": "1.0.0"
}
}

View file

@ -26,6 +26,16 @@
{
"args": "outdated",
"output": "outdated.out"
},
{
// Filtering that matches nothing, should exit cleanly
"args": "outdated foobar",
"output": ""
},
{
// Respect `--quiet flag and don't print hint how to update
"args": "outdated --quiet",
"output": "outdated_quiet.out"
}
]
},
@ -38,6 +48,11 @@
{
"args": "outdated --compatible",
"output": "outdated_compatible.out"
},
{
// Filtering that matches nothing, should exit cleanly
"args": "outdated --compatible foobar",
"output": ""
}
]
},

View file

@ -0,0 +1,15 @@
┌────────────────────────────────────────────────┬─────────┬────────┬────────┐
│ Package │ Current │ Update │ Latest │
├────────────────────────────────────────────────┼─────────┼────────┼────────┤
│ jsr:@denotest/multiple-exports │ 0.2.0 │ 0.2.0 │ 1.0.0 │
├────────────────────────────────────────────────┼─────────┼────────┼────────┤
│ jsr:@denotest/subtract │ 0.2.0 │ 0.2.0 │ 1.0.0 │
├────────────────────────────────────────────────┼─────────┼────────┼────────┤
│ jsr:@denotest/add │ 0.2.0 │ 0.2.1 │ 1.0.0 │
├────────────────────────────────────────────────┼─────────┼────────┼────────┤
│ npm:@denotest/has-patch-versions │ 0.1.0 │ 0.1.1 │ 0.2.0 │
├────────────────────────────────────────────────┼─────────┼────────┼────────┤
│ npm:@denotest/bin │ 0.6.0 │ 0.6.0 │ 1.0.0 │
├────────────────────────────────────────────────┼─────────┼────────┼────────┤
│ npm:@denotest/breaking-change-between-versions │ 1.0.0 │ 1.0.0 │ 2.0.0 │
└────────────────────────────────────────────────┴─────────┴────────┴────────┘

View file

@ -26,6 +26,11 @@
{
"args": "outdated",
"output": "print_outdated/root.out"
},
{
// Filtering that matches nothing, should exit cleanly
"args": "outdated foobar",
"output": ""
}
]
},
@ -38,6 +43,11 @@
{
"args": "outdated --recursive",
"output": "print_outdated/recursive.out"
},
{
// Filtering that matches nothing, should exit cleanly
"args": "outdated foobar",
"output": ""
}
]
},

View file

@ -0,0 +1,6 @@
{
"tempDir": true,
"args": "outdated",
"exitCode": 1,
"output": "error: No deno.json or package.json in \"[WILDLINE]\".\n"
}

View file

@ -25,6 +25,11 @@
{
"args": "outdated",
"output": "outdated.out"
},
{
// Filtering that matches nothing, should exit cleanly
"args": "outdated foobar",
"output": ""
}
]
},
@ -37,6 +42,11 @@
{
"args": "outdated --compatible",
"output": "outdated_compatible.out"
},
{
// Filtering that matches nothing, should exit cleanly
"args": "outdated --compatible foobar",
"output": ""
}
]
},

View file

@ -211,7 +211,7 @@ async function ensureNoNewITests() {
"bench_tests.rs": 0,
"cache_tests.rs": 0,
"cert_tests.rs": 0,
"check_tests.rs": 2,
"check_tests.rs": 0,
"compile_tests.rs": 0,
"coverage_tests.rs": 0,
"eval_tests.rs": 0,