summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-11-13 10:10:09 -0500
committerGitHub <noreply@github.com>2024-11-13 15:10:09 +0000
commitf091d1ad69b4e5217ae3272b641171781a372c4f (patch)
tree4ef4f90ec8a6b5c977efb187449f8c59c45de5e1
parent6a4c6d83bacf5f03628a494778a30bce970f7cbc (diff)
feat(node): stabilize detecting if CJS via `"type": "commonjs"` in a package.json (#26439)
This will respect `"type": "commonjs"` in a package.json to determine if `.js`/`.jsx`/`.ts`/.tsx` files are CJS or ESM. If the file is found to be ESM it will be loaded as ESM though.
-rw-r--r--cli/args/flags.rs2
-rw-r--r--cli/args/mod.rs70
-rw-r--r--cli/emit.rs8
-rw-r--r--cli/factory.rs25
-rw-r--r--cli/graph_util.rs79
-rw-r--r--cli/lsp/analysis.rs37
-rw-r--r--cli/lsp/completions.rs22
-rw-r--r--cli/lsp/config.rs12
-rw-r--r--cli/lsp/diagnostics.rs1
-rw-r--r--cli/lsp/documents.rs136
-rw-r--r--cli/lsp/language_server.rs40
-rw-r--r--cli/lsp/repl.rs2
-rw-r--r--cli/lsp/resolver.rs287
-rw-r--r--cli/lsp/tsc.rs34
-rw-r--r--cli/module_loader.rs79
-rw-r--r--cli/node.rs12
-rw-r--r--cli/resolver.rs271
-rw-r--r--cli/schemas/config-file.v1.json1
-rw-r--r--cli/standalone/binary.rs1
-rw-r--r--cli/standalone/mod.rs40
-rw-r--r--cli/tools/coverage/mod.rs2
-rw-r--r--cli/tools/installer.rs1
-rw-r--r--cli/tools/jupyter/mod.rs2
-rw-r--r--cli/tools/lint/mod.rs2
-rw-r--r--cli/tools/lint/rules/no_sloppy_imports.rs1
-rw-r--r--cli/tools/repl/session.rs17
-rw-r--r--cli/tools/run/hmr.rs7
-rw-r--r--cli/tsc/99_main_compiler.js41
-rw-r--r--cli/tsc/mod.rs78
-rw-r--r--cli/worker.rs2
-rw-r--r--ext/node/lib.rs7
-rw-r--r--ext/node/ops/require.rs44
-rw-r--r--ext/node/polyfills/01_require.js31
-rw-r--r--ext/node/polyfills/process.ts2
-rw-r--r--resolvers/node/package_json.rs4
-rw-r--r--resolvers/node/resolution.rs23
-rw-r--r--runtime/fmt_errors.rs7
-rw-r--r--runtime/web_worker.rs7
-rw-r--r--tests/integration/lsp_tests.rs49
-rw-r--r--tests/node_compat/package.json3
-rw-r--r--tests/node_compat/test/common/package.json1
-rw-r--r--tests/node_compat/test/fixtures/package.json1
-rw-r--r--tests/node_compat/test/internet/package.json1
-rw-r--r--tests/node_compat/test/parallel/package.json1
-rw-r--r--tests/node_compat/test/pseudo-tty/package.json1
-rw-r--r--tests/node_compat/test/pummel/package.json1
-rw-r--r--tests/node_compat/test/sequential/package.json1
-rw-r--r--tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/install.js12
-rw-r--r--tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/package.json7
-rw-r--r--tests/registry/npm/@denotest/install-no-ext/1.0.0/install/check.js1
-rw-r--r--tests/registry/npm/@denotest/install-no-ext/1.0.0/install/index.js1
-rw-r--r--tests/registry/npm/@denotest/install-no-ext/1.0.0/install/output.js1
-rw-r--r--tests/registry/npm/@denotest/install-no-ext/1.0.0/package.json7
-rw-r--r--tests/specs/compile/detect_cjs/deno.json5
-rw-r--r--tests/specs/compile/package_json_type/__test__.jsonc (renamed from tests/specs/compile/detect_cjs/__test__.jsonc)0
-rw-r--r--tests/specs/compile/package_json_type/add.js (renamed from tests/specs/compile/detect_cjs/add.js)0
-rw-r--r--tests/specs/compile/package_json_type/compile.out (renamed from tests/specs/compile/detect_cjs/compile.out)0
-rw-r--r--tests/specs/compile/package_json_type/main.js (renamed from tests/specs/compile/detect_cjs/main.js)0
-rw-r--r--tests/specs/compile/package_json_type/output.out (renamed from tests/specs/compile/detect_cjs/output.out)0
-rw-r--r--tests/specs/compile/package_json_type/package.json (renamed from tests/specs/compile/detect_cjs/package.json)0
-rw-r--r--tests/specs/compile/package_json_type/subtract.ts (renamed from tests/specs/compile/detect_cjs/subtract.ts)0
-rw-r--r--tests/specs/eval/pkg_json_type_cjs/__test__.jsonc4
-rw-r--r--tests/specs/eval/pkg_json_type_cjs/package.json3
-rw-r--r--tests/specs/install/scripts_install_launch_cjs_temp_dir/__test__.jsonc5
-rw-r--r--tests/specs/install/scripts_install_launch_cjs_temp_dir/output.out4
-rw-r--r--tests/specs/install/scripts_install_launch_cjs_temp_dir/package.json5
-rw-r--r--tests/specs/install/scripts_install_no_ext/__test__.jsonc5
-rw-r--r--tests/specs/install/scripts_install_no_ext/output.out4
-rw-r--r--tests/specs/install/scripts_install_no_ext/package.json5
-rw-r--r--tests/specs/mod.rs20
-rw-r--r--tests/specs/npm/dual_cjs_esm/__test__.jsonc4
-rw-r--r--tests/specs/npm/dual_cjs_esm/cjs_referrer/__test__.jsonc14
-rw-r--r--tests/specs/npm/dual_cjs_esm/cjs_referrer/check.out8
-rw-r--r--tests/specs/npm/dual_cjs_esm/cjs_referrer/main.cts4
-rw-r--r--tests/specs/npm/dual_cjs_esm/cjs_referrer/main.out4
-rw-r--r--tests/specs/npm/dual_cjs_esm/cjs_referrer/package.json5
-rw-r--r--tests/specs/npm/dual_cjs_esm/esm_referrer/__test__.jsonc4
-rw-r--r--tests/specs/npm/dual_cjs_esm/esm_referrer/main.out (renamed from tests/specs/npm/dual_cjs_esm/dual_cjs_esm/main.out)0
-rw-r--r--tests/specs/npm/dual_cjs_esm/esm_referrer/main.ts (renamed from tests/specs/npm/dual_cjs_esm/dual_cjs_esm/main.ts)0
-rw-r--r--tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/__test__.jsonc14
-rw-r--r--tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/check.out8
-rw-r--r--tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.out4
-rw-r--r--tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.ts4
-rw-r--r--tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/package.json6
-rw-r--r--tests/specs/npm/permissions_outside_package/__test__.jsonc5
-rw-r--r--tests/specs/npm/permissions_outside_package/foo/config.js (renamed from tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/config.js)0
-rw-r--r--tests/specs/npm/permissions_outside_package/foo/package.json5
-rw-r--r--tests/specs/npm/permissions_outside_package/main.out (renamed from tests/specs/npm/permissions_outside_package/permissions_outside_package/main.out)0
-rw-r--r--tests/specs/npm/permissions_outside_package/main.ts (renamed from tests/specs/npm/permissions_outside_package/permissions_outside_package/main.ts)2
-rw-r--r--tests/specs/npm/permissions_outside_package/package.json2
-rw-r--r--tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/package.json4
-rw-r--r--tests/specs/run/import_common_js/__test__.jsonc20
-rw-r--r--tests/specs/run/import_common_js/a.js7
-rw-r--r--tests/specs/run/import_common_js/exports_error.out7
-rw-r--r--tests/specs/run/import_common_js/index.cjs2
-rw-r--r--tests/specs/run/import_common_js/index.out2
-rw-r--r--tests/specs/run/import_common_js/main.out2
-rw-r--r--tests/specs/run/import_common_js/module_error.out7
-rw-r--r--tests/specs/run/import_common_js/node_modules/foo/index.mjs1
-rw-r--r--tests/specs/run/import_common_js/require_error.out7
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/__test__.jsonc5
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/file.js1
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/logs_require.js1
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/main.js5
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/index.js3
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/package.json4
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/output.out12
-rw-r--r--tests/specs/run/npm_pkg_requires_esm_js/package.json0
-rw-r--r--tests/specs/run/package_json_type/commonjs/basic/deno.jsonc5
-rw-r--r--tests/specs/run/package_json_type/commonjs/basic/main_mix.out7
-rw-r--r--tests/specs/run/package_json_type/commonjs/jsx/deno.jsonc5
-rw-r--r--tests/specs/run/package_json_type/none/deno.jsonc5
-rw-r--r--tests/specs/run/package_json_type/none/main_cjs.out7
-rw-r--r--tests/specs/run/require_esm/main.out11
-rw-r--r--tests/specs/run/stdin_type_cjs/__test__.jsonc5
-rw-r--r--tests/specs/run/stdin_type_cjs/package.json3
-rw-r--r--tests/specs/run/stdin_type_cjs/stdin_read_all.ts1
-rw-r--r--tests/specs/schema.json3
-rw-r--r--tests/util/server/src/servers/mod.rs22
119 files changed, 1235 insertions, 607 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index eb7797174..37f589937 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -576,7 +576,6 @@ pub struct UnstableConfig {
// TODO(bartlomieju): remove in Deno 2.5
pub legacy_flag_enabled: bool, // --unstable
pub bare_node_builtins: bool,
- pub detect_cjs: bool,
pub sloppy_imports: bool,
pub features: Vec<String>, // --unstabe-kv --unstable-cron
}
@@ -5720,7 +5719,6 @@ fn unstable_args_parse(
flags.unstable_config.bare_node_builtins =
matches.get_flag("unstable-bare-node-builtins");
- flags.unstable_config.detect_cjs = matches.get_flag("unstable-detect-cjs");
flags.unstable_config.sloppy_imports =
matches.get_flag("unstable-sloppy-imports");
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 3aaf2bd43..5e5bae87d 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -7,6 +7,7 @@ mod import_map;
mod lockfile;
mod package_json;
+use deno_ast::MediaType;
use deno_ast::SourceMapOption;
use deno_config::deno_json::NodeModulesDirMode;
use deno_config::workspace::CreateResolverOptions;
@@ -34,7 +35,6 @@ use import_map::resolve_import_map_value_from_specifier;
pub use deno_config::deno_json::BenchConfig;
pub use deno_config::deno_json::ConfigFile;
pub use deno_config::deno_json::FmtOptionsConfig;
-pub use deno_config::deno_json::JsxImportSourceConfig;
pub use deno_config::deno_json::LintRulesConfig;
pub use deno_config::deno_json::ProseWrap;
pub use deno_config::deno_json::TsConfig;
@@ -1155,21 +1155,34 @@ impl CliOptions {
self
.main_module_cell
.get_or_init(|| {
- let main_module = match &self.flags.subcommand {
+ Ok(match &self.flags.subcommand {
DenoSubcommand::Compile(compile_flags) => {
resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
}
DenoSubcommand::Eval(_) => {
- resolve_url_or_path("./$deno$eval.ts", self.initial_cwd())?
+ resolve_url_or_path("./$deno$eval.mts", self.initial_cwd())?
}
DenoSubcommand::Repl(_) => {
- resolve_url_or_path("./$deno$repl.ts", self.initial_cwd())?
+ resolve_url_or_path("./$deno$repl.mts", self.initial_cwd())?
}
DenoSubcommand::Run(run_flags) => {
if run_flags.is_stdin() {
- resolve_url_or_path("./$deno$stdin.ts", self.initial_cwd())?
+ resolve_url_or_path("./$deno$stdin.mts", self.initial_cwd())?
} else {
- resolve_url_or_path(&run_flags.script, self.initial_cwd())?
+ let url =
+ resolve_url_or_path(&run_flags.script, self.initial_cwd())?;
+ if self.is_node_main()
+ && url.scheme() == "file"
+ && MediaType::from_specifier(&url) == MediaType::Unknown
+ {
+ try_resolve_node_binary_main_entrypoint(
+ &run_flags.script,
+ self.initial_cwd(),
+ )?
+ .unwrap_or(url)
+ } else {
+ url
+ }
}
}
DenoSubcommand::Serve(run_flags) => {
@@ -1178,9 +1191,7 @@ impl CliOptions {
_ => {
bail!("No main module.")
}
- };
-
- Ok(main_module)
+ })
})
.as_ref()
.map_err(|err| deno_core::anyhow::anyhow!("{}", err))
@@ -1229,7 +1240,7 @@ impl CliOptions {
// This is triggered via a secret environment variable which is used
// for functionality like child_process.fork. Users should NOT depend
// on this functionality.
- pub fn is_npm_main(&self) -> bool {
+ pub fn is_node_main(&self) -> bool {
NPM_PROCESS_STATE.is_some()
}
@@ -1607,9 +1618,11 @@ impl CliOptions {
|| self.workspace().has_unstable("bare-node-builtins")
}
- pub fn unstable_detect_cjs(&self) -> bool {
- self.flags.unstable_config.detect_cjs
- || self.workspace().has_unstable("detect-cjs")
+ pub fn detect_cjs(&self) -> bool {
+ // only enabled when there's a package.json in order to not have a
+ // perf penalty for non-npm Deno projects of searching for the closest
+ // package.json beside each module
+ self.workspace().package_jsons().next().is_some() || self.is_node_main()
}
fn byonm_enabled(&self) -> bool {
@@ -1673,7 +1686,6 @@ impl CliOptions {
"byonm",
"bare-node-builtins",
"fmt-component",
- "detect-cjs",
])
.collect();
@@ -1811,6 +1823,36 @@ fn resolve_node_modules_folder(
Ok(Some(canonicalize_path_maybe_not_exists(&path)?))
}
+fn try_resolve_node_binary_main_entrypoint(
+ specifier: &str,
+ initial_cwd: &Path,
+) -> Result<Option<Url>, AnyError> {
+ // node allows running files at paths without a `.js` extension
+ // or at directories with an index.js file
+ let path = deno_core::normalize_path(initial_cwd.join(specifier));
+ if path.is_dir() {
+ let index_file = path.join("index.js");
+ Ok(if index_file.is_file() {
+ Some(deno_path_util::url_from_file_path(&index_file)?)
+ } else {
+ None
+ })
+ } else {
+ let path = path.with_extension(
+ path
+ .extension()
+ .and_then(|s| s.to_str())
+ .map(|s| format!("{}.js", s))
+ .unwrap_or("js".to_string()),
+ );
+ if path.is_file() {
+ Ok(Some(deno_path_util::url_from_file_path(&path)?))
+ } else {
+ Ok(None)
+ }
+ }
+}
+
fn resolve_import_map_specifier(
maybe_import_map_path: Option<&str>,
maybe_config_file: Option<&ConfigFile>,
diff --git a/cli/emit.rs b/cli/emit.rs
index 8c4f2091c..3cd23b7ab 100644
--- a/cli/emit.rs
+++ b/cli/emit.rs
@@ -181,7 +181,6 @@ impl Emitter {
pub async fn load_and_emit_for_hmr(
&self,
specifier: &ModuleSpecifier,
- module_kind: deno_ast::ModuleKind,
) -> Result<String, AnyError> {
let media_type = MediaType::from_specifier(specifier);
let source_code = tokio::fs::read_to_string(
@@ -203,11 +202,16 @@ impl Emitter {
// this statement is probably wrong)
let mut options = self.transpile_and_emit_options.1.clone();
options.source_map = SourceMapOption::None;
+ let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script(
+ specifier,
+ media_type,
+ parsed_source.compute_is_script(),
+ )?;
let transpiled_source = parsed_source
.transpile(
&self.transpile_and_emit_options.0,
&deno_ast::TranspileModuleOptions {
- module_kind: Some(module_kind),
+ module_kind: Some(ModuleKind::from_is_cjs(is_cjs)),
},
&options,
)?
diff --git a/cli/factory.rs b/cli/factory.rs
index 417f771a3..5cb2dd7b3 100644
--- a/cli/factory.rs
+++ b/cli/factory.rs
@@ -42,12 +42,12 @@ use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::resolver::CjsTracker;
-use crate::resolver::CjsTrackerOptions;
use crate::resolver::CliDenoResolverFs;
-use crate::resolver::CliGraphResolver;
-use crate::resolver::CliGraphResolverOptions;
use crate::resolver::CliNodeResolver;
+use crate::resolver::CliResolver;
+use crate::resolver::CliResolverOptions;
use crate::resolver::CliSloppyImportsResolver;
+use crate::resolver::IsCjsResolverOptions;
use crate::resolver::NpmModuleLoader;
use crate::resolver::SloppyImportsCachedFs;
use crate::standalone::DenoCompileBinaryWriter;
@@ -201,7 +201,7 @@ struct CliFactoryServices {
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
permission_desc_parser: Deferred<Arc<RuntimePermissionDescriptorParser>>,
pkg_json_resolver: Deferred<Arc<PackageJsonResolver>>,
- resolver: Deferred<Arc<CliGraphResolver>>,
+ resolver: Deferred<Arc<CliResolver>>,
root_cert_store_provider: Deferred<Arc<dyn RootCertStoreProvider>>,
root_permissions_container: Deferred<PermissionsContainer>,
sloppy_imports_resolver: Deferred<Option<Arc<CliSloppyImportsResolver>>>,
@@ -523,14 +523,14 @@ impl CliFactory {
.await
}
- pub async fn resolver(&self) -> Result<&Arc<CliGraphResolver>, AnyError> {
+ pub async fn resolver(&self) -> Result<&Arc<CliResolver>, AnyError> {
self
.services
.resolver
.get_or_try_init_async(
async {
let cli_options = self.cli_options()?;
- Ok(Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
+ Ok(Arc::new(CliResolver::new(CliResolverOptions {
sloppy_imports_resolver: self.sloppy_imports_resolver()?.cloned(),
node_resolver: Some(self.cli_node_resolver().await?.clone()),
npm_resolver: if cli_options.no_npm() {
@@ -541,9 +541,6 @@ impl CliFactory {
workspace_resolver: self.workspace_resolver().await?.clone(),
bare_node_builtins_enabled: cli_options
.unstable_bare_node_builtins(),
- maybe_jsx_import_source_config: cli_options
- .workspace()
- .to_maybe_jsx_import_source_config()?,
maybe_vendor_dir: cli_options.vendor_dir_path(),
})))
}
@@ -652,7 +649,6 @@ impl CliFactory {
self.cjs_tracker()?.clone(),
self.fs().clone(),
Some(self.parsed_source_cache().clone()),
- self.cli_options()?.is_npm_main(),
);
Ok(Arc::new(NodeCodeTranslator::new(
@@ -706,6 +702,7 @@ impl CliFactory {
let cli_options = self.cli_options()?;
Ok(Arc::new(ModuleGraphBuilder::new(
self.caches()?.clone(),
+ self.cjs_tracker()?.clone(),
cli_options.clone(),
self.file_fetcher()?.clone(),
self.fs().clone(),
@@ -794,8 +791,9 @@ impl CliFactory {
Ok(Arc::new(CjsTracker::new(
self.in_npm_pkg_checker()?.clone(),
self.pkg_json_resolver().clone(),
- CjsTrackerOptions {
- unstable_detect_cjs: options.unstable_detect_cjs(),
+ IsCjsResolverOptions {
+ detect_cjs: options.detect_cjs(),
+ is_node_main: options.is_node_main(),
},
)))
})
@@ -809,7 +807,6 @@ impl CliFactory {
.cli_node_resolver
.get_or_try_init_async(async {
Ok(Arc::new(CliNodeResolver::new(
- self.cjs_tracker()?.clone(),
self.fs().clone(),
self.in_npm_pkg_checker()?.clone(),
self.node_resolver().await?.clone(),
@@ -950,10 +947,8 @@ impl CliFactory {
let create_hmr_runner = if cli_options.has_hmr() {
let watcher_communicator = self.watcher_communicator.clone().unwrap();
let emitter = self.emitter()?.clone();
- let cjs_tracker = self.cjs_tracker()?.clone();
let fn_: crate::worker::CreateHmrRunnerCb = Box::new(move |session| {
Box::new(HmrRunner::new(
- cjs_tracker.clone(),
emitter.clone(),
session,
watcher_communicator.clone(),
diff --git a/cli/graph_util.rs b/cli/graph_util.rs
index 46257cf78..3f48449bc 100644
--- a/cli/graph_util.rs
+++ b/cli/graph_util.rs
@@ -13,16 +13,19 @@ use crate::colors;
use crate::errors::get_error_class_name;
use crate::file_fetcher::FileFetcher;
use crate::npm::CliNpmResolver;
-use crate::resolver::CliGraphResolver;
+use crate::resolver::CjsTracker;
+use crate::resolver::CliResolver;
use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::SloppyImportsCachedFs;
use crate::tools::check;
use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator;
use crate::util::fs::canonicalize_path;
+use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::JsrPackageConfig;
use deno_core::anyhow::bail;
use deno_graph::source::LoaderChecksum;
+use deno_graph::source::ResolutionMode;
use deno_graph::FillFromLockfileOptions;
use deno_graph::JsrLoadError;
use deno_graph::ModuleLoadError;
@@ -379,6 +382,7 @@ pub struct BuildFastCheckGraphOptions<'a> {
pub struct ModuleGraphBuilder {
caches: Arc<cache::Caches>,
+ cjs_tracker: Arc<CjsTracker>,
cli_options: Arc<CliOptions>,
file_fetcher: Arc<FileFetcher>,
fs: Arc<dyn FileSystem>,
@@ -389,7 +393,7 @@ pub struct ModuleGraphBuilder {
module_info_cache: Arc<ModuleInfoCache>,
npm_resolver: Arc<dyn CliNpmResolver>,
parsed_source_cache: Arc<ParsedSourceCache>,
- resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer,
}
@@ -397,6 +401,7 @@ impl ModuleGraphBuilder {
#[allow(clippy::too_many_arguments)]
pub fn new(
caches: Arc<cache::Caches>,
+ cjs_tracker: Arc<CjsTracker>,
cli_options: Arc<CliOptions>,
file_fetcher: Arc<FileFetcher>,
fs: Arc<dyn FileSystem>,
@@ -407,11 +412,12 @@ impl ModuleGraphBuilder {
module_info_cache: Arc<ModuleInfoCache>,
npm_resolver: Arc<dyn CliNpmResolver>,
parsed_source_cache: Arc<ParsedSourceCache>,
- resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
root_permissions_container: PermissionsContainer,
) -> Self {
Self {
caches,
+ cjs_tracker,
cli_options,
file_fetcher,
fs,
@@ -518,7 +524,7 @@ impl ModuleGraphBuilder {
None => MutLoaderRef::Owned(self.create_graph_loader()),
};
let cli_resolver = &self.resolver;
- let graph_resolver = cli_resolver.as_graph_resolver();
+ let graph_resolver = self.create_graph_resolver()?;
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver();
let maybe_file_watcher_reporter = self
.maybe_file_watcher_reporter
@@ -543,7 +549,7 @@ impl ModuleGraphBuilder {
npm_resolver: Some(&graph_npm_resolver),
module_analyzer: &analyzer,
reporter: maybe_file_watcher_reporter,
- resolver: Some(graph_resolver),
+ resolver: Some(&graph_resolver),
locker: locker.as_mut().map(|l| l as _),
},
)
@@ -666,7 +672,7 @@ impl ModuleGraphBuilder {
};
let parser = self.parsed_source_cache.as_capturing_parser();
let cli_resolver = &self.resolver;
- let graph_resolver = cli_resolver.as_graph_resolver();
+ let graph_resolver = self.create_graph_resolver()?;
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver();
graph.build_fast_check_type_graph(
@@ -675,7 +681,7 @@ impl ModuleGraphBuilder {
fast_check_cache: fast_check_cache.as_ref().map(|c| c as _),
fast_check_dts: false,
jsr_url_provider: &CliJsrUrlProvider,
- resolver: Some(graph_resolver),
+ resolver: Some(&graph_resolver),
npm_resolver: Some(&graph_npm_resolver),
workspace_fast_check: options.workspace_fast_check,
},
@@ -739,6 +745,18 @@ impl ModuleGraphBuilder {
},
)
}
+
+ fn create_graph_resolver(&self) -> Result<CliGraphResolver, AnyError> {
+ let jsx_import_source_config = self
+ .cli_options
+ .workspace()
+ .to_maybe_jsx_import_source_config()?;
+ Ok(CliGraphResolver {
+ cjs_tracker: &self.cjs_tracker,
+ resolver: &self.resolver,
+ jsx_import_source_config,
+ })
+ }
}
/// Adds more explanatory information to a resolution error.
@@ -1143,6 +1161,53 @@ fn format_deno_graph_error(err: &dyn Error) -> String {
message
}
+#[derive(Debug)]
+struct CliGraphResolver<'a> {
+ cjs_tracker: &'a CjsTracker,
+ resolver: &'a CliResolver,
+ jsx_import_source_config: Option<JsxImportSourceConfig>,
+}
+
+impl<'a> deno_graph::source::Resolver for CliGraphResolver<'a> {
+ fn default_jsx_import_source(&self) -> Option<String> {
+ self
+ .jsx_import_source_config
+ .as_ref()
+ .and_then(|c| c.default_specifier.clone())
+ }
+
+ fn default_jsx_import_source_types(&self) -> Option<String> {
+ self
+ .jsx_import_source_config
+ .as_ref()
+ .and_then(|c| c.default_types_specifier.clone())
+ }
+
+ fn jsx_import_source_module(&self) -> &str {
+ self
+ .jsx_import_source_config
+ .as_ref()
+ .map(|c| c.module.as_str())
+ .unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
+ }
+
+ fn resolve(
+ &self,
+ raw_specifier: &str,
+ referrer_range: &deno_graph::Range,
+ mode: ResolutionMode,
+ ) -> Result<ModuleSpecifier, ResolveError> {
+ self.resolver.resolve(
+ raw_specifier,
+ referrer_range,
+ self
+ .cjs_tracker
+ .get_referrer_kind(&referrer_range.specifier),
+ mode,
+ )
+ }
+}
+
#[cfg(test)]
mod test {
use std::sync::Arc;
diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs
index 683a59c21..9f26de70c 100644
--- a/cli/lsp/analysis.rs
+++ b/cli/lsp/analysis.rs
@@ -39,6 +39,7 @@ use deno_semver::package::PackageReq;
use deno_semver::package::PackageReqReference;
use deno_semver::Version;
use import_map::ImportMap;
+use node_resolver::NodeModuleKind;
use once_cell::sync::Lazy;
use regex::Regex;
use std::borrow::Cow;
@@ -467,6 +468,7 @@ impl<'a> TsResponseImportMapper<'a> {
&self,
specifier: &str,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
) -> Option<String> {
let specifier_stem = specifier.strip_suffix(".js").unwrap_or(specifier);
let specifiers = std::iter::once(Cow::Borrowed(specifier)).chain(
@@ -477,7 +479,7 @@ impl<'a> TsResponseImportMapper<'a> {
for specifier in specifiers {
if let Some(specifier) = self
.resolver
- .as_graph_resolver(Some(&self.file_referrer))
+ .as_cli_resolver(Some(&self.file_referrer))
.resolve(
&specifier,
&deno_graph::Range {
@@ -485,6 +487,7 @@ impl<'a> TsResponseImportMapper<'a> {
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ referrer_kind,
ResolutionMode::Types,
)
.ok()
@@ -507,10 +510,11 @@ impl<'a> TsResponseImportMapper<'a> {
&self,
specifier_text: &str,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
) -> bool {
self
.resolver
- .as_graph_resolver(Some(&self.file_referrer))
+ .as_cli_resolver(Some(&self.file_referrer))
.resolve(
specifier_text,
&deno_graph::Range {
@@ -518,6 +522,7 @@ impl<'a> TsResponseImportMapper<'a> {
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ referrer_kind,
deno_graph::source::ResolutionMode::Types,
)
.is_ok()
@@ -586,6 +591,7 @@ fn try_reverse_map_package_json_exports(
/// like an import and rewrite the import specifier to include the extension
pub fn fix_ts_import_changes(
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
changes: &[tsc::FileTextChanges],
language_server: &language_server::Inner,
) -> Result<Vec<tsc::FileTextChanges>, AnyError> {
@@ -602,8 +608,8 @@ pub fn fix_ts_import_changes(
if let Some(captures) = IMPORT_SPECIFIER_RE.captures(line) {
let specifier =
captures.iter().skip(1).find_map(|s| s).unwrap().as_str();
- if let Some(new_specifier) =
- import_mapper.check_unresolved_specifier(specifier, referrer)
+ if let Some(new_specifier) = import_mapper
+ .check_unresolved_specifier(specifier, referrer, referrer_kind)
{
line.replace(specifier, &new_specifier)
} else {
@@ -633,6 +639,7 @@ pub fn fix_ts_import_changes(
/// resolution by Deno (includes the extension).
fn fix_ts_import_action<'a>(
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
action: &'a tsc::CodeFixAction,
language_server: &language_server::Inner,
) -> Option<Cow<'a, tsc::CodeFixAction>> {
@@ -652,7 +659,7 @@ fn fix_ts_import_action<'a>(
};
let import_mapper = language_server.get_ts_response_import_mapper(referrer);
if let Some(new_specifier) =
- import_mapper.check_unresolved_specifier(specifier, referrer)
+ import_mapper.check_unresolved_specifier(specifier, referrer, referrer_kind)
{
let description = action.description.replace(specifier, &new_specifier);
let changes = action
@@ -683,7 +690,7 @@ fn fix_ts_import_action<'a>(
fix_id: None,
fix_all_description: None,
}))
- } else if !import_mapper.is_valid_import(specifier, referrer) {
+ } else if !import_mapper.is_valid_import(specifier, referrer, referrer_kind) {
None
} else {
Some(Cow::Borrowed(action))
@@ -1017,6 +1024,7 @@ impl CodeActionCollection {
pub fn add_ts_fix_action(
&mut self,
specifier: &ModuleSpecifier,
+ specifier_kind: NodeModuleKind,
action: &tsc::CodeFixAction,
diagnostic: &lsp::Diagnostic,
language_server: &language_server::Inner,
@@ -1034,7 +1042,8 @@ impl CodeActionCollection {
"The action returned from TypeScript is unsupported.",
));
}
- let Some(action) = fix_ts_import_action(specifier, action, language_server)
+ let Some(action) =
+ fix_ts_import_action(specifier, specifier_kind, action, language_server)
else {
return Ok(());
};
@@ -1276,6 +1285,9 @@ impl CodeActionCollection {
import_start_from_specifier(document, i)
})?;
let referrer = document.specifier();
+ let referrer_kind = language_server
+ .is_cjs_resolver
+ .get_doc_module_kind(document);
let file_referrer = document.file_referrer();
let config_data = language_server
.config
@@ -1298,10 +1310,11 @@ impl CodeActionCollection {
if !config_data.byonm {
return None;
}
- if !language_server
- .resolver
- .is_bare_package_json_dep(&dep_key, referrer)
- {
+ if !language_server.resolver.is_bare_package_json_dep(
+ &dep_key,
+ referrer,
+ referrer_kind,
+ ) {
return None;
}
NpmPackageReqReference::from_str(&format!("npm:{}", &dep_key)).ok()?
@@ -1320,7 +1333,7 @@ impl CodeActionCollection {
}
if language_server
.resolver
- .npm_to_file_url(&npm_ref, document.specifier(), file_referrer)
+ .npm_to_file_url(&npm_ref, referrer, referrer_kind, file_referrer)
.is_some()
{
// The package import has types.
diff --git a/cli/lsp/completions.rs b/cli/lsp/completions.rs
index 1590743b2..3ee8ae93e 100644
--- a/cli/lsp/completions.rs
+++ b/cli/lsp/completions.rs
@@ -9,6 +9,7 @@ use super::jsr::CliJsrSearchApi;
use super::lsp_custom;
use super::npm::CliNpmSearchApi;
use super::registries::ModuleRegistry;
+use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver;
use super::search::PackageSearchApi;
use super::tsc;
@@ -35,6 +36,7 @@ use deno_semver::package::PackageNv;
use import_map::ImportMap;
use indexmap::IndexSet;
use lsp_types::CompletionList;
+use node_resolver::NodeModuleKind;
use once_cell::sync::Lazy;
use regex::Regex;
use tower_lsp::lsp_types as lsp;
@@ -159,15 +161,17 @@ pub async fn get_import_completions(
jsr_search_api: &CliJsrSearchApi,
npm_search_api: &CliNpmSearchApi,
documents: &Documents,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver,
maybe_import_map: Option<&ImportMap>,
) -> Option<lsp::CompletionResponse> {
let document = documents.get(specifier)?;
+ let specifier_kind = is_cjs_resolver.get_doc_module_kind(&document);
let file_referrer = document.file_referrer();
let (text, _, range) = document.get_maybe_dependency(position)?;
let range = to_narrow_lsp_range(document.text_info(), &range);
let resolved = resolver
- .as_graph_resolver(file_referrer)
+ .as_cli_resolver(file_referrer)
.resolve(
&text,
&Range {
@@ -175,6 +179,7 @@ pub async fn get_import_completions(
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ specifier_kind,
ResolutionMode::Execution,
)
.ok();
@@ -201,7 +206,7 @@ pub async fn get_import_completions(
// completions for import map specifiers
Some(lsp::CompletionResponse::List(completion_list))
} else if let Some(completion_list) =
- get_local_completions(specifier, &text, &range, resolver)
+ get_local_completions(specifier, specifier_kind, &text, &range, resolver)
{
// completions for local relative modules
Some(lsp::CompletionResponse::List(completion_list))
@@ -355,24 +360,26 @@ fn get_import_map_completions(
/// Return local completions that are relative to the base specifier.
fn get_local_completions(
- base: &ModuleSpecifier,
+ referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
text: &str,
range: &lsp::Range,
resolver: &LspResolver,
) -> Option<CompletionList> {
- if base.scheme() != "file" {
+ if referrer.scheme() != "file" {
return None;
}
let parent = &text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1];
let resolved_parent = resolver
- .as_graph_resolver(Some(base))
+ .as_cli_resolver(Some(referrer))
.resolve(
parent,
&Range {
- specifier: base.clone(),
+ specifier: referrer.clone(),
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ referrer_kind,
ResolutionMode::Execution,
)
.ok()?;
@@ -385,7 +392,7 @@ fn get_local_completions(
let de = de.ok()?;
let label = de.path().file_name()?.to_string_lossy().to_string();
let entry_specifier = resolve_path(de.path().to_str()?, &cwd).ok()?;
- if entry_specifier == *base {
+ if entry_specifier == *referrer {
return None;
}
let full_text = format!("{parent}{label}");
@@ -905,6 +912,7 @@ mod tests {
ModuleSpecifier::from_file_path(file_c).expect("could not create");
let actual = get_local_completions(
&specifier,
+ NodeModuleKind::Esm,
"./",
&lsp::Range {
start: lsp::Position {
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index 34bf64446..ea77e36bc 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -4,6 +4,7 @@ use deno_ast::MediaType;
use deno_config::deno_json::DenoJsonCache;
use deno_config::deno_json::FmtConfig;
use deno_config::deno_json::FmtOptionsConfig;
+use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::deno_json::LintConfig;
use deno_config::deno_json::NodeModulesDirMode;
use deno_config::deno_json::TestConfig;
@@ -1654,6 +1655,17 @@ impl ConfigData {
self.member_dir.maybe_pkg_json()
}
+ pub fn maybe_jsx_import_source_config(
+ &self,
+ ) -> Option<JsxImportSourceConfig> {
+ self
+ .member_dir
+ .workspace
+ .to_maybe_jsx_import_source_config()
+ .ok()
+ .flatten()
+ }
+
pub fn scope_contains_specifier(&self, specifier: &ModuleSpecifier) -> bool {
specifier.as_str().starts_with(self.scope.as_str())
|| self
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs
index 83c00d27e..e4fb82e58 100644
--- a/cli/lsp/diagnostics.rs
+++ b/cli/lsp/diagnostics.rs
@@ -1707,6 +1707,7 @@ mod tests {
documents: Arc::new(documents),
assets: Default::default(),
config: Arc::new(config),
+ is_cjs_resolver: Default::default(),
resolver,
},
)
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index ce13c3215..b62fa8553 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -3,7 +3,9 @@
use super::cache::calculate_fs_version;
use super::cache::LspCache;
use super::config::Config;
+use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver;
+use super::resolver::SingleReferrerGraphResolver;
use super::testing::TestCollector;
use super::testing::TestModule;
use super::text::LineIndex;
@@ -33,6 +35,7 @@ use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use indexmap::IndexSet;
+use node_resolver::NodeModuleKind;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
@@ -293,6 +296,8 @@ pub struct Document {
/// Contains the last-known-good set of dependencies from parsing the module.
config: Arc<Config>,
dependencies: Arc<IndexMap<String, deno_graph::Dependency>>,
+ /// If this is maybe a CJS script and maybe not an ES module.
+ is_script: Option<bool>,
// TODO(nayeemrmn): This is unused, use it for scope attribution for remote
// modules.
file_referrer: Option<ModuleSpecifier>,
@@ -323,6 +328,7 @@ impl Document {
maybe_lsp_version: Option<i32>,
maybe_language_id: Option<LanguageId>,
maybe_headers: Option<HashMap<String, String>>,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: Arc<LspResolver>,
config: Arc<Config>,
cache: &Arc<LspCache>,
@@ -342,6 +348,7 @@ impl Document {
maybe_headers.as_ref(),
media_type,
file_referrer.as_ref(),
+ is_cjs_resolver,
&resolver,
)
} else {
@@ -367,6 +374,7 @@ impl Document {
file_referrer.as_ref(),
),
file_referrer,
+ is_script: maybe_module.as_ref().map(|m| m.is_script),
maybe_types_dependency,
line_index,
maybe_language_id,
@@ -388,6 +396,7 @@ impl Document {
fn with_new_config(
&self,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: Arc<LspResolver>,
config: Arc<Config>,
) -> Arc<Self> {
@@ -399,6 +408,7 @@ impl Document {
let dependencies;
let maybe_types_dependency;
let maybe_parsed_source;
+ let is_script;
let maybe_test_module_fut;
if media_type != self.media_type {
let parsed_source_result =
@@ -408,6 +418,7 @@ impl Document {
&parsed_source_result,
self.maybe_headers.as_ref(),
self.file_referrer.as_ref(),
+ is_cjs_resolver,
&resolver,
)
.ok();
@@ -415,6 +426,7 @@ impl Document {
.as_ref()
.map(|m| Arc::new(m.dependencies.clone()))
.unwrap_or_default();
+ is_script = maybe_module.as_ref().map(|m| m.is_script);
maybe_types_dependency = maybe_module
.as_ref()
.and_then(|m| Some(Arc::new(m.maybe_types_dependency.clone()?)));
@@ -422,10 +434,19 @@ impl Document {
maybe_test_module_fut =
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &config);
} else {
- let graph_resolver =
- resolver.as_graph_resolver(self.file_referrer.as_ref());
+ let cli_resolver = resolver.as_cli_resolver(self.file_referrer.as_ref());
let npm_resolver =
resolver.create_graph_npm_resolver(self.file_referrer.as_ref());
+ let config_data = resolver.as_config_data(self.file_referrer.as_ref());
+ let jsx_import_source_config =
+ config_data.and_then(|d| d.maybe_jsx_import_source_config());
+ let resolver = SingleReferrerGraphResolver {
+ valid_referrer: &self.specifier,
+ referrer_kind: is_cjs_resolver
+ .get_lsp_referrer_kind(&self.specifier, self.is_script),
+ cli_resolver,
+ jsx_import_source_config: jsx_import_source_config.as_ref(),
+ };
dependencies = Arc::new(
self
.dependencies
@@ -436,7 +457,7 @@ impl Document {
d.with_new_resolver(
s,
&CliJsrUrlProvider,
- Some(graph_resolver),
+ Some(&resolver),
Some(&npm_resolver),
),
)
@@ -446,10 +467,11 @@ impl Document {
maybe_types_dependency = self.maybe_types_dependency.as_ref().map(|d| {
Arc::new(d.with_new_resolver(
&CliJsrUrlProvider,
- Some(graph_resolver),
+ Some(&resolver),
Some(&npm_resolver),
))
});
+ is_script = self.is_script;
maybe_parsed_source = self.maybe_parsed_source().cloned();
maybe_test_module_fut = self
.maybe_test_module_fut
@@ -461,6 +483,7 @@ impl Document {
// updated properties
dependencies,
file_referrer: self.file_referrer.clone(),
+ is_script,
maybe_types_dependency,
maybe_navigation_tree: Mutex::new(None),
// maintain - this should all be copies/clones
@@ -485,6 +508,7 @@ impl Document {
fn with_change(
&self,
+ is_cjs_resolver: &LspIsCjsResolver,
version: i32,
changes: Vec<lsp::TextDocumentContentChangeEvent>,
) -> Result<Arc<Self>, AnyError> {
@@ -518,6 +542,7 @@ impl Document {
self.maybe_headers.as_ref(),
media_type,
self.file_referrer.as_ref(),
+ is_cjs_resolver,
self.resolver.as_ref(),
)
} else {
@@ -541,6 +566,7 @@ impl Document {
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &self.config);
Ok(Arc::new(Self {
config: self.config.clone(),
+ is_script: maybe_module.as_ref().map(|m| m.is_script),
specifier: self.specifier.clone(),
file_referrer: self.file_referrer.clone(),
maybe_fs_version: self.maybe_fs_version.clone(),
@@ -575,6 +601,7 @@ impl Document {
),
maybe_language_id: self.maybe_language_id,
dependencies: self.dependencies.clone(),
+ is_script: self.is_script,
maybe_types_dependency: self.maybe_types_dependency.clone(),
text: self.text.clone(),
text_info_cell: once_cell::sync::OnceCell::new(),
@@ -602,6 +629,7 @@ impl Document {
),
maybe_language_id: self.maybe_language_id,
dependencies: self.dependencies.clone(),
+ is_script: self.is_script,
maybe_types_dependency: self.maybe_types_dependency.clone(),
text: self.text.clone(),
text_info_cell: once_cell::sync::OnceCell::new(),
@@ -650,6 +678,13 @@ impl Document {
})
}
+ /// If this is maybe a CJS script and maybe not an ES module.
+ ///
+ /// Use `LspIsCjsResolver` to determine for sure.
+ pub fn is_script(&self) -> Option<bool> {
+ self.is_script
+ }
+
pub fn line_index(&self) -> Arc<LineIndex> {
self.line_index.clone()
}
@@ -797,6 +832,7 @@ impl FileSystemDocuments {
pub fn get(
&self,
specifier: &ModuleSpecifier,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &Arc<LspResolver>,
config: &Arc<Config>,
cache: &Arc<LspCache>,
@@ -820,7 +856,14 @@ impl FileSystemDocuments {
};
if dirty {
// attempt to update the file on the file system
- self.refresh_document(specifier, resolver, config, cache, file_referrer)
+ self.refresh_document(
+ specifier,
+ is_cjs_resolver,
+ resolver,
+ config,
+ cache,
+ file_referrer,
+ )
} else {
old_doc
}
@@ -831,6 +874,7 @@ impl FileSystemDocuments {
fn refresh_document(
&self,
specifier: &ModuleSpecifier,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &Arc<LspResolver>,
config: &Arc<Config>,
cache: &Arc<LspCache>,
@@ -847,6 +891,7 @@ impl FileSystemDocuments {
None,
None,
None,
+ is_cjs_resolver,
resolver.clone(),
config.clone(),
cache,
@@ -863,6 +908,7 @@ impl FileSystemDocuments {
None,
None,
None,
+ is_cjs_resolver,
resolver.clone(),
config.clone(),
cache,
@@ -890,6 +936,7 @@ impl FileSystemDocuments {
None,
None,
maybe_headers,
+ is_cjs_resolver,
resolver.clone(),
config.clone(),
cache,
@@ -930,6 +977,11 @@ pub struct Documents {
/// The DENO_DIR that the documents looks for non-file based modules.
cache: Arc<LspCache>,
config: Arc<Config>,
+ /// Resolver for detecting if a document is CJS or ESM.
+ is_cjs_resolver: Arc<LspIsCjsResolver>,
+ /// A resolver that takes into account currently loaded import map and JSX
+ /// settings.
+ resolver: Arc<LspResolver>,
/// A flag that indicates that stated data is potentially invalid and needs to
/// be recalculated before being considered valid.
dirty: bool,
@@ -937,9 +989,6 @@ pub struct Documents {
open_docs: HashMap<ModuleSpecifier, Arc<Document>>,
/// Documents stored on the file system.
file_system_docs: Arc<FileSystemDocuments>,
- /// A resolver that takes into account currently loaded import map and JSX
- /// settings.
- resolver: Arc<LspResolver>,
/// The npm package requirements found in npm specifiers.
npm_reqs_by_scope:
Arc<BTreeMap<Option<ModuleSpecifier>, BTreeSet<PackageReq>>>,
@@ -970,6 +1019,7 @@ impl Documents {
// the cache for remote modules here in order to get the
// x-typescript-types?
None,
+ &self.is_cjs_resolver,
self.resolver.clone(),
self.config.clone(),
&self.cache,
@@ -1004,7 +1054,7 @@ impl Documents {
))
})?;
self.dirty = true;
- let doc = doc.with_change(version, changes)?;
+ let doc = doc.with_change(&self.is_cjs_resolver, version, changes)?;
self.open_docs.insert(doc.specifier().clone(), doc.clone());
Ok(doc)
}
@@ -1133,6 +1183,7 @@ impl Documents {
if let Some(old_doc) = old_doc {
self.file_system_docs.get(
specifier,
+ &self.is_cjs_resolver,
&self.resolver,
&self.config,
&self.cache,
@@ -1157,6 +1208,7 @@ impl Documents {
} else {
self.file_system_docs.get(
&specifier,
+ &self.is_cjs_resolver,
&self.resolver,
&self.config,
&self.cache,
@@ -1215,12 +1267,15 @@ impl Documents {
referrer: &ModuleSpecifier,
file_referrer: Option<&ModuleSpecifier>,
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
- let document = self.get(referrer);
- let file_referrer = document
+ let referrer_doc = self.get(referrer);
+ let file_referrer = referrer_doc
.as_ref()
.and_then(|d| d.file_referrer())
.or(file_referrer);
- let dependencies = document.as_ref().map(|d| d.dependencies());
+ let dependencies = referrer_doc.as_ref().map(|d| d.dependencies());
+ let referrer_kind = self
+ .is_cjs_resolver
+ .get_maybe_doc_module_kind(referrer, referrer_doc.as_deref());
let mut results = Vec::new();
for raw_specifier in raw_specifiers {
if raw_specifier.starts_with("asset:") {
@@ -1237,31 +1292,35 @@ impl Documents {
results.push(self.resolve_dependency(
specifier,
referrer,
+ referrer_kind,
file_referrer,
));
} else if let Some(specifier) = dep.maybe_code.maybe_specifier() {
results.push(self.resolve_dependency(
specifier,
referrer,
+ referrer_kind,
file_referrer,
));
} else {
results.push(None);
}
} else if let Ok(specifier) =
- self.resolver.as_graph_resolver(file_referrer).resolve(
+ self.resolver.as_cli_resolver(file_referrer).resolve(
raw_specifier,
&deno_graph::Range {
specifier: referrer.clone(),
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ referrer_kind,
ResolutionMode::Types,
)
{
results.push(self.resolve_dependency(
&specifier,
referrer,
+ referrer_kind,
file_referrer,
));
} else {
@@ -1280,7 +1339,11 @@ impl Documents {
) {
self.config = Arc::new(config.clone());
self.cache = Arc::new(cache.clone());
+ self.is_cjs_resolver = Arc::new(LspIsCjsResolver::new(cache));
self.resolver = resolver.clone();
+
+ node_resolver::PackageJsonThreadLocalCache::clear();
+
{
let fs_docs = &self.file_system_docs;
// Clean up non-existent documents.
@@ -1300,14 +1363,21 @@ impl Documents {
if !config.specifier_enabled(doc.specifier()) {
continue;
}
- *doc = doc.with_new_config(self.resolver.clone(), self.config.clone());
+ *doc = doc.with_new_config(
+ &self.is_cjs_resolver,
+ self.resolver.clone(),
+ self.config.clone(),
+ );
}
for mut doc in self.file_system_docs.docs.iter_mut() {
if !config.specifier_enabled(doc.specifier()) {
continue;
}
- *doc.value_mut() =
- doc.with_new_config(self.resolver.clone(), self.config.clone());
+ *doc.value_mut() = doc.with_new_config(
+ &self.is_cjs_resolver,
+ self.resolver.clone(),
+ self.config.clone(),
+ );
}
self.open_docs = open_docs;
let mut preload_count = 0;
@@ -1324,6 +1394,7 @@ impl Documents {
{
fs_docs.refresh_document(
specifier,
+ &self.is_cjs_resolver,
&self.resolver,
&self.config,
&self.cache,
@@ -1409,6 +1480,7 @@ impl Documents {
&self,
specifier: &ModuleSpecifier,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
if let Some(module_name) = specifier.as_str().strip_prefix("node:") {
@@ -1422,10 +1494,12 @@ impl Documents {
let mut specifier = specifier.clone();
let mut media_type = None;
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&specifier) {
- let (s, mt) =
- self
- .resolver
- .npm_to_file_url(&npm_ref, referrer, file_referrer)?;
+ let (s, mt) = self.resolver.npm_to_file_url(
+ &npm_ref,
+ referrer,
+ referrer_kind,
+ file_referrer,
+ )?;
specifier = s;
media_type = Some(mt);
}
@@ -1435,7 +1509,8 @@ impl Documents {
return Some((specifier, media_type));
};
if let Some(types) = doc.maybe_types_dependency().maybe_specifier() {
- self.resolve_dependency(types, &specifier, file_referrer)
+ let specifier_kind = self.is_cjs_resolver.get_doc_module_kind(&doc);
+ self.resolve_dependency(types, &specifier, specifier_kind, file_referrer)
} else {
Some((doc.specifier().clone(), doc.media_type()))
}
@@ -1503,6 +1578,7 @@ fn parse_and_analyze_module(
maybe_headers: Option<&HashMap<String, String>>,
media_type: MediaType,
file_referrer: Option<&ModuleSpecifier>,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver,
) -> (Option<ParsedSourceResult>, Option<ModuleResult>) {
let parsed_source_result = parse_source(specifier.clone(), text, media_type);
@@ -1511,6 +1587,7 @@ fn parse_and_analyze_module(
&parsed_source_result,
maybe_headers,
file_referrer,
+ is_cjs_resolver,
resolver,
);
(Some(parsed_source_result), Some(module_result))
@@ -1536,11 +1613,26 @@ fn analyze_module(
parsed_source_result: &ParsedSourceResult,
maybe_headers: Option<&HashMap<String, String>>,
file_referrer: Option<&ModuleSpecifier>,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver,
) -> ModuleResult {
match parsed_source_result {
Ok(parsed_source) => {
let npm_resolver = resolver.create_graph_npm_resolver(file_referrer);
+ let cli_resolver = resolver.as_cli_resolver(file_referrer);
+ let config_data = resolver.as_config_data(file_referrer);
+ let valid_referrer = specifier.clone();
+ let jsx_import_source_config =
+ config_data.and_then(|d| d.maybe_jsx_import_source_config());
+ let resolver = SingleReferrerGraphResolver {
+ valid_referrer: &valid_referrer,
+ referrer_kind: is_cjs_resolver.get_lsp_referrer_kind(
+ &specifier,
+ Some(parsed_source.compute_is_script()),
+ ),
+ cli_resolver,
+ jsx_import_source_config: jsx_import_source_config.as_ref(),
+ };
Ok(deno_graph::parse_module_from_ast(
deno_graph::ParseModuleFromAstOptions {
graph_kind: deno_graph::GraphKind::TypesOnly,
@@ -1551,7 +1643,7 @@ fn analyze_module(
// dynamic imports like import(`./dir/${something}`) in the LSP
file_system: &deno_graph::source::NullFileSystem,
jsr_url_provider: &CliJsrUrlProvider,
- maybe_resolver: Some(resolver.as_graph_resolver(file_referrer)),
+ maybe_resolver: Some(&resolver),
maybe_npm_resolver: Some(&npm_resolver),
},
))
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 2554fa34b..b2bd72416 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -22,6 +22,7 @@ use deno_semver::jsr::JsrPackageReqReference;
use indexmap::Equivalent;
use indexmap::IndexSet;
use log::error;
+use node_resolver::NodeModuleKind;
use serde::Deserialize;
use serde_json::from_value;
use std::collections::BTreeMap;
@@ -77,6 +78,7 @@ use super::parent_process_checker;
use super::performance::Performance;
use super::refactor;
use super::registries::ModuleRegistry;
+use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver;
use super::testing;
use super::text;
@@ -144,6 +146,7 @@ pub struct StateSnapshot {
pub project_version: usize,
pub assets: AssetsSnapshot,
pub config: Arc<Config>,
+ pub is_cjs_resolver: Arc<LspIsCjsResolver>,
pub documents: Arc<Documents>,
pub resolver: Arc<LspResolver>,
}
@@ -203,6 +206,7 @@ pub struct Inner {
pub documents: Documents,
http_client_provider: Arc<HttpClientProvider>,
initial_cwd: PathBuf,
+ pub is_cjs_resolver: Arc<LspIsCjsResolver>,
jsr_search_api: CliJsrSearchApi,
/// Handles module registries, which allow discovery of modules
module_registry: ModuleRegistry,
@@ -480,6 +484,7 @@ impl Inner {
let initial_cwd = std::env::current_dir().unwrap_or_else(|_| {
panic!("Could not resolve current working directory")
});
+ let is_cjs_resolver = Arc::new(LspIsCjsResolver::new(&cache));
Self {
assets,
@@ -491,6 +496,7 @@ impl Inner {
documents,
http_client_provider,
initial_cwd: initial_cwd.clone(),
+ is_cjs_resolver,
jsr_search_api,
project_version: 0,
task_queue: Default::default(),
@@ -601,6 +607,7 @@ impl Inner {
project_version: self.project_version,
assets: self.assets.snapshot(),
config: Arc::new(self.config.clone()),
+ is_cjs_resolver: self.is_cjs_resolver.clone(),
documents: Arc::new(self.documents.clone()),
resolver: self.resolver.snapshot(),
})
@@ -622,6 +629,7 @@ impl Inner {
}
});
self.cache = LspCache::new(global_cache_url);
+ self.is_cjs_resolver = Arc::new(LspIsCjsResolver::new(&self.cache));
let deno_dir = self.cache.deno_dir();
let workspace_settings = self.config.workspace_settings();
let maybe_root_path = self
@@ -982,7 +990,7 @@ impl Inner {
spawn(async move {
let specifier = {
let inner = ls.inner.read().await;
- let resolver = inner.resolver.as_graph_resolver(Some(&referrer));
+ let resolver = inner.resolver.as_cli_resolver(Some(&referrer));
let Ok(specifier) = resolver.resolve(
&specifier,
&deno_graph::Range {
@@ -990,6 +998,7 @@ impl Inner {
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ NodeModuleKind::Esm,
deno_graph::source::ResolutionMode::Types,
) else {
return;
@@ -1622,6 +1631,10 @@ impl Inner {
let file_diagnostics = self
.diagnostics_server
.get_ts_diagnostics(&specifier, asset_or_doc.document_lsp_version());
+ let specifier_kind = asset_or_doc
+ .document()
+ .map(|d| self.is_cjs_resolver.get_doc_module_kind(d))
+ .unwrap_or(NodeModuleKind::Esm);
let mut includes_no_cache = false;
for diagnostic in &fixable_diagnostics {
match diagnostic.source.as_deref() {
@@ -1660,7 +1673,13 @@ impl Inner {
.await;
for action in actions {
code_actions
- .add_ts_fix_action(&specifier, &action, diagnostic, self)
+ .add_ts_fix_action(
+ &specifier,
+ specifier_kind,
+ &action,
+ diagnostic,
+ self,
+ )
.map_err(|err| {
error!("Unable to convert fix: {:#}", err);
LspError::internal_error()
@@ -1806,10 +1825,9 @@ impl Inner {
error!("Unable to decode code action data: {:#}", err);
LspError::invalid_params("The CodeAction's data is invalid.")
})?;
- let scope = self
- .get_asset_or_document(&code_action_data.specifier)
- .ok()
- .and_then(|d| d.scope().cloned());
+ let maybe_asset_or_doc =
+ self.get_asset_or_document(&code_action_data.specifier).ok();
+ let scope = maybe_asset_or_doc.as_ref().and_then(|d| d.scope().cloned());
let combined_code_actions = self
.ts_server
.get_combined_code_fix(
@@ -1836,6 +1854,11 @@ impl Inner {
let changes = if code_action_data.fix_id == "fixMissingImport" {
fix_ts_import_changes(
&code_action_data.specifier,
+ maybe_asset_or_doc
+ .as_ref()
+ .and_then(|d| d.document())
+ .map(|d| self.is_cjs_resolver.get_doc_module_kind(d))
+ .unwrap_or(NodeModuleKind::Esm),
&combined_code_actions.changes,
self,
)
@@ -1889,6 +1912,10 @@ impl Inner {
if kind_suffix == ".rewrite.function.returnType" {
refactor_edit_info.edits = fix_ts_import_changes(
&action_data.specifier,
+ asset_or_doc
+ .document()
+ .map(|d| self.is_cjs_resolver.get_doc_module_kind(d))
+ .unwrap_or(NodeModuleKind::Esm),
&refactor_edit_info.edits,
self,
)
@@ -2238,6 +2265,7 @@ impl Inner {
&self.jsr_search_api,
&self.npm_search_api,
&self.documents,
+ &self.is_cjs_resolver,
self.resolver.as_ref(),
self
.config
diff --git a/cli/lsp/repl.rs b/cli/lsp/repl.rs
index fa5809045..b4aaa8cd0 100644
--- a/cli/lsp/repl.rs
+++ b/cli/lsp/repl.rs
@@ -263,7 +263,7 @@ impl ReplLanguageServer {
}
fn get_document_uri(&self) -> Uri {
- uri_parse_unencoded(self.cwd_uri.join("$deno$repl.ts").unwrap().as_str())
+ uri_parse_unencoded(self.cwd_uri.join("$deno$repl.mts").unwrap().as_str())
.unwrap()
}
}
diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs
index f5df24d57..37f63b912 100644
--- a/cli/lsp/resolver.rs
+++ b/cli/lsp/resolver.rs
@@ -2,16 +2,18 @@
use dashmap::DashMap;
use deno_ast::MediaType;
-use deno_ast::ParsedSource;
use deno_cache_dir::npm::NpmCacheDir;
use deno_cache_dir::HttpCache;
+use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::PackageJsonDepResolution;
use deno_config::workspace::WorkspaceResolver;
use deno_core::url::Url;
-use deno_graph::source::Resolver;
+use deno_graph::source::ResolutionMode;
use deno_graph::GraphImport;
use deno_graph::ModuleSpecifier;
+use deno_graph::Range;
use deno_npm::NpmSystemInfo;
+use deno_path_util::url_from_directory_path;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::NodeResolver;
@@ -24,6 +26,7 @@ use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker;
+use node_resolver::NodeModuleKind;
use node_resolver::NodeResolutionMode;
use std::borrow::Cow;
use std::collections::BTreeMap;
@@ -33,6 +36,7 @@ use std::collections::HashSet;
use std::sync::Arc;
use super::cache::LspCache;
+use super::documents::Document;
use super::jsr::JsrCacheResolver;
use crate::args::create_default_npmrc;
use crate::args::CacheSetting;
@@ -53,21 +57,20 @@ use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::npm::ManagedCliNpmResolver;
-use crate::resolver::CjsTracker;
-use crate::resolver::CjsTrackerOptions;
use crate::resolver::CliDenoResolverFs;
-use crate::resolver::CliGraphResolver;
-use crate::resolver::CliGraphResolverOptions;
use crate::resolver::CliNodeResolver;
+use crate::resolver::CliResolver;
+use crate::resolver::CliResolverOptions;
+use crate::resolver::IsCjsResolver;
use crate::resolver::WorkerCliNpmGraphResolver;
use crate::tsc::into_specifier_and_media_type;
+use crate::util::fs::canonicalize_path_maybe_not_exists;
use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle;
#[derive(Debug, Clone)]
struct LspScopeResolver {
- cjs_tracker: Option<Arc<LspCjsTracker>>,
- graph_resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
jsr_resolver: Option<Arc<JsrCacheResolver>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
node_resolver: Option<Arc<CliNodeResolver>>,
@@ -81,8 +84,7 @@ struct LspScopeResolver {
impl Default for LspScopeResolver {
fn default() -> Self {
Self {
- cjs_tracker: None,
- graph_resolver: create_graph_resolver(None, None, None),
+ resolver: create_cli_resolver(None, None, None),
jsr_resolver: None,
npm_resolver: None,
node_resolver: None,
@@ -103,7 +105,6 @@ impl LspScopeResolver {
) -> Self {
let mut npm_resolver = None;
let mut node_resolver = None;
- let mut lsp_cjs_tracker = None;
let fs = Arc::new(deno_fs::RealFs);
let pkg_json_resolver = Arc::new(PackageJsonResolver::new(
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
@@ -118,14 +119,7 @@ impl LspScopeResolver {
.await;
if let Some(npm_resolver) = &npm_resolver {
let in_npm_pkg_checker = create_in_npm_pkg_checker(npm_resolver);
- let cjs_tracker = create_cjs_tracker(
- in_npm_pkg_checker.clone(),
- pkg_json_resolver.clone(),
- );
- lsp_cjs_tracker =
- Some(Arc::new(LspCjsTracker::new(cjs_tracker.clone())));
node_resolver = Some(create_node_resolver(
- cjs_tracker,
fs.clone(),
in_npm_pkg_checker,
npm_resolver,
@@ -133,7 +127,7 @@ impl LspScopeResolver {
));
}
}
- let graph_resolver = create_graph_resolver(
+ let cli_resolver = create_cli_resolver(
config_data.map(|d| d.as_ref()),
npm_resolver.as_ref(),
node_resolver.as_ref(),
@@ -146,7 +140,9 @@ 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 = graph_resolver.create_graph_npm_resolver();
+ let npm_graph_resolver = cli_resolver.create_graph_npm_resolver();
+ let maybe_jsx_import_source_config =
+ config_data.and_then(|d| d.maybe_jsx_import_source_config());
let graph_imports = config_data
.and_then(|d| d.member_dir.workspace.to_compiler_option_types().ok())
.map(|imports| {
@@ -154,11 +150,18 @@ impl LspScopeResolver {
imports
.into_iter()
.map(|(referrer, imports)| {
+ let resolver = SingleReferrerGraphResolver {
+ valid_referrer: &referrer,
+ referrer_kind: NodeModuleKind::Esm,
+ cli_resolver: &cli_resolver,
+ jsx_import_source_config: maybe_jsx_import_source_config
+ .as_ref(),
+ };
let graph_import = GraphImport::new(
&referrer,
imports,
&CliJsrUrlProvider,
- Some(graph_resolver.as_ref()),
+ Some(&resolver),
Some(&npm_graph_resolver),
);
(referrer, graph_import)
@@ -182,6 +185,8 @@ impl LspScopeResolver {
.resolve_req_reference(
&req_ref,
&referrer,
+ // todo(dsherret): this is wrong because it doesn't consider CJS referrers
+ NodeModuleKind::Esm,
NodeResolutionMode::Types,
)
.ok()?,
@@ -195,8 +200,7 @@ impl LspScopeResolver {
let package_json_deps_by_resolution =
Arc::new(package_json_deps_by_resolution.unwrap_or_default());
Self {
- cjs_tracker: lsp_cjs_tracker,
- graph_resolver,
+ resolver: cli_resolver,
jsr_resolver,
npm_resolver,
node_resolver,
@@ -216,30 +220,22 @@ impl LspScopeResolver {
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
));
let mut node_resolver = None;
- let mut lsp_cjs_tracker = None;
if let Some(npm_resolver) = &npm_resolver {
let in_npm_pkg_checker = create_in_npm_pkg_checker(npm_resolver);
- let cjs_tracker = create_cjs_tracker(
- in_npm_pkg_checker.clone(),
- pkg_json_resolver.clone(),
- );
- lsp_cjs_tracker = Some(Arc::new(LspCjsTracker::new(cjs_tracker.clone())));
node_resolver = Some(create_node_resolver(
- cjs_tracker,
fs,
in_npm_pkg_checker,
npm_resolver,
pkg_json_resolver.clone(),
));
}
- let graph_resolver = create_graph_resolver(
+ let graph_resolver = create_cli_resolver(
self.config_data.as_deref(),
npm_resolver.as_ref(),
node_resolver.as_ref(),
);
Arc::new(Self {
- cjs_tracker: lsp_cjs_tracker,
- graph_resolver,
+ resolver: graph_resolver,
jsr_resolver: self.jsr_resolver.clone(),
npm_resolver,
node_resolver,
@@ -334,12 +330,12 @@ impl LspResolver {
}
}
- pub fn as_graph_resolver(
+ pub fn as_cli_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
- ) -> &dyn Resolver {
+ ) -> &CliResolver {
let resolver = self.get_scope_resolver(file_referrer);
- resolver.graph_resolver.as_ref()
+ resolver.resolver.as_ref()
}
pub fn create_graph_npm_resolver(
@@ -347,15 +343,15 @@ impl LspResolver {
file_referrer: Option<&ModuleSpecifier>,
) -> WorkerCliNpmGraphResolver {
let resolver = self.get_scope_resolver(file_referrer);
- resolver.graph_resolver.create_graph_npm_resolver()
+ resolver.resolver.create_graph_npm_resolver()
}
- pub fn maybe_cjs_tracker(
+ pub fn as_config_data(
&self,
file_referrer: Option<&ModuleSpecifier>,
- ) -> Option<&Arc<LspCjsTracker>> {
+ ) -> Option<&Arc<ConfigData>> {
let resolver = self.get_scope_resolver(file_referrer);
- resolver.cjs_tracker.as_ref()
+ resolver.config_data.as_ref()
}
pub fn maybe_node_resolver(
@@ -429,13 +425,19 @@ impl LspResolver {
&self,
req_ref: &NpmPackageReqReference,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
let resolver = self.get_scope_resolver(file_referrer);
let node_resolver = resolver.node_resolver.as_ref()?;
Some(into_specifier_and_media_type(Some(
node_resolver
- .resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
+ .resolve_req_reference(
+ req_ref,
+ referrer,
+ referrer_kind,
+ NodeResolutionMode::Types,
+ )
.ok()?,
)))
}
@@ -478,6 +480,7 @@ impl LspResolver {
&self,
specifier_text: &str,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
) -> bool {
let resolver = self.get_scope_resolver(Some(referrer));
let Some(node_resolver) = resolver.node_resolver.as_ref() else {
@@ -487,6 +490,7 @@ impl LspResolver {
.resolve_if_for_npm_pkg(
specifier_text,
referrer,
+ referrer_kind,
NodeResolutionMode::Types,
)
.ok()
@@ -615,21 +619,6 @@ async fn create_npm_resolver(
Some(create_cli_npm_resolver_for_lsp(options).await)
}
-fn create_cjs_tracker(
- in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
- pkg_json_resolver: Arc<PackageJsonResolver>,
-) -> Arc<CjsTracker> {
- Arc::new(CjsTracker::new(
- in_npm_pkg_checker,
- pkg_json_resolver,
- CjsTrackerOptions {
- // todo(dsherret): support in the lsp by stabilizing the feature
- // so that we don't have to pipe the config in here
- unstable_detect_cjs: false,
- },
- ))
-}
-
fn create_in_npm_pkg_checker(
npm_resolver: &Arc<dyn CliNpmResolver>,
) -> Arc<dyn InNpmPackageChecker> {
@@ -649,7 +638,6 @@ fn create_in_npm_pkg_checker(
}
fn create_node_resolver(
- cjs_tracker: Arc<CjsTracker>,
fs: Arc<dyn deno_fs::FileSystem>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
npm_resolver: &Arc<dyn CliNpmResolver>,
@@ -662,7 +650,6 @@ fn create_node_resolver(
pkg_json_resolver.clone(),
));
Arc::new(CliNodeResolver::new(
- cjs_tracker.clone(),
fs,
in_npm_pkg_checker,
node_resolver_inner,
@@ -670,13 +657,12 @@ fn create_node_resolver(
))
}
-fn create_graph_resolver(
+fn create_cli_resolver(
config_data: Option<&ConfigData>,
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
node_resolver: Option<&Arc<CliNodeResolver>>,
-) -> Arc<CliGraphResolver> {
- let workspace = config_data.map(|d| &d.member_dir.workspace);
- Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
+) -> Arc<CliResolver> {
+ Arc::new(CliResolver::new(CliResolverOptions {
node_resolver: node_resolver.cloned(),
npm_resolver: npm_resolver.cloned(),
workspace_resolver: config_data.map(|d| d.resolver.clone()).unwrap_or_else(
@@ -691,9 +677,6 @@ fn create_graph_resolver(
))
},
),
- maybe_jsx_import_source_config: workspace.and_then(|workspace| {
- workspace.to_maybe_jsx_import_source_config().ok().flatten()
- }),
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
bare_node_builtins_enabled: config_data
.is_some_and(|d| d.unstable.contains("bare-node-builtins")),
@@ -726,6 +709,141 @@ impl std::fmt::Debug for RedirectResolver {
}
}
+#[derive(Debug)]
+pub struct LspIsCjsResolver {
+ inner: IsCjsResolver,
+}
+
+impl Default for LspIsCjsResolver {
+ fn default() -> Self {
+ LspIsCjsResolver::new(&Default::default())
+ }
+}
+
+impl LspIsCjsResolver {
+ pub fn new(cache: &LspCache) -> Self {
+ #[derive(Debug)]
+ struct LspInNpmPackageChecker {
+ global_cache_dir: ModuleSpecifier,
+ }
+
+ impl LspInNpmPackageChecker {
+ pub fn new(cache: &LspCache) -> Self {
+ let npm_folder_path = cache.deno_dir().npm_folder_path();
+ Self {
+ global_cache_dir: url_from_directory_path(
+ &canonicalize_path_maybe_not_exists(&npm_folder_path)
+ .unwrap_or(npm_folder_path),
+ )
+ .unwrap_or_else(|_| {
+ ModuleSpecifier::parse("file:///invalid/").unwrap()
+ }),
+ }
+ }
+ }
+
+ impl InNpmPackageChecker for LspInNpmPackageChecker {
+ fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
+ if specifier.scheme() != "file" {
+ return false;
+ }
+ if specifier
+ .as_str()
+ .starts_with(self.global_cache_dir.as_str())
+ {
+ return true;
+ }
+ specifier.as_str().contains("/node_modules/")
+ }
+ }
+
+ let fs = Arc::new(deno_fs::RealFs);
+ let pkg_json_resolver = Arc::new(PackageJsonResolver::new(
+ deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
+ ));
+
+ LspIsCjsResolver {
+ inner: IsCjsResolver::new(
+ Arc::new(LspInNpmPackageChecker::new(cache)),
+ pkg_json_resolver,
+ crate::resolver::IsCjsResolverOptions {
+ detect_cjs: true,
+ is_node_main: false,
+ },
+ ),
+ }
+ }
+
+ pub fn get_maybe_doc_module_kind(
+ &self,
+ specifier: &ModuleSpecifier,
+ maybe_document: Option<&Document>,
+ ) -> NodeModuleKind {
+ self.get_lsp_referrer_kind(
+ specifier,
+ maybe_document.and_then(|d| d.is_script()),
+ )
+ }
+
+ pub fn get_doc_module_kind(&self, document: &Document) -> NodeModuleKind {
+ self.get_lsp_referrer_kind(document.specifier(), document.is_script())
+ }
+
+ pub fn get_lsp_referrer_kind(
+ &self,
+ specifier: &ModuleSpecifier,
+ is_script: Option<bool>,
+ ) -> NodeModuleKind {
+ self.inner.get_lsp_referrer_kind(specifier, is_script)
+ }
+}
+
+#[derive(Debug)]
+pub struct SingleReferrerGraphResolver<'a> {
+ pub valid_referrer: &'a ModuleSpecifier,
+ pub referrer_kind: NodeModuleKind,
+ pub cli_resolver: &'a CliResolver,
+ pub jsx_import_source_config: Option<&'a JsxImportSourceConfig>,
+}
+
+impl<'a> deno_graph::source::Resolver for SingleReferrerGraphResolver<'a> {
+ fn default_jsx_import_source(&self) -> Option<String> {
+ self
+ .jsx_import_source_config
+ .and_then(|c| c.default_specifier.clone())
+ }
+
+ fn default_jsx_import_source_types(&self) -> Option<String> {
+ self
+ .jsx_import_source_config
+ .and_then(|c| c.default_types_specifier.clone())
+ }
+
+ fn jsx_import_source_module(&self) -> &str {
+ self
+ .jsx_import_source_config
+ .map(|c| c.module.as_str())
+ .unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
+ }
+
+ fn resolve(
+ &self,
+ specifier_text: &str,
+ referrer_range: &Range,
+ mode: ResolutionMode,
+ ) -> Result<ModuleSpecifier, deno_graph::source::ResolveError> {
+ // this resolver assumes it will only be used with a single referrer
+ // with the provided referrer kind
+ debug_assert_eq!(referrer_range.specifier, *self.valid_referrer);
+ self.cli_resolver.resolve(
+ specifier_text,
+ referrer_range,
+ self.referrer_kind,
+ mode,
+ )
+ }
+}
+
impl RedirectResolver {
fn new(
cache: Arc<dyn HttpCache>,
@@ -842,45 +960,6 @@ impl RedirectResolver {
}
}
-#[derive(Debug)]
-pub struct LspCjsTracker {
- cjs_tracker: Arc<CjsTracker>,
-}
-
-impl LspCjsTracker {
- pub fn new(cjs_tracker: Arc<CjsTracker>) -> Self {
- Self { cjs_tracker }
- }
-
- pub fn is_cjs(
- &self,
- specifier: &ModuleSpecifier,
- media_type: MediaType,
- maybe_parsed_source: Option<&ParsedSource>,
- ) -> bool {
- if let Some(module_kind) =
- self.cjs_tracker.get_known_kind(specifier, media_type)
- {
- module_kind.is_cjs()
- } else {
- let maybe_is_script = maybe_parsed_source.map(|p| p.compute_is_script());
- maybe_is_script
- .and_then(|is_script| {
- self
- .cjs_tracker
- .is_cjs_with_known_is_script(specifier, media_type, is_script)
- .ok()
- })
- .unwrap_or_else(|| {
- self
- .cjs_tracker
- .is_maybe_cjs(specifier, media_type)
- .unwrap_or(false)
- })
- }
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs
index 6f63ced5b..c9b24176a 100644
--- a/cli/lsp/tsc.rs
+++ b/cli/lsp/tsc.rs
@@ -69,6 +69,7 @@ use indexmap::IndexMap;
use indexmap::IndexSet;
use lazy_regex::lazy_regex;
use log::error;
+use node_resolver::NodeModuleKind;
use once_cell::sync::Lazy;
use regex::Captures;
use regex::Regex;
@@ -4401,25 +4402,15 @@ fn op_load<'s>(
None
} else {
let asset_or_document = state.get_asset_or_document(&specifier);
- asset_or_document.map(|doc| {
- let maybe_cjs_tracker = state
- .state_snapshot
- .resolver
- .maybe_cjs_tracker(Some(&specifier));
- LoadResponse {
- data: doc.text(),
- script_kind: crate::tsc::as_ts_script_kind(doc.media_type()),
- version: state.script_version(&specifier),
- is_cjs: maybe_cjs_tracker
- .map(|t| {
- t.is_cjs(
- &specifier,
- doc.media_type(),
- doc.maybe_parsed_source().and_then(|p| p.as_ref().ok()),
- )
- })
- .unwrap_or(false),
- }
+ asset_or_document.map(|doc| LoadResponse {
+ data: doc.text(),
+ script_kind: crate::tsc::as_ts_script_kind(doc.media_type()),
+ version: state.script_version(&specifier),
+ is_cjs: doc
+ .document()
+ .map(|d| state.state_snapshot.is_cjs_resolver.get_doc_module_kind(d))
+ .unwrap_or(NodeModuleKind::Esm)
+ == NodeModuleKind::Cjs,
})
};
@@ -4662,6 +4653,10 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
let (types, _) = documents.resolve_dependency(
types,
specifier,
+ state
+ .state_snapshot
+ .is_cjs_resolver
+ .get_doc_module_kind(doc),
doc.file_referrer(),
)?;
let types_doc = documents.get_or_load(&types, doc.file_referrer())?;
@@ -5544,6 +5539,7 @@ mod tests {
documents: Arc::new(documents),
assets: Default::default(),
config: Arc::new(config),
+ is_cjs_resolver: Default::default(),
resolver,
});
let performance = Arc::new(Performance::default());
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index 43c9e1aa0..f9c974d77 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -27,8 +27,8 @@ use crate::node;
use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver;
use crate::resolver::CjsTracker;
-use crate::resolver::CliGraphResolver;
use crate::resolver::CliNodeResolver;
+use crate::resolver::CliResolver;
use crate::resolver::ModuleCodeStringSource;
use crate::resolver::NotSupportedKindInNpmError;
use crate::resolver::NpmModuleLoader;
@@ -60,7 +60,6 @@ use deno_core::RequestedModuleType;
use deno_core::ResolutionKind;
use deno_core::SourceCodeCacheInfo;
use deno_graph::source::ResolutionMode;
-use deno_graph::source::Resolver;
use deno_graph::GraphKind;
use deno_graph::JsModule;
use deno_graph::JsonModule;
@@ -73,6 +72,7 @@ use deno_runtime::deno_node::create_host_defined_options;
use deno_runtime::deno_node::NodeRequireLoader;
use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
+use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker;
use node_resolver::NodeResolutionMode;
@@ -206,7 +206,6 @@ struct SharedCliModuleLoaderState {
lib_worker: TsTypeLib,
initial_cwd: PathBuf,
is_inspecting: bool,
- is_npm_main: bool,
is_repl: bool,
cjs_tracker: Arc<CjsTracker>,
code_cache: Option<Arc<CodeCache>>,
@@ -220,7 +219,7 @@ struct SharedCliModuleLoaderState {
npm_resolver: Arc<dyn CliNpmResolver>,
npm_module_loader: NpmModuleLoader,
parsed_source_cache: Arc<ParsedSourceCache>,
- resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
}
pub struct CliModuleLoaderFactory {
@@ -243,7 +242,7 @@ impl CliModuleLoaderFactory {
npm_resolver: Arc<dyn CliNpmResolver>,
npm_module_loader: NpmModuleLoader,
parsed_source_cache: Arc<ParsedSourceCache>,
- resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
) -> Self {
Self {
shared: Arc::new(SharedCliModuleLoaderState {
@@ -252,7 +251,6 @@ impl CliModuleLoaderFactory {
lib_worker: options.ts_type_lib_worker(),
initial_cwd: options.initial_cwd().to_path_buf(),
is_inspecting: options.is_inspecting(),
- is_npm_main: options.is_npm_main(),
is_repl: matches!(
options.sub_command(),
DenoSubcommand::Repl(_) | DenoSubcommand::Jupyter(_)
@@ -286,7 +284,6 @@ impl CliModuleLoaderFactory {
Rc::new(CliModuleLoader(Rc::new(CliModuleLoaderInner {
lib,
is_worker,
- is_npm_main: self.shared.is_npm_main,
parent_permissions,
permissions,
graph_container: graph_container.clone(),
@@ -295,13 +292,14 @@ impl CliModuleLoaderFactory {
parsed_source_cache: self.shared.parsed_source_cache.clone(),
shared: self.shared.clone(),
})));
- let node_require_loader = Rc::new(CliNodeRequireLoader::new(
- self.shared.emitter.clone(),
- self.shared.fs.clone(),
+ let node_require_loader = Rc::new(CliNodeRequireLoader {
+ cjs_tracker: self.shared.cjs_tracker.clone(),
+ emitter: self.shared.emitter.clone(),
+ fs: self.shared.fs.clone(),
graph_container,
- self.shared.in_npm_pkg_checker.clone(),
- self.shared.npm_resolver.clone(),
- ));
+ in_npm_pkg_checker: self.shared.in_npm_pkg_checker.clone(),
+ npm_resolver: self.shared.npm_resolver.clone(),
+ });
CreateModuleLoaderResult {
module_loader,
node_require_loader,
@@ -343,7 +341,6 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
lib: TsTypeLib,
- is_npm_main: bool,
is_worker: bool,
/// The initial set of permissions used to resolve the static imports in the
/// worker. These are "allow all" for main worker, and parent thread
@@ -450,7 +447,7 @@ impl<TGraphContainer: ModuleGraphContainer>
let referrer = if referrer.is_empty() && self.shared.is_repl {
// FIXME(bartlomieju): this is a hacky way to provide compatibility with REPL
// and `Deno.core.evalContext` API. Ideally we should always have a referrer filled
- "./$deno$repl.ts"
+ "./$deno$repl.mts"
} else {
referrer
};
@@ -478,7 +475,12 @@ impl<TGraphContainer: ModuleGraphContainer>
self
.shared
.node_resolver
- .resolve(raw_specifier, referrer, NodeResolutionMode::Execution)?
+ .resolve(
+ raw_specifier,
+ referrer,
+ self.shared.cjs_tracker.get_referrer_kind(referrer),
+ NodeResolutionMode::Execution,
+ )?
.into_url(),
);
}
@@ -508,6 +510,7 @@ impl<TGraphContainer: ModuleGraphContainer>
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ self.shared.cjs_tracker.get_referrer_kind(referrer),
ResolutionMode::Execution,
)?),
};
@@ -518,6 +521,7 @@ impl<TGraphContainer: ModuleGraphContainer>
return self.shared.node_resolver.resolve_req_reference(
&reference,
referrer,
+ self.shared.cjs_tracker.get_referrer_kind(referrer),
NodeResolutionMode::Execution,
);
}
@@ -538,6 +542,7 @@ impl<TGraphContainer: ModuleGraphContainer>
&package_folder,
module.nv_reference.sub_path(),
Some(referrer),
+ self.shared.cjs_tracker.get_referrer_kind(referrer),
NodeResolutionMode::Execution,
)
.with_context(|| {
@@ -668,14 +673,11 @@ impl<TGraphContainer: ModuleGraphContainer>
is_script,
..
})) => {
- // todo(dsherret): revert in https://github.com/denoland/deno/pull/26439
- if self.is_npm_main && *is_script
- || self.shared.cjs_tracker.is_cjs_with_known_is_script(
- specifier,
- *media_type,
- *is_script,
- )?
- {
+ if self.shared.cjs_tracker.is_cjs_with_known_is_script(
+ specifier,
+ *media_type,
+ *is_script,
+ )? {
return Ok(Some(CodeOrDeferredEmit::Cjs {
specifier,
media_type: *media_type,
@@ -1031,6 +1033,7 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit {
#[derive(Debug)]
struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
+ cjs_tracker: Arc<CjsTracker>,
emitter: Arc<Emitter>,
fs: Arc<dyn FileSystem>,
graph_container: TGraphContainer,
@@ -1038,26 +1041,6 @@ struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
npm_resolver: Arc<dyn CliNpmResolver>,
}
-impl<TGraphContainer: ModuleGraphContainer>
- CliNodeRequireLoader<TGraphContainer>
-{
- pub fn new(
- emitter: Arc<Emitter>,
- fs: Arc<dyn FileSystem>,
- graph_container: TGraphContainer,
- in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
- npm_resolver: Arc<dyn CliNpmResolver>,
- ) -> Self {
- Self {
- emitter,
- fs,
- graph_container,
- in_npm_pkg_checker,
- npm_resolver,
- }
- }
-}
-
impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
for CliNodeRequireLoader<TGraphContainer>
{
@@ -1103,4 +1086,12 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
Ok(text)
}
}
+
+ fn is_maybe_cjs(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Result<bool, ClosestPkgJsonError> {
+ let media_type = MediaType::from_specifier(specifier);
+ self.cjs_tracker.is_maybe_cjs(specifier, media_type)
+ }
}
diff --git a/cli/node.rs b/cli/node.rs
index 1d410a726..8235745a9 100644
--- a/cli/node.rs
+++ b/cli/node.rs
@@ -62,10 +62,6 @@ pub struct CliCjsCodeAnalyzer {
cjs_tracker: Arc<CjsTracker>,
fs: deno_fs::FileSystemRc,
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
- // todo(dsherret): hack, remove in https://github.com/denoland/deno/pull/26439
- // For example, this does not properly handle if cjs analysis was already done
- // and has been cached.
- is_npm_main: bool,
}
impl CliCjsCodeAnalyzer {
@@ -74,14 +70,12 @@ impl CliCjsCodeAnalyzer {
cjs_tracker: Arc<CjsTracker>,
fs: deno_fs::FileSystemRc,
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
- is_npm_main: bool,
) -> Self {
Self {
cache,
cjs_tracker,
fs,
parsed_source_cache,
- is_npm_main,
}
}
@@ -106,9 +100,7 @@ impl CliCjsCodeAnalyzer {
}
let cjs_tracker = self.cjs_tracker.clone();
- let is_npm_main = self.is_npm_main;
- let is_maybe_cjs =
- cjs_tracker.is_maybe_cjs(specifier, media_type)? || is_npm_main;
+ let is_maybe_cjs = cjs_tracker.is_maybe_cjs(specifier, media_type)?;
let analysis = if is_maybe_cjs {
let maybe_parsed_source = self
.parsed_source_cache
@@ -135,7 +127,7 @@ impl CliCjsCodeAnalyzer {
parsed_source.specifier(),
media_type,
is_script,
- )? || is_script && is_npm_main;
+ )?;
if is_cjs {
let analysis = parsed_source.analyze_cjs();
Ok(CliCjsAnalysis::Cjs {
diff --git a/cli/resolver.rs b/cli/resolver.rs
index 710b97509..786e5d0db 100644
--- a/cli/resolver.rs
+++ b/cli/resolver.rs
@@ -4,7 +4,6 @@ use async_trait::async_trait;
use dashmap::DashMap;
use dashmap::DashSet;
use deno_ast::MediaType;
-use deno_ast::ModuleKind;
use deno_config::workspace::MappedResolution;
use deno_config::workspace::MappedResolutionDiagnostic;
use deno_config::workspace::MappedResolutionError;
@@ -17,9 +16,7 @@ use deno_core::ModuleSourceCode;
use deno_core::ModuleSpecifier;
use deno_graph::source::ResolutionMode;
use deno_graph::source::ResolveError;
-use deno_graph::source::Resolver;
use deno_graph::source::UnknownBuiltInNodeModuleError;
-use deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE;
use deno_graph::NpmLoadError;
use deno_graph::NpmResolvePkgReqsResult;
use deno_npm::resolution::NpmResolutionError;
@@ -52,7 +49,6 @@ use std::path::PathBuf;
use std::sync::Arc;
use thiserror::Error;
-use crate::args::JsxImportSourceConfig;
use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS;
use crate::node::CliNodeCodeTranslator;
use crate::npm::CliNpmResolver;
@@ -108,7 +104,6 @@ impl deno_resolver::fs::DenoResolverFs for CliDenoResolverFs {
#[derive(Debug)]
pub struct CliNodeResolver {
- cjs_tracker: Arc<CjsTracker>,
fs: Arc<dyn deno_fs::FileSystem>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
node_resolver: Arc<NodeResolver>,
@@ -117,14 +112,12 @@ pub struct CliNodeResolver {
impl CliNodeResolver {
pub fn new(
- cjs_tracker: Arc<CjsTracker>,
fs: Arc<dyn deno_fs::FileSystem>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
node_resolver: Arc<NodeResolver>,
npm_resolver: Arc<dyn CliNpmResolver>,
) -> Self {
Self {
- cjs_tracker,
fs,
in_npm_pkg_checker,
node_resolver,
@@ -140,9 +133,11 @@ impl CliNodeResolver {
&self,
specifier: &str,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
mode: NodeResolutionMode,
) -> Result<Option<NodeResolution>, AnyError> {
- let resolution_result = self.resolve(specifier, referrer, mode);
+ let resolution_result =
+ self.resolve(specifier, referrer, referrer_kind, mode);
match resolution_result {
Ok(res) => Ok(Some(res)),
Err(err) => {
@@ -213,35 +208,26 @@ impl CliNodeResolver {
&self,
specifier: &str,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
mode: NodeResolutionMode,
) -> Result<NodeResolution, NodeResolveError> {
- let referrer_kind = if self
- .cjs_tracker
- .is_maybe_cjs(referrer, MediaType::from_specifier(referrer))
- .map_err(|err| NodeResolveErrorKind::PackageResolve(err.into()))?
- {
- NodeModuleKind::Cjs
- } else {
- NodeModuleKind::Esm
- };
-
- let res =
- self
- .node_resolver
- .resolve(specifier, referrer, referrer_kind, mode)?;
- Ok(res)
+ self
+ .node_resolver
+ .resolve(specifier, referrer, referrer_kind, mode)
}
pub fn resolve_req_reference(
&self,
req_ref: &NpmPackageReqReference,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
mode: NodeResolutionMode,
) -> Result<ModuleSpecifier, AnyError> {
self.resolve_req_with_sub_path(
req_ref.req(),
req_ref.sub_path(),
referrer,
+ referrer_kind,
mode,
)
}
@@ -251,6 +237,7 @@ impl CliNodeResolver {
req: &PackageReq,
sub_path: Option<&str>,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
mode: NodeResolutionMode,
) -> Result<ModuleSpecifier, AnyError> {
let package_folder = self
@@ -260,6 +247,7 @@ impl CliNodeResolver {
&package_folder,
sub_path,
Some(referrer),
+ referrer_kind,
mode,
);
match resolution_result {
@@ -284,12 +272,14 @@ impl CliNodeResolver {
package_folder: &Path,
sub_path: Option<&str>,
maybe_referrer: Option<&ModuleSpecifier>,
+ referrer_kind: NodeModuleKind,
mode: NodeResolutionMode,
) -> Result<ModuleSpecifier, PackageSubpathResolveError> {
self.node_resolver.resolve_package_subpath_from_deno_module(
package_folder,
sub_path,
maybe_referrer,
+ referrer_kind,
mode,
)
}
@@ -419,10 +409,6 @@ impl NpmModuleLoader {
}
}
-pub struct CjsTrackerOptions {
- pub unstable_detect_cjs: bool,
-}
-
/// Keeps track of what module specifiers were resolved as CJS.
///
/// Modules that are `.js` or `.ts` are only known to be CJS or
@@ -430,22 +416,22 @@ pub struct CjsTrackerOptions {
/// will be "maybe CJS" until they're loaded.
#[derive(Debug)]
pub struct CjsTracker {
- in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
- pkg_json_resolver: Arc<PackageJsonResolver>,
- unstable_detect_cjs: bool,
- known: DashMap<ModuleSpecifier, ModuleKind>,
+ is_cjs_resolver: IsCjsResolver,
+ known: DashMap<ModuleSpecifier, NodeModuleKind>,
}
impl CjsTracker {
pub fn new(
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
pkg_json_resolver: Arc<PackageJsonResolver>,
- options: CjsTrackerOptions,
+ options: IsCjsResolverOptions,
) -> Self {
Self {
- in_npm_pkg_checker,
- pkg_json_resolver,
- unstable_detect_cjs: options.unstable_detect_cjs,
+ is_cjs_resolver: IsCjsResolver::new(
+ in_npm_pkg_checker,
+ pkg_json_resolver,
+ options,
+ ),
known: Default::default(),
}
}
@@ -485,47 +471,135 @@ impl CjsTracker {
.get_known_kind_with_is_script(specifier, media_type, is_script)
{
Some(kind) => kind,
- None => self.check_based_on_pkg_json(specifier)?,
+ None => self.is_cjs_resolver.check_based_on_pkg_json(specifier)?,
};
- Ok(kind.is_cjs())
+ Ok(kind == NodeModuleKind::Cjs)
}
pub fn get_known_kind(
&self,
specifier: &ModuleSpecifier,
media_type: MediaType,
- ) -> Option<ModuleKind> {
+ ) -> Option<NodeModuleKind> {
self.get_known_kind_with_is_script(specifier, media_type, None)
}
+ pub fn get_referrer_kind(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> NodeModuleKind {
+ if specifier.scheme() != "file" {
+ return NodeModuleKind::Esm;
+ }
+ self
+ .get_known_kind(specifier, MediaType::from_specifier(specifier))
+ .unwrap_or(NodeModuleKind::Esm)
+ }
+
+ fn get_known_kind_with_is_script(
+ &self,
+ specifier: &ModuleSpecifier,
+ media_type: MediaType,
+ is_script: Option<bool>,
+ ) -> Option<NodeModuleKind> {
+ self.is_cjs_resolver.get_known_kind_with_is_script(
+ specifier,
+ media_type,
+ is_script,
+ &self.known,
+ )
+ }
+}
+
+#[derive(Debug)]
+pub struct IsCjsResolverOptions {
+ pub detect_cjs: bool,
+ pub is_node_main: bool,
+}
+
+#[derive(Debug)]
+pub struct IsCjsResolver {
+ in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
+ pkg_json_resolver: Arc<PackageJsonResolver>,
+ options: IsCjsResolverOptions,
+}
+
+impl IsCjsResolver {
+ pub fn new(
+ in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
+ pkg_json_resolver: Arc<PackageJsonResolver>,
+ options: IsCjsResolverOptions,
+ ) -> Self {
+ Self {
+ in_npm_pkg_checker,
+ pkg_json_resolver,
+ options,
+ }
+ }
+
+ pub fn get_lsp_referrer_kind(
+ &self,
+ specifier: &ModuleSpecifier,
+ is_script: Option<bool>,
+ ) -> NodeModuleKind {
+ if specifier.scheme() != "file" {
+ return NodeModuleKind::Esm;
+ }
+ match MediaType::from_specifier(specifier) {
+ MediaType::Mts | MediaType::Mjs | MediaType::Dmts => NodeModuleKind::Esm,
+ MediaType::Cjs | MediaType::Cts | MediaType::Dcts => NodeModuleKind::Cjs,
+ MediaType::Dts => {
+ // dts files are always determined based on the package.json because
+ // they contain imports/exports even when considered CJS
+ self.check_based_on_pkg_json(specifier).unwrap_or(NodeModuleKind::Esm)
+ }
+ MediaType::Wasm |
+ MediaType::Json => NodeModuleKind::Esm,
+ MediaType::JavaScript
+ | MediaType::Jsx
+ | MediaType::TypeScript
+ | MediaType::Tsx
+ // treat these as unknown
+ | MediaType::Css
+ | MediaType::SourceMap
+ | MediaType::Unknown => {
+ match is_script {
+ Some(true) => self.check_based_on_pkg_json(specifier).unwrap_or(NodeModuleKind::Esm),
+ Some(false) | None => NodeModuleKind::Esm,
+ }
+ }
+ }
+ }
+
fn get_known_kind_with_is_script(
&self,
specifier: &ModuleSpecifier,
media_type: MediaType,
is_script: Option<bool>,
- ) -> Option<ModuleKind> {
+ known_cache: &DashMap<ModuleSpecifier, NodeModuleKind>,
+ ) -> Option<NodeModuleKind> {
if specifier.scheme() != "file" {
- return Some(ModuleKind::Esm);
+ return Some(NodeModuleKind::Esm);
}
match media_type {
- MediaType::Mts | MediaType::Mjs | MediaType::Dmts => Some(ModuleKind::Esm),
- MediaType::Cjs | MediaType::Cts | MediaType::Dcts => Some(ModuleKind::Cjs),
+ MediaType::Mts | MediaType::Mjs | MediaType::Dmts => Some(NodeModuleKind::Esm),
+ MediaType::Cjs | MediaType::Cts | MediaType::Dcts => Some(NodeModuleKind::Cjs),
MediaType::Dts => {
// dts files are always determined based on the package.json because
// they contain imports/exports even when considered CJS
- if let Some(value) = self.known.get(specifier).map(|v| *v) {
+ if let Some(value) = known_cache.get(specifier).map(|v| *v) {
Some(value)
} else {
let value = self.check_based_on_pkg_json(specifier).ok();
if let Some(value) = value {
- self.known.insert(specifier.clone(), value);
+ known_cache.insert(specifier.clone(), value);
}
- Some(value.unwrap_or(ModuleKind::Esm))
+ Some(value.unwrap_or(NodeModuleKind::Esm))
}
}
MediaType::Wasm |
- MediaType::Json => Some(ModuleKind::Esm),
+ MediaType::Json => Some(NodeModuleKind::Esm),
MediaType::JavaScript
| MediaType::Jsx
| MediaType::TypeScript
@@ -534,18 +608,18 @@ impl CjsTracker {
| MediaType::Css
| MediaType::SourceMap
| MediaType::Unknown => {
- if let Some(value) = self.known.get(specifier).map(|v| *v) {
- if value.is_cjs() && is_script == Some(false) {
+ if let Some(value) = known_cache.get(specifier).map(|v| *v) {
+ if value == NodeModuleKind::Cjs && is_script == Some(false) {
// we now know this is actually esm
- self.known.insert(specifier.clone(), ModuleKind::Esm);
- Some(ModuleKind::Esm)
+ known_cache.insert(specifier.clone(), NodeModuleKind::Esm);
+ Some(NodeModuleKind::Esm)
} else {
Some(value)
}
} else if is_script == Some(false) {
// we know this is esm
- self.known.insert(specifier.clone(), ModuleKind::Esm);
- Some(ModuleKind::Esm)
+ known_cache.insert(specifier.clone(), NodeModuleKind::Esm);
+ Some(NodeModuleKind::Esm)
} else {
None
}
@@ -556,27 +630,38 @@ impl CjsTracker {
fn check_based_on_pkg_json(
&self,
specifier: &ModuleSpecifier,
- ) -> Result<ModuleKind, ClosestPkgJsonError> {
+ ) -> Result<NodeModuleKind, ClosestPkgJsonError> {
if self.in_npm_pkg_checker.in_npm_package(specifier) {
if let Some(pkg_json) =
self.pkg_json_resolver.get_closest_package_json(specifier)?
{
let is_file_location_cjs = pkg_json.typ != "module";
- Ok(ModuleKind::from_is_cjs(is_file_location_cjs))
+ Ok(if is_file_location_cjs {
+ NodeModuleKind::Cjs
+ } else {
+ NodeModuleKind::Esm
+ })
} else {
- Ok(ModuleKind::Cjs)
+ Ok(NodeModuleKind::Cjs)
}
- } else if self.unstable_detect_cjs {
+ } else if self.options.detect_cjs || self.options.is_node_main {
if let Some(pkg_json) =
self.pkg_json_resolver.get_closest_package_json(specifier)?
{
- let is_cjs_type = pkg_json.typ == "commonjs";
- Ok(ModuleKind::from_is_cjs(is_cjs_type))
+ let is_cjs_type = pkg_json.typ == "commonjs"
+ || self.options.is_node_main && pkg_json.typ == "none";
+ Ok(if is_cjs_type {
+ NodeModuleKind::Cjs
+ } else {
+ NodeModuleKind::Esm
+ })
+ } else if self.options.is_node_main {
+ Ok(NodeModuleKind::Cjs)
} else {
- Ok(ModuleKind::Esm)
+ Ok(NodeModuleKind::Esm)
}
} else {
- Ok(ModuleKind::Esm)
+ Ok(NodeModuleKind::Esm)
}
}
}
@@ -587,48 +672,33 @@ pub type CliSloppyImportsResolver =
/// A resolver that takes care of resolution, taking into account loaded
/// import map, JSX settings.
#[derive(Debug)]
-pub struct CliGraphResolver {
+pub struct CliResolver {
node_resolver: Option<Arc<CliNodeResolver>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
workspace_resolver: Arc<WorkspaceResolver>,
- maybe_default_jsx_import_source: Option<String>,
- maybe_default_jsx_import_source_types: Option<String>,
- maybe_jsx_import_source_module: Option<String>,
maybe_vendor_specifier: Option<ModuleSpecifier>,
found_package_json_dep_flag: AtomicFlag,
bare_node_builtins_enabled: bool,
warned_pkgs: DashSet<PackageReq>,
}
-pub struct CliGraphResolverOptions<'a> {
+pub struct CliResolverOptions<'a> {
pub node_resolver: Option<Arc<CliNodeResolver>>,
pub npm_resolver: Option<Arc<dyn CliNpmResolver>>,
pub sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
pub workspace_resolver: Arc<WorkspaceResolver>,
pub bare_node_builtins_enabled: bool,
- pub maybe_jsx_import_source_config: Option<JsxImportSourceConfig>,
pub maybe_vendor_dir: Option<&'a PathBuf>,
}
-impl CliGraphResolver {
- pub fn new(options: CliGraphResolverOptions) -> Self {
+impl CliResolver {
+ pub fn new(options: CliResolverOptions) -> Self {
Self {
node_resolver: options.node_resolver,
npm_resolver: options.npm_resolver,
sloppy_imports_resolver: options.sloppy_imports_resolver,
workspace_resolver: options.workspace_resolver,
- maybe_default_jsx_import_source: options
- .maybe_jsx_import_source_config
- .as_ref()
- .and_then(|c| c.default_specifier.clone()),
- maybe_default_jsx_import_source_types: options
- .maybe_jsx_import_source_config
- .as_ref()
- .and_then(|c| c.default_types_specifier.clone()),
- maybe_jsx_import_source_module: options
- .maybe_jsx_import_source_config
- .map(|c| c.module),
maybe_vendor_specifier: options
.maybe_vendor_dir
.and_then(|v| ModuleSpecifier::from_directory_path(v).ok()),
@@ -638,10 +708,6 @@ impl CliGraphResolver {
}
}
- pub fn as_graph_resolver(&self) -> &dyn Resolver {
- self
- }
-
pub fn create_graph_npm_resolver(&self) -> WorkerCliNpmGraphResolver {
WorkerCliNpmGraphResolver {
npm_resolver: self.npm_resolver.as_ref(),
@@ -649,28 +715,12 @@ impl CliGraphResolver {
bare_node_builtins_enabled: self.bare_node_builtins_enabled,
}
}
-}
-
-impl Resolver for CliGraphResolver {
- fn default_jsx_import_source(&self) -> Option<String> {
- self.maybe_default_jsx_import_source.clone()
- }
-
- fn default_jsx_import_source_types(&self) -> Option<String> {
- self.maybe_default_jsx_import_source_types.clone()
- }
- fn jsx_import_source_module(&self) -> &str {
- self
- .maybe_jsx_import_source_module
- .as_deref()
- .unwrap_or(DEFAULT_JSX_IMPORT_SOURCE_MODULE)
- }
-
- fn resolve(
+ pub fn resolve(
&self,
raw_specifier: &str,
referrer_range: &deno_graph::Range,
+ referrer_kind: NodeModuleKind,
mode: ResolutionMode,
) -> Result<ModuleSpecifier, ResolveError> {
fn to_node_mode(mode: ResolutionMode) -> NodeResolutionMode {
@@ -686,7 +736,7 @@ impl Resolver for CliGraphResolver {
if let Some(node_resolver) = self.node_resolver.as_ref() {
if referrer.scheme() == "file" && node_resolver.in_npm_package(referrer) {
return node_resolver
- .resolve(raw_specifier, referrer, to_node_mode(mode))
+ .resolve(raw_specifier, referrer, referrer_kind, to_node_mode(mode))
.map(|res| res.into_url())
.map_err(|e| ResolveError::Other(e.into()));
}
@@ -759,6 +809,7 @@ impl Resolver for CliGraphResolver {
pkg_json.dir_path(),
sub_path.as_deref(),
Some(referrer),
+ referrer_kind,
to_node_mode(mode),
)
.map_err(|e| ResolveError::Other(e.into())),
@@ -800,6 +851,7 @@ impl Resolver for CliGraphResolver {
pkg_folder,
sub_path.as_deref(),
Some(referrer),
+ referrer_kind,
to_node_mode(mode),
)
.map_err(|e| ResolveError::Other(e.into()))
@@ -847,6 +899,7 @@ impl Resolver for CliGraphResolver {
pkg_folder,
npm_req_ref.sub_path(),
Some(referrer),
+ referrer_kind,
to_node_mode(mode),
)
.map_err(|e| ResolveError::Other(e.into()));
@@ -855,7 +908,12 @@ impl Resolver for CliGraphResolver {
// do npm resolution for byonm
if is_byonm {
return node_resolver
- .resolve_req_reference(&npm_req_ref, referrer, to_node_mode(mode))
+ .resolve_req_reference(
+ &npm_req_ref,
+ referrer,
+ referrer_kind,
+ to_node_mode(mode),
+ )
.map_err(|err| err.into());
}
}
@@ -869,7 +927,12 @@ impl Resolver for CliGraphResolver {
// If byonm, check if the bare specifier resolves to an npm package
if is_byonm && referrer.scheme() == "file" {
let maybe_resolution = node_resolver
- .resolve_if_for_npm_pkg(raw_specifier, referrer, to_node_mode(mode))
+ .resolve_if_for_npm_pkg(
+ raw_specifier,
+ referrer,
+ referrer_kind,
+ to_node_mode(mode),
+ )
.map_err(ResolveError::Other)?;
if let Some(res) = maybe_resolution {
match res {
diff --git a/cli/schemas/config-file.v1.json b/cli/schemas/config-file.v1.json
index 27c8499ea..ed80eb17b 100644
--- a/cli/schemas/config-file.v1.json
+++ b/cli/schemas/config-file.v1.json
@@ -528,7 +528,6 @@
"bare-node-builtins",
"byonm",
"cron",
- "detect-cjs",
"ffi",
"fs",
"fmt-component",
diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs
index 960aad157..b48e1c97c 100644
--- a/cli/standalone/binary.rs
+++ b/cli/standalone/binary.rs
@@ -720,7 +720,6 @@ impl<'a> DenoCompileBinaryWriter<'a> {
unstable_config: UnstableConfig {
legacy_flag_enabled: false,
bare_node_builtins: cli_options.unstable_bare_node_builtins(),
- detect_cjs: cli_options.unstable_detect_cjs(),
sloppy_imports: cli_options.unstable_sloppy_imports(),
features: cli_options.unstable_features(),
},
diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs
index bb0ab423d..15937c7ae 100644
--- a/cli/standalone/mod.rs
+++ b/cli/standalone/mod.rs
@@ -45,6 +45,8 @@ use deno_runtime::WorkerLogLevel;
use deno_semver::npm::NpmPackageReqReference;
use import_map::parse_from_json;
use node_resolver::analyze::NodeCodeTranslator;
+use node_resolver::errors::ClosestPkgJsonError;
+use node_resolver::NodeModuleKind;
use node_resolver::NodeResolutionMode;
use serialization::DenoCompileModuleSource;
use std::borrow::Cow;
@@ -76,9 +78,9 @@ use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::resolver::CjsTracker;
-use crate::resolver::CjsTrackerOptions;
use crate::resolver::CliDenoResolverFs;
use crate::resolver::CliNodeResolver;
+use crate::resolver::IsCjsResolverOptions;
use crate::resolver::NpmModuleLoader;
use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle;
@@ -146,13 +148,27 @@ impl ModuleLoader for EmbeddedModuleLoader {
type_error(format!("Referrer uses invalid specifier: {}", err))
})?
};
+ let referrer_kind = if self
+ .shared
+ .cjs_tracker
+ .is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer))?
+ {
+ NodeModuleKind::Cjs
+ } else {
+ NodeModuleKind::Esm
+ };
if self.shared.node_resolver.in_npm_package(&referrer) {
return Ok(
self
.shared
.node_resolver
- .resolve(raw_specifier, &referrer, NodeResolutionMode::Execution)?
+ .resolve(
+ raw_specifier,
+ &referrer,
+ referrer_kind,
+ NodeResolutionMode::Execution,
+ )?
.into_url(),
);
}
@@ -178,6 +194,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
pkg_json.dir_path(),
sub_path.as_deref(),
Some(&referrer),
+ referrer_kind,
NodeResolutionMode::Execution,
)?,
),
@@ -192,6 +209,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
req,
sub_path.as_deref(),
&referrer,
+ referrer_kind,
NodeResolutionMode::Execution,
)
}
@@ -211,6 +229,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
pkg_folder,
sub_path.as_deref(),
Some(&referrer),
+ referrer_kind,
NodeResolutionMode::Execution,
)?,
)
@@ -224,6 +243,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
return self.shared.node_resolver.resolve_req_reference(
&reference,
&referrer,
+ referrer_kind,
NodeResolutionMode::Execution,
);
}
@@ -250,6 +270,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
let maybe_res = self.shared.node_resolver.resolve_if_for_npm_pkg(
raw_specifier,
&referrer,
+ referrer_kind,
NodeResolutionMode::Execution,
)?;
if let Some(res) = maybe_res {
@@ -429,6 +450,14 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
) -> Result<String, AnyError> {
Ok(self.shared.fs.read_text_file_lossy_sync(path, None)?)
}
+
+ fn is_maybe_cjs(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Result<bool, ClosestPkgJsonError> {
+ let media_type = MediaType::from_specifier(specifier);
+ self.shared.cjs_tracker.is_maybe_cjs(specifier, media_type)
+ }
}
struct StandaloneModuleLoaderFactory {
@@ -628,14 +657,14 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
let cjs_tracker = Arc::new(CjsTracker::new(
in_npm_pkg_checker.clone(),
pkg_json_resolver.clone(),
- CjsTrackerOptions {
- unstable_detect_cjs: metadata.unstable_config.detect_cjs,
+ IsCjsResolverOptions {
+ detect_cjs: !metadata.workspace_resolver.package_jsons.is_empty(),
+ is_node_main: false,
},
));
let cache_db = Caches::new(deno_dir_provider.clone());
let node_analysis_cache = NodeAnalysisCache::new(cache_db.node_analysis_db());
let cli_node_resolver = Arc::new(CliNodeResolver::new(
- cjs_tracker.clone(),
fs.clone(),
in_npm_pkg_checker.clone(),
node_resolver.clone(),
@@ -646,7 +675,6 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
cjs_tracker.clone(),
fs.clone(),
None,
- false,
);
let node_code_translator = Arc::new(NodeCodeTranslator::new(
cjs_esm_code_analyzer,
diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs
index f59333247..2a554c133 100644
--- a/cli/tools/coverage/mod.rs
+++ b/cli/tools/coverage/mod.rs
@@ -480,7 +480,7 @@ fn filter_coverages(
.filter(|e| {
let is_internal = e.url.starts_with("ext:")
|| e.url.ends_with("__anonymous__")
- || e.url.ends_with("$deno$test.js")
+ || e.url.ends_with("$deno$test.mjs")
|| e.url.ends_with(".snap")
|| is_supported_test_path(Path::new(e.url.as_str()))
|| doc_test_re.is_match(e.url.as_str())
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs
index ed86e86c7..1655f0a32 100644
--- a/cli/tools/installer.rs
+++ b/cli/tools/installer.rs
@@ -1396,6 +1396,7 @@ mod tests {
.env_clear()
// use the deno binary in the target directory
.env("PATH", test_util::target_dir())
+ .env("RUST_BACKTRACE", "1")
.spawn()
.unwrap()
.wait()
diff --git a/cli/tools/jupyter/mod.rs b/cli/tools/jupyter/mod.rs
index 0ffd0da1e..732f95c49 100644
--- a/cli/tools/jupyter/mod.rs
+++ b/cli/tools/jupyter/mod.rs
@@ -61,7 +61,7 @@ pub async fn kernel(
let factory = CliFactory::from_flags(flags);
let cli_options = factory.cli_options()?;
let main_module =
- resolve_url_or_path("./$deno$jupyter.ts", cli_options.initial_cwd())
+ resolve_url_or_path("./$deno$jupyter.mts", cli_options.initial_cwd())
.unwrap();
// TODO(bartlomieju): should we run with all permissions?
let permissions =
diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs
index e096b486e..d8edf2404 100644
--- a/cli/tools/lint/mod.rs
+++ b/cli/tools/lint/mod.rs
@@ -63,7 +63,7 @@ pub use rules::LintRuleProvider;
const JSON_SCHEMA_VERSION: u8 = 1;
-static STDIN_FILE_NAME: &str = "$deno$stdin.ts";
+static STDIN_FILE_NAME: &str = "$deno$stdin.mts";
pub async fn lint(
flags: Arc<Flags>,
diff --git a/cli/tools/lint/rules/no_sloppy_imports.rs b/cli/tools/lint/rules/no_sloppy_imports.rs
index 2f6087588..94bf9a7c6 100644
--- a/cli/tools/lint/rules/no_sloppy_imports.rs
+++ b/cli/tools/lint/rules/no_sloppy_imports.rs
@@ -87,6 +87,7 @@ impl LintRule for NoSloppyImportsRule {
captures: Default::default(),
};
+ // fill this and capture the sloppy imports in the resolver
deno_graph::parse_module_from_ast(deno_graph::ParseModuleFromAstOptions {
graph_kind: deno_graph::GraphKind::All,
specifier: context.specifier().clone(),
diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs
index 23b0f11ac..8e05c4abb 100644
--- a/cli/tools/repl/session.rs
+++ b/cli/tools/repl/session.rs
@@ -7,7 +7,7 @@ use crate::cdp;
use crate::colors;
use crate::lsp::ReplLanguageServer;
use crate::npm::CliNpmResolver;
-use crate::resolver::CliGraphResolver;
+use crate::resolver::CliResolver;
use crate::tools::test::report_tests;
use crate::tools::test::reporters::PrettyTestReporter;
use crate::tools::test::reporters::TestReporter;
@@ -44,12 +44,12 @@ use deno_core::url::Url;
use deno_core::LocalInspectorSession;
use deno_core::PollEventLoopOptions;
use deno_graph::source::ResolutionMode;
-use deno_graph::source::Resolver;
use deno_graph::Position;
use deno_graph::PositionRange;
use deno_graph::SpecifierWithRange;
use deno_runtime::worker::MainWorker;
use deno_semver::npm::NpmPackageReqReference;
+use node_resolver::NodeModuleKind;
use once_cell::sync::Lazy;
use regex::Match;
use regex::Regex;
@@ -180,7 +180,7 @@ struct ReplJsxState {
pub struct ReplSession {
npm_resolver: Arc<dyn CliNpmResolver>,
- resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
pub worker: MainWorker,
session: LocalInspectorSession,
pub context_id: u64,
@@ -199,7 +199,7 @@ impl ReplSession {
pub async fn initialize(
cli_options: &CliOptions,
npm_resolver: Arc<dyn CliNpmResolver>,
- resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
mut worker: MainWorker,
main_module: ModuleSpecifier,
test_event_receiver: TestEventReceiver,
@@ -245,7 +245,7 @@ impl ReplSession {
assert_ne!(context_id, 0);
let referrer =
- deno_core::resolve_path("./$deno$repl.ts", cli_options.initial_cwd())
+ deno_core::resolve_path("./$deno$repl.mts", cli_options.initial_cwd())
.unwrap();
let cwd_url =
@@ -712,7 +712,12 @@ impl ReplSession {
.flat_map(|i| {
self
.resolver
- .resolve(i, &referrer_range, ResolutionMode::Execution)
+ .resolve(
+ i,
+ &referrer_range,
+ NodeModuleKind::Esm,
+ ResolutionMode::Execution,
+ )
.ok()
.or_else(|| ModuleSpecifier::parse(i).ok())
})
diff --git a/cli/tools/run/hmr.rs b/cli/tools/run/hmr.rs
index 6cebedd01..373c207d6 100644
--- a/cli/tools/run/hmr.rs
+++ b/cli/tools/run/hmr.rs
@@ -4,8 +4,6 @@ use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
-use deno_ast::MediaType;
-use deno_ast::ModuleKind;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures::StreamExt;
@@ -18,7 +16,6 @@ use tokio::select;
use crate::cdp;
use crate::emit::Emitter;
-use crate::resolver::CjsTracker;
use crate::util::file_watcher::WatcherCommunicator;
use crate::util::file_watcher::WatcherRestartMode;
@@ -63,7 +60,6 @@ pub struct HmrRunner {
session: LocalInspectorSession,
watcher_communicator: Arc<WatcherCommunicator>,
script_ids: HashMap<String, String>,
- cjs_tracker: Arc<CjsTracker>,
emitter: Arc<Emitter>,
}
@@ -146,7 +142,6 @@ impl crate::worker::HmrRunner for HmrRunner {
let source_code = self.emitter.load_and_emit_for_hmr(
&module_url,
- ModuleKind::from_is_cjs(self.cjs_tracker.is_maybe_cjs(&module_url, MediaType::from_specifier(&module_url))?),
).await?;
let mut tries = 1;
@@ -179,14 +174,12 @@ impl crate::worker::HmrRunner for HmrRunner {
impl HmrRunner {
pub fn new(
- cjs_tracker: Arc<CjsTracker>,
emitter: Arc<Emitter>,
session: LocalInspectorSession,
watcher_communicator: Arc<WatcherCommunicator>,
) -> Self {
Self {
session,
- cjs_tracker,
emitter,
watcher_communicator,
script_ids: HashMap::new(),
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js
index 52c9134da..68d099253 100644
--- a/cli/tsc/99_main_compiler.js
+++ b/cli/tsc/99_main_compiler.js
@@ -121,8 +121,8 @@ delete Object.prototype.__proto__;
/** @type {Map<string, ts.SourceFile>} */
const sourceFileCache = new Map();
- /** @type {Map<string, string>} */
- const sourceTextCache = new Map();
+ /** @type {Map<string, ts.IScriptSnapshot & { isCjs?: boolean; }>} */
+ const scriptSnapshotCache = new Map();
/** @type {Map<string, number>} */
const sourceRefCounts = new Map();
@@ -133,9 +133,6 @@ delete Object.prototype.__proto__;
/** @type {Map<string, boolean>} */
const isNodeSourceFileCache = new Map();
- /** @type {Map<string, boolean>} */
- const isCjsCache = new Map();
-
// Maps asset specifiers to the first scope that the asset was loaded into.
/** @type {Map<string, string | null>} */
const assetScopes = new Map();
@@ -210,12 +207,13 @@ delete Object.prototype.__proto__;
const mapKey = path + key;
let sourceFile = documentRegistrySourceFileCache.get(mapKey);
if (!sourceFile || sourceFile.version !== version) {
+ const isCjs = /** @type {any} */ (scriptSnapshot).isCjs;
sourceFile = ts.createLanguageServiceSourceFile(
fileName,
scriptSnapshot,
{
...getCreateSourceFileOptions(sourceFileOptions),
- impliedNodeFormat: (isCjsCache.get(fileName) ?? false)
+ impliedNodeFormat: isCjs
? ts.ModuleKind.CommonJS
: ts.ModuleKind.ESNext,
// in the lsp we want to be able to show documentation
@@ -320,7 +318,7 @@ delete Object.prototype.__proto__;
if (lastRequestMethod != "cleanupSemanticCache") {
const mapKey = path + key;
documentRegistrySourceFileCache.delete(mapKey);
- sourceTextCache.delete(path);
+ scriptSnapshotCache.delete(path);
ops.op_release(path);
}
} else {
@@ -624,8 +622,6 @@ delete Object.prototype.__proto__;
`"data" is unexpectedly null for "${specifier}".`,
);
- isCjsCache.set(specifier, isCjs);
-
sourceFile = ts.createSourceFile(
specifier,
data,
@@ -699,7 +695,7 @@ delete Object.prototype.__proto__;
/** @type {[string, ts.Extension] | undefined} */
const resolved = ops.op_resolve(
containingFilePath,
- isCjsCache.get(containingFilePath) ?? false,
+ containingFileMode === ts.ModuleKind.CommonJS,
[fileReference.fileName],
)?.[0];
if (resolved) {
@@ -723,7 +719,14 @@ delete Object.prototype.__proto__;
}
});
},
- resolveModuleNames(specifiers, base) {
+ resolveModuleNames(
+ specifiers,
+ base,
+ _reusedNames,
+ _redirectedReference,
+ _options,
+ containingSourceFile,
+ ) {
if (logDebug) {
debug(`host.resolveModuleNames()`);
debug(` base: ${base}`);
@@ -732,7 +735,7 @@ delete Object.prototype.__proto__;
/** @type {Array<[string, ts.Extension] | undefined>} */
const resolved = ops.op_resolve(
base,
- isCjsCache.get(base) ?? false,
+ containingSourceFile?.impliedNodeFormat === ts.ModuleKind.CommonJS,
specifiers,
);
if (resolved) {
@@ -814,19 +817,19 @@ delete Object.prototype.__proto__;
return ts.ScriptSnapshot.fromString(sourceFile.text);
}
}
- let sourceText = sourceTextCache.get(specifier);
- if (sourceText == undefined) {
+ let scriptSnapshot = scriptSnapshotCache.get(specifier);
+ if (scriptSnapshot == undefined) {
/** @type {{ data: string, version: string, isCjs: boolean }} */
const fileInfo = ops.op_load(specifier);
if (!fileInfo) {
return undefined;
}
- isCjsCache.set(specifier, fileInfo.isCjs);
- sourceTextCache.set(specifier, fileInfo.data);
+ scriptSnapshot = ts.ScriptSnapshot.fromString(fileInfo.data);
+ scriptSnapshot.isCjs = fileInfo.isCjs;
+ scriptSnapshotCache.set(specifier, scriptSnapshot);
scriptVersionCache.set(specifier, fileInfo.version);
- sourceText = fileInfo.data;
}
- return ts.ScriptSnapshot.fromString(sourceText);
+ return scriptSnapshot;
},
};
@@ -1238,7 +1241,7 @@ delete Object.prototype.__proto__;
closed = true;
}
scriptVersionCache.delete(script);
- sourceTextCache.delete(script);
+ scriptSnapshotCache.delete(script);
}
if (newConfigsByScope || opened || closed) {
diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs
index dc7fc38f7..a56906162 100644
--- a/cli/tsc/mod.rs
+++ b/cli/tsc/mod.rs
@@ -343,31 +343,36 @@ impl TypeCheckingCjsTracker {
media_type: MediaType,
code: &Arc<str>,
) -> bool {
- if let Some(module_kind) =
- self.cjs_tracker.get_known_kind(specifier, media_type)
- {
- module_kind.is_cjs()
- } else {
- let maybe_is_script = self
- .module_info_cache
- .as_module_analyzer()
- .analyze_sync(specifier, media_type, code)
- .ok()
- .map(|info| info.is_script);
- maybe_is_script
- .and_then(|is_script| {
- self
- .cjs_tracker
- .is_cjs_with_known_is_script(specifier, media_type, is_script)
- .ok()
- })
- .unwrap_or_else(|| {
- self
- .cjs_tracker
- .is_maybe_cjs(specifier, media_type)
- .unwrap_or(false)
- })
- }
+ let maybe_is_script = self
+ .module_info_cache
+ .as_module_analyzer()
+ .analyze_sync(specifier, media_type, code)
+ .ok()
+ .map(|info| info.is_script);
+ maybe_is_script
+ .and_then(|is_script| {
+ self
+ .cjs_tracker
+ .is_cjs_with_known_is_script(specifier, media_type, is_script)
+ .ok()
+ })
+ .unwrap_or_else(|| {
+ self
+ .cjs_tracker
+ .is_maybe_cjs(specifier, media_type)
+ .unwrap_or(false)
+ })
+ }
+
+ pub fn is_cjs_with_known_is_script(
+ &self,
+ specifier: &ModuleSpecifier,
+ media_type: MediaType,
+ is_script: bool,
+ ) -> Result<bool, node_resolver::errors::ClosestPkgJsonError> {
+ self
+ .cjs_tracker
+ .is_cjs_with_known_is_script(specifier, media_type, is_script)
}
}
@@ -627,8 +632,12 @@ fn op_load_inner(
match module {
Module::Js(module) => {
media_type = module.media_type;
- if matches!(media_type, MediaType::Cjs | MediaType::Cts) {
- is_cjs = true;
+ if let Some(npm_state) = &state.maybe_npm {
+ is_cjs = npm_state.cjs_tracker.is_cjs_with_known_is_script(
+ specifier,
+ module.media_type,
+ module.is_script,
+ )?;
}
let source = module
.fast_check_module()
@@ -737,6 +746,7 @@ fn op_resolve_inner(
"Error converting a string module specifier for \"op_resolve\".",
)?
};
+ let referrer_module = state.graph.get(&referrer);
for specifier in args.specifiers {
if specifier.starts_with("node:") {
resolved.push((
@@ -752,16 +762,19 @@ fn op_resolve_inner(
continue;
}
- let graph = &state.graph;
- let resolved_dep = graph
- .get(&referrer)
+ let resolved_dep = referrer_module
.and_then(|m| m.js())
.and_then(|m| m.dependencies_prefer_fast_check().get(&specifier))
.and_then(|d| d.maybe_type.ok().or_else(|| d.maybe_code.ok()));
let maybe_result = match resolved_dep {
Some(ResolutionResolved { specifier, .. }) => {
- resolve_graph_specifier_types(specifier, &referrer, state)?
+ resolve_graph_specifier_types(
+ specifier,
+ &referrer,
+ referrer_kind,
+ state,
+ )?
}
_ => {
match resolve_non_graph_specifier_types(
@@ -834,6 +847,7 @@ fn op_resolve_inner(
fn resolve_graph_specifier_types(
specifier: &ModuleSpecifier,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
state: &State,
) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> {
let graph = &state.graph;
@@ -886,6 +900,7 @@ fn resolve_graph_specifier_types(
&package_folder,
module.nv_reference.sub_path(),
Some(referrer),
+ referrer_kind,
NodeResolutionMode::Types,
);
let maybe_url = match res_result {
@@ -965,6 +980,7 @@ fn resolve_non_graph_specifier_types(
&package_folder,
npm_req_ref.sub_path(),
Some(referrer),
+ referrer_kind,
NodeResolutionMode::Types,
);
let maybe_url = match res_result {
diff --git a/cli/worker.rs b/cli/worker.rs
index 402644a42..83e36b36c 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -44,6 +44,7 @@ use deno_runtime::WorkerExecutionMode;
use deno_runtime::WorkerLogLevel;
use deno_semver::npm::NpmPackageReqReference;
use deno_terminal::colors;
+use node_resolver::NodeModuleKind;
use node_resolver::NodeResolutionMode;
use tokio::select;
@@ -680,6 +681,7 @@ impl CliMainWorkerFactory {
package_folder,
sub_path,
/* referrer */ None,
+ NodeModuleKind::Esm,
NodeResolutionMode::Execution,
)?;
if specifier
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 6d320b92c..702c919f4 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -14,6 +14,7 @@ use deno_core::url::Url;
#[allow(unused_imports)]
use deno_core::v8;
use deno_core::v8::ExternalReference;
+use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::NpmResolverRc;
use once_cell::sync::Lazy;
@@ -157,6 +158,10 @@ pub trait NodeRequireLoader {
) -> Result<Cow<'a, Path>, AnyError>;
fn load_text_file_lossy(&self, path: &Path) -> Result<String, AnyError>;
+
+ /// Get if the module kind is maybe CJS and loading should determine
+ /// if its CJS or ESM.
+ fn is_maybe_cjs(&self, specifier: &Url) -> Result<bool, ClosestPkgJsonError>;
}
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
@@ -385,6 +390,7 @@ deno_core::extension!(deno_node,
ops::require::op_require_proxy_path,
ops::require::op_require_is_deno_dir_package,
ops::require::op_require_resolve_deno_dir,
+ 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>,
@@ -398,7 +404,6 @@ deno_core::extension!(deno_node,
ops::require::op_require_read_file<P>,
ops::require::op_require_as_file_path,
ops::require::op_require_resolve_exports<P>,
- ops::require::op_require_read_closest_package_json<P>,
ops::require::op_require_read_package_scope<P>,
ops::require::op_require_package_imports_resolve<P>,
ops::require::op_require_break_on_next_statement,
diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs
index 30db8b629..b7fa8feb2 100644
--- a/ext/node/ops/require.rs
+++ b/ext/node/ops/require.rs
@@ -1,16 +1,18 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::url::Url;
use deno_core::v8;
use deno_core::JsRuntimeInspector;
-use deno_core::ModuleSpecifier;
use deno_core::OpState;
use deno_fs::FileSystemRc;
+use deno_package_json::NodeModuleKind;
use deno_package_json::PackageJsonRc;
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::NodeModuleKind;
+use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::NodeResolutionMode;
use node_resolver::REQUIRE_CONDITIONS;
use std::borrow::Cow;
@@ -217,17 +219,17 @@ pub fn op_require_resolve_deno_dir(
state: &mut OpState,
#[string] request: String,
#[string] parent_filename: String,
-) -> Option<String> {
+) -> Result<Option<String>, AnyError> {
let resolver = state.borrow::<NpmResolverRc>();
- resolver
- .resolve_package_folder_from_package(
- &request,
- &ModuleSpecifier::from_file_path(&parent_filename).unwrap_or_else(|_| {
- panic!("Url::from_file_path: [{:?}]", parent_filename)
- }),
- )
- .ok()
- .map(|p| p.to_string_lossy().into_owned())
+ Ok(
+ resolver
+ .resolve_package_folder_from_package(
+ &request,
+ &url_from_file_path(&PathBuf::from(parent_filename))?,
+ )
+ .ok()
+ .map(|p| p.to_string_lossy().into_owned()),
+ )
}
#[op2(fast)]
@@ -564,19 +566,17 @@ where
}))
}
-#[op2]
-#[serde]
-pub fn op_require_read_closest_package_json<P>(
+#[op2(fast)]
+pub fn op_require_is_maybe_cjs(
state: &mut OpState,
#[string] filename: String,
-) -> Result<Option<PackageJsonRc>, node_resolver::errors::ClosestPkgJsonError>
-where
- P: NodePermissions + 'static,
-{
+) -> Result<bool, ClosestPkgJsonError> {
let filename = PathBuf::from(filename);
- // permissions: allow reading the closest package.json files
- let pkg_json_resolver = state.borrow::<PackageJsonResolverRc>();
- pkg_json_resolver.get_closest_package_json_from_path(&filename)
+ let Ok(url) = url_from_file_path(&filename) else {
+ return Ok(false);
+ };
+ let loader = state.borrow::<NodeRequireLoaderRc>();
+ loader.is_maybe_cjs(&url)
}
#[op2]
diff --git a/ext/node/polyfills/01_require.js b/ext/node/polyfills/01_require.js
index 0d267ca44..083d4e49b 100644
--- a/ext/node/polyfills/01_require.js
+++ b/ext/node/polyfills/01_require.js
@@ -11,6 +11,7 @@ import {
op_require_can_parse_as_esm,
op_require_init_paths,
op_require_is_deno_dir_package,
+ op_require_is_maybe_cjs,
op_require_is_request_relative,
op_require_node_module_paths,
op_require_package_imports_resolve,
@@ -19,7 +20,6 @@ import {
op_require_path_is_absolute,
op_require_path_resolve,
op_require_proxy_path,
- op_require_read_closest_package_json,
op_require_read_file,
op_require_read_package_scope,
op_require_real_path,
@@ -1060,36 +1060,13 @@ Module.prototype._compile = function (content, filename, format) {
return result;
};
-Module._extensions[".js"] = function (module, filename) {
- const content = op_require_read_file(filename);
-
- let format;
- if (StringPrototypeEndsWith(filename, ".js")) {
- const pkg = op_require_read_closest_package_json(filename);
- if (pkg?.type === "module") {
- format = "module";
- } else if (pkg?.type === "commonjs") {
- format = "commonjs";
- }
- }
-
- module._compile(content, filename, format);
-};
-
-Module._extensions[".ts"] =
+Module._extensions[".js"] =
+ Module._extensions[".ts"] =
Module._extensions[".jsx"] =
Module._extensions[".tsx"] =
function (module, filename) {
const content = op_require_read_file(filename);
-
- let format;
- const pkg = op_require_read_closest_package_json(filename);
- if (pkg?.type === "module") {
- format = "module";
- } else if (pkg?.type === "commonjs") {
- format = "commonjs";
- }
-
+ const format = op_require_is_maybe_cjs(filename) ? undefined : "module";
module._compile(content, filename, format);
};
diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts
index bf626e410..647376d5c 100644
--- a/ext/node/polyfills/process.ts
+++ b/ext/node/polyfills/process.ts
@@ -919,7 +919,7 @@ Object.defineProperty(argv, "1", {
if (Deno.mainModule?.startsWith("file:")) {
return pathFromURL(new URL(Deno.mainModule));
} else {
- return join(Deno.cwd(), "$deno$node.js");
+ return join(Deno.cwd(), "$deno$node.mjs");
}
},
});
diff --git a/resolvers/node/package_json.rs b/resolvers/node/package_json.rs
index 6967779e5..ae016ebe3 100644
--- a/resolvers/node/package_json.rs
+++ b/resolvers/node/package_json.rs
@@ -15,8 +15,8 @@ use crate::errors::CanonicalizingPkgJsonDirError;
use crate::errors::ClosestPkgJsonError;
use crate::errors::PackageJsonLoadError;
-// todo(dsherret): this isn't exactly correct and we should change it to instead
-// be created per worker and passed down as a ctor arg to the pkg json resolver
+// it would be nice if this was passed down as a ctor arg to the package.json resolver,
+// but it's a little bit complicated to do that, so we just maintain a thread local cache
thread_local! {
static CACHE: RefCell<HashMap<PathBuf, PackageJsonRc>> = RefCell::new(HashMap::new());
}
diff --git a/resolvers/node/resolution.rs b/resolvers/node/resolution.rs
index d44539e97..fcff29242 100644
--- a/resolvers/node/resolution.rs
+++ b/resolvers/node/resolution.rs
@@ -50,6 +50,15 @@ pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"];
pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"];
static TYPES_ONLY_CONDITIONS: &[&str] = &["types"];
+fn conditions_from_module_kind(
+ kind: NodeModuleKind,
+) -> &'static [&'static str] {
+ match kind {
+ NodeModuleKind::Esm => DEFAULT_CONDITIONS,
+ NodeModuleKind::Cjs => REQUIRE_CONDITIONS,
+ }
+}
+
pub type NodeModuleKind = deno_package_json::NodeModuleKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -166,8 +175,7 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
specifier,
referrer,
referrer_kind,
- // even though the referrer may be CJS, if we're here that means we're doing ESM resolution
- DEFAULT_CONDITIONS,
+ conditions_from_module_kind(referrer_kind),
mode,
)?;
@@ -299,9 +307,9 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
package_dir: &Path,
package_subpath: Option<&str>,
maybe_referrer: Option<&Url>,
+ referrer_kind: NodeModuleKind,
mode: NodeResolutionMode,
) -> Result<Url, PackageSubpathResolveError> {
- let node_module_kind = NodeModuleKind::Esm;
let package_subpath = package_subpath
.map(|s| format!("./{s}"))
.unwrap_or_else(|| ".".to_string());
@@ -309,8 +317,8 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
package_dir,
&package_subpath,
maybe_referrer,
- node_module_kind,
- DEFAULT_CONDITIONS,
+ referrer_kind,
+ conditions_from_module_kind(referrer_kind),
mode,
)?;
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
@@ -441,10 +449,7 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
/* sub path */ ".",
maybe_referrer,
referrer_kind,
- match referrer_kind {
- NodeModuleKind::Esm => DEFAULT_CONDITIONS,
- NodeModuleKind::Cjs => REQUIRE_CONDITIONS,
- },
+ conditions_from_module_kind(referrer_kind),
NodeResolutionMode::Types,
);
if let Ok(resolution) = resolution_result {
diff --git a/runtime/fmt_errors.rs b/runtime/fmt_errors.rs
index 4cd8a0634..28cd70296 100644
--- a/runtime/fmt_errors.rs
+++ b/runtime/fmt_errors.rs
@@ -310,14 +310,13 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec<FixSuggestion> {
{
return vec![
FixSuggestion::info_multiline(&[
- cstr!("Deno supports CommonJS modules in <u>.cjs</> files, or when there's a <u>package.json</>"),
- cstr!("with <i>\"type\": \"commonjs\"</> option and <i>--unstable-detect-cjs</> flag is used.")
+ cstr!("Deno supports CommonJS modules in <u>.cjs</> files, or when the closest"),
+ cstr!("<u>package.json</> has a <i>\"type\": \"commonjs\"</> option.")
]),
FixSuggestion::hint_multiline(&[
"Rewrite this module to ESM,",
cstr!("or change the file extension to <u>.cjs</u>,"),
- cstr!("or add <u>package.json</> next to the file with <i>\"type\": \"commonjs\"</> option"),
- cstr!("and pass <i>--unstable-detect-cjs</> flag."),
+ cstr!("or add <u>package.json</> next to the file with <i>\"type\": \"commonjs\"</> option."),
]),
FixSuggestion::docs("https://docs.deno.com/go/commonjs"),
];
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index d81c82c50..e27229153 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -393,6 +393,13 @@ pub struct WebWorker {
maybe_worker_metadata: Option<WorkerMetadata>,
}
+impl Drop for WebWorker {
+ fn drop(&mut self) {
+ // clean up the package.json thread local cache
+ node_resolver::PackageJsonThreadLocalCache::clear();
+ }
+}
+
impl WebWorker {
pub fn bootstrap_from_options(
services: WebWorkerServiceOptions,
diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs
index af5f9de23..dcef69608 100644
--- a/tests/integration/lsp_tests.rs
+++ b/tests/integration/lsp_tests.rs
@@ -16140,6 +16140,55 @@ fn lsp_cjs_import_dual() {
}
#[test]
+fn lsp_type_commonjs() {
+ let context = TestContextBuilder::new()
+ .use_http_server()
+ .use_temp_cwd()
+ .add_npm_env_vars()
+ .build();
+ let temp_dir = context.temp_dir();
+ temp_dir.write("deno.json", r#"{}"#);
+ temp_dir.write(
+ "package.json",
+ r#"{
+ "type": "commonjs",
+ "dependencies": {
+ "@denotest/dual-cjs-esm": "1"
+ }
+}"#,
+ );
+ context.run_npm("install");
+
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
+ let main_url = temp_dir.path().join("main.ts").url_file();
+ let diagnostics = client.did_open(
+ json!({
+ "textDocument": {
+ "uri": main_url,
+ "languageId": "typescript",
+ "version": 1,
+ // getKind() should resolve as "cjs" and cause a type checker error
+ "text": "import mod = require('@denotest/dual-cjs-esm');\nconst kind: 'other' = mod.getKind(); console.log(kind);",
+ }
+ }),
+ );
+ assert_eq!(
+ json!(diagnostics.all()),
+ json!([{
+ "range": {
+ "start": { "line": 1, "character": 6, },
+ "end": { "line": 1, "character": 10, },
+ },
+ "severity": 1,
+ "code": 2322,
+ "source": "deno-ts",
+ "message": "Type '\"cjs\"' is not assignable to type '\"other\"'.",
+ }])
+ );
+}
+
+#[test]
fn lsp_ts_code_fix_any_param() {
let context = TestContextBuilder::new().use_temp_cwd().build();
let temp_dir = context.temp_dir();
diff --git a/tests/node_compat/package.json b/tests/node_compat/package.json
new file mode 100644
index 000000000..5bbefffba
--- /dev/null
+++ b/tests/node_compat/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "commonjs"
+}
diff --git a/tests/node_compat/test/common/package.json b/tests/node_compat/test/common/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/common/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/node_compat/test/fixtures/package.json b/tests/node_compat/test/fixtures/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/fixtures/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/node_compat/test/internet/package.json b/tests/node_compat/test/internet/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/internet/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/node_compat/test/parallel/package.json b/tests/node_compat/test/parallel/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/parallel/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/node_compat/test/pseudo-tty/package.json b/tests/node_compat/test/pseudo-tty/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/pseudo-tty/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/node_compat/test/pummel/package.json b/tests/node_compat/test/pummel/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/pummel/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/node_compat/test/sequential/package.json b/tests/node_compat/test/sequential/package.json
deleted file mode 100644
index 0967ef424..000000000
--- a/tests/node_compat/test/sequential/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/install.js b/tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/install.js
new file mode 100644
index 000000000..61aadeb83
--- /dev/null
+++ b/tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/install.js
@@ -0,0 +1,12 @@
+const tempDir = Deno.makeTempDirSync();
+try {
+ // should work requiring these because this was launched via a node binary entrypoint
+ Deno.writeTextFileSync(`${tempDir}/index.js`, "module.exports = require('./other');");
+ Deno.writeTextFileSync(`${tempDir}/other.js`, "module.exports = (a, b) => a + b;");
+ const add = require(`${tempDir}/index.js`);
+ if (add(1, 2) !== 3) {
+ throw new Error("FAILED");
+ }
+} finally {
+ Deno.removeSync(tempDir, { recursive: true });
+}
diff --git a/tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/package.json b/tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/package.json
new file mode 100644
index 000000000..c3cf8dc4c
--- /dev/null
+++ b/tests/registry/npm/@denotest/install-launch-cjs-temp-dir/1.0.0/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "@denotest/install-launch-cjs-temp-dir",
+ "version": "1.0.0",
+ "scripts": {
+ "install": "node install.js"
+ }
+} \ No newline at end of file
diff --git a/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/check.js b/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/check.js
new file mode 100644
index 000000000..7d55c2481
--- /dev/null
+++ b/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/check.js
@@ -0,0 +1 @@
+require("./output");
diff --git a/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/index.js b/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/index.js
new file mode 100644
index 000000000..7d55c2481
--- /dev/null
+++ b/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/index.js
@@ -0,0 +1 @@
+require("./output");
diff --git a/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/output.js b/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/output.js
new file mode 100644
index 000000000..69668cd62
--- /dev/null
+++ b/tests/registry/npm/@denotest/install-no-ext/1.0.0/install/output.js
@@ -0,0 +1 @@
+console.log("SUCCESS");
diff --git a/tests/registry/npm/@denotest/install-no-ext/1.0.0/package.json b/tests/registry/npm/@denotest/install-no-ext/1.0.0/package.json
new file mode 100644
index 000000000..b9abed1f6
--- /dev/null
+++ b/tests/registry/npm/@denotest/install-no-ext/1.0.0/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "@denotest/install-no-ext",
+ "version": "1.0.0",
+ "scripts": {
+ "install": "node install/check && node install"
+ }
+} \ No newline at end of file
diff --git a/tests/specs/compile/detect_cjs/deno.json b/tests/specs/compile/detect_cjs/deno.json
deleted file mode 100644
index 35f64c86f..000000000
--- a/tests/specs/compile/detect_cjs/deno.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "unstable": [
- "detect-cjs"
- ]
-}
diff --git a/tests/specs/compile/detect_cjs/__test__.jsonc b/tests/specs/compile/package_json_type/__test__.jsonc
index 0abf121f0..0abf121f0 100644
--- a/tests/specs/compile/detect_cjs/__test__.jsonc
+++ b/tests/specs/compile/package_json_type/__test__.jsonc
diff --git a/tests/specs/compile/detect_cjs/add.js b/tests/specs/compile/package_json_type/add.js
index 94b0263f0..94b0263f0 100644
--- a/tests/specs/compile/detect_cjs/add.js
+++ b/tests/specs/compile/package_json_type/add.js
diff --git a/tests/specs/compile/detect_cjs/compile.out b/tests/specs/compile/package_json_type/compile.out
index 913e363c3..913e363c3 100644
--- a/tests/specs/compile/detect_cjs/compile.out
+++ b/tests/specs/compile/package_json_type/compile.out
diff --git a/tests/specs/compile/detect_cjs/main.js b/tests/specs/compile/package_json_type/main.js
index 8c55f673b..8c55f673b 100644
--- a/tests/specs/compile/detect_cjs/main.js
+++ b/tests/specs/compile/package_json_type/main.js
diff --git a/tests/specs/compile/detect_cjs/output.out b/tests/specs/compile/package_json_type/output.out
index 00750edc0..00750edc0 100644
--- a/tests/specs/compile/detect_cjs/output.out
+++ b/tests/specs/compile/package_json_type/output.out
diff --git a/tests/specs/compile/detect_cjs/package.json b/tests/specs/compile/package_json_type/package.json
index 6e65b32ed..6e65b32ed 100644
--- a/tests/specs/compile/detect_cjs/package.json
+++ b/tests/specs/compile/package_json_type/package.json
diff --git a/tests/specs/compile/detect_cjs/subtract.ts b/tests/specs/compile/package_json_type/subtract.ts
index e4f6760b7..e4f6760b7 100644
--- a/tests/specs/compile/detect_cjs/subtract.ts
+++ b/tests/specs/compile/package_json_type/subtract.ts
diff --git a/tests/specs/eval/pkg_json_type_cjs/__test__.jsonc b/tests/specs/eval/pkg_json_type_cjs/__test__.jsonc
new file mode 100644
index 000000000..cd3804d77
--- /dev/null
+++ b/tests/specs/eval/pkg_json_type_cjs/__test__.jsonc
@@ -0,0 +1,4 @@
+{
+ "args": "eval console.log(1)",
+ "output": "1\n"
+}
diff --git a/tests/specs/eval/pkg_json_type_cjs/package.json b/tests/specs/eval/pkg_json_type_cjs/package.json
new file mode 100644
index 000000000..5bbefffba
--- /dev/null
+++ b/tests/specs/eval/pkg_json_type_cjs/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "commonjs"
+}
diff --git a/tests/specs/install/scripts_install_launch_cjs_temp_dir/__test__.jsonc b/tests/specs/install/scripts_install_launch_cjs_temp_dir/__test__.jsonc
new file mode 100644
index 000000000..087d08eff
--- /dev/null
+++ b/tests/specs/install/scripts_install_launch_cjs_temp_dir/__test__.jsonc
@@ -0,0 +1,5 @@
+{
+ "tempDir": true,
+ "args": "install --allow-scripts",
+ "output": "output.out"
+}
diff --git a/tests/specs/install/scripts_install_launch_cjs_temp_dir/output.out b/tests/specs/install/scripts_install_launch_cjs_temp_dir/output.out
new file mode 100644
index 000000000..d5f06cc6e
--- /dev/null
+++ b/tests/specs/install/scripts_install_launch_cjs_temp_dir/output.out
@@ -0,0 +1,4 @@
+Download http://localhost:4260/@denotest%2finstall-launch-cjs-temp-dir
+Download http://localhost:4260/@denotest/install-launch-cjs-temp-dir/1.0.0.tgz
+Initialize @denotest/install-launch-cjs-temp-dir@1.0.0
+Initialize @denotest/install-launch-cjs-temp-dir@1.0.0: running 'install' script
diff --git a/tests/specs/install/scripts_install_launch_cjs_temp_dir/package.json b/tests/specs/install/scripts_install_launch_cjs_temp_dir/package.json
new file mode 100644
index 000000000..71672f9bc
--- /dev/null
+++ b/tests/specs/install/scripts_install_launch_cjs_temp_dir/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "@denotest/install-launch-cjs-temp-dir": "*"
+ }
+}
diff --git a/tests/specs/install/scripts_install_no_ext/__test__.jsonc b/tests/specs/install/scripts_install_no_ext/__test__.jsonc
new file mode 100644
index 000000000..087d08eff
--- /dev/null
+++ b/tests/specs/install/scripts_install_no_ext/__test__.jsonc
@@ -0,0 +1,5 @@
+{
+ "tempDir": true,
+ "args": "install --allow-scripts",
+ "output": "output.out"
+}
diff --git a/tests/specs/install/scripts_install_no_ext/output.out b/tests/specs/install/scripts_install_no_ext/output.out
new file mode 100644
index 000000000..074e97812
--- /dev/null
+++ b/tests/specs/install/scripts_install_no_ext/output.out
@@ -0,0 +1,4 @@
+Download http://localhost:4260/@denotest%2finstall-no-ext
+Download http://localhost:4260/@denotest/install-no-ext/1.0.0.tgz
+Initialize @denotest/install-no-ext@1.0.0
+Initialize @denotest/install-no-ext@1.0.0: running 'install' script
diff --git a/tests/specs/install/scripts_install_no_ext/package.json b/tests/specs/install/scripts_install_no_ext/package.json
new file mode 100644
index 000000000..7ac9ca6b2
--- /dev/null
+++ b/tests/specs/install/scripts_install_no_ext/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "@denotest/install-no-ext": "*"
+ }
+}
diff --git a/tests/specs/mod.rs b/tests/specs/mod.rs
index 34221dd9d..b4c8781d3 100644
--- a/tests/specs/mod.rs
+++ b/tests/specs/mod.rs
@@ -119,6 +119,9 @@ struct MultiStepMetaData {
/// steps.
#[serde(default)]
pub temp_dir: bool,
+ /// Whether the temporary directory should be symlinked to another path.
+ #[serde(default)]
+ pub symlinked_temp_dir: bool,
/// The base environment to use for the test.
#[serde(default)]
pub base: Option<String>,
@@ -142,6 +145,8 @@ struct SingleTestMetaData {
#[serde(default)]
pub temp_dir: bool,
#[serde(default)]
+ pub symlinked_temp_dir: bool,
+ #[serde(default)]
pub repeat: Option<usize>,
#[serde(flatten)]
pub step: StepMetaData,
@@ -155,6 +160,7 @@ impl SingleTestMetaData {
base: self.base,
cwd: None,
temp_dir: self.temp_dir,
+ symlinked_temp_dir: self.symlinked_temp_dir,
repeat: self.repeat,
envs: Default::default(),
steps: vec![self.step],
@@ -330,6 +336,20 @@ fn test_context_from_metadata(
builder = builder.cwd(cwd.to_string_lossy());
}
+ if metadata.symlinked_temp_dir {
+ // not actually deprecated, we just want to discourage its use
+ // because it's mostly used for testing purposes locally
+ #[allow(deprecated)]
+ {
+ builder = builder.use_symlinked_temp_dir();
+ }
+ if cfg!(not(debug_assertions)) {
+ // panic to prevent using this on the CI as CI already uses
+ // a symlinked temp directory for every test
+ panic!("Cannot use symlinkedTempDir in release mode");
+ }
+ }
+
match &metadata.base {
// todo(dsherret): add bases in the future as needed
Some(base) => panic!("Unknown test base: {}", base),
diff --git a/tests/specs/npm/dual_cjs_esm/__test__.jsonc b/tests/specs/npm/dual_cjs_esm/__test__.jsonc
deleted file mode 100644
index f2b0d694e..000000000
--- a/tests/specs/npm/dual_cjs_esm/__test__.jsonc
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "args": "run -A --quiet dual_cjs_esm/main.ts",
- "output": "dual_cjs_esm/main.out"
-}
diff --git a/tests/specs/npm/dual_cjs_esm/cjs_referrer/__test__.jsonc b/tests/specs/npm/dual_cjs_esm/cjs_referrer/__test__.jsonc
new file mode 100644
index 000000000..de2c1a0bc
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/cjs_referrer/__test__.jsonc
@@ -0,0 +1,14 @@
+{
+ "tempDir": true,
+ "tests": {
+ "check": {
+ "args": "check --node-modules-dir=auto main.cts",
+ "output": "check.out",
+ "exitCode": 1
+ },
+ "run": {
+ "args": "run --node-modules-dir=auto --allow-read main.cts",
+ "output": "main.out"
+ }
+ }
+}
diff --git a/tests/specs/npm/dual_cjs_esm/cjs_referrer/check.out b/tests/specs/npm/dual_cjs_esm/cjs_referrer/check.out
new file mode 100644
index 000000000..267d31fb7
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/cjs_referrer/check.out
@@ -0,0 +1,8 @@
+Download http://localhost:4260/@denotest%2fdual-cjs-esm
+Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
+Initialize @denotest/dual-cjs-esm@1.0.0
+Check file:///[WILDLINE]/main.cts
+error: TS2322 [ERROR]: Type '"cjs"' is not assignable to type '"other"'.
+const kind: "other" = mod.getKind();
+ ~~~~
+ at file:///[WILDLINE]/main.cts:3:7
diff --git a/tests/specs/npm/dual_cjs_esm/cjs_referrer/main.cts b/tests/specs/npm/dual_cjs_esm/cjs_referrer/main.cts
new file mode 100644
index 000000000..b8dd343f8
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/cjs_referrer/main.cts
@@ -0,0 +1,4 @@
+import mod = require("@denotest/dual-cjs-esm");
+
+const kind: "other" = mod.getKind();
+console.log(kind);
diff --git a/tests/specs/npm/dual_cjs_esm/cjs_referrer/main.out b/tests/specs/npm/dual_cjs_esm/cjs_referrer/main.out
new file mode 100644
index 000000000..62ddbf479
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/cjs_referrer/main.out
@@ -0,0 +1,4 @@
+Download http://localhost:4260/@denotest%2fdual-cjs-esm
+Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
+Initialize @denotest/dual-cjs-esm@1.0.0
+cjs
diff --git a/tests/specs/npm/dual_cjs_esm/cjs_referrer/package.json b/tests/specs/npm/dual_cjs_esm/cjs_referrer/package.json
new file mode 100644
index 000000000..e1b1e1a5f
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/cjs_referrer/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "@denotest/dual-cjs-esm": "*"
+ }
+}
diff --git a/tests/specs/npm/dual_cjs_esm/esm_referrer/__test__.jsonc b/tests/specs/npm/dual_cjs_esm/esm_referrer/__test__.jsonc
new file mode 100644
index 000000000..0ef147253
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/esm_referrer/__test__.jsonc
@@ -0,0 +1,4 @@
+{
+ "args": "run -A --quiet main.ts",
+ "output": "main.out"
+}
diff --git a/tests/specs/npm/dual_cjs_esm/dual_cjs_esm/main.out b/tests/specs/npm/dual_cjs_esm/esm_referrer/main.out
index 32e232f11..32e232f11 100644
--- a/tests/specs/npm/dual_cjs_esm/dual_cjs_esm/main.out
+++ b/tests/specs/npm/dual_cjs_esm/esm_referrer/main.out
diff --git a/tests/specs/npm/dual_cjs_esm/dual_cjs_esm/main.ts b/tests/specs/npm/dual_cjs_esm/esm_referrer/main.ts
index 4f3b79667..4f3b79667 100644
--- a/tests/specs/npm/dual_cjs_esm/dual_cjs_esm/main.ts
+++ b/tests/specs/npm/dual_cjs_esm/esm_referrer/main.ts
diff --git a/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/__test__.jsonc b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/__test__.jsonc
new file mode 100644
index 000000000..cf19217d1
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/__test__.jsonc
@@ -0,0 +1,14 @@
+{
+ "tempDir": true,
+ "tests": {
+ "check": {
+ "args": "check --node-modules-dir=auto main.ts",
+ "output": "check.out",
+ "exitCode": 1
+ },
+ "run": {
+ "args": "run --node-modules-dir=auto --allow-read main.ts",
+ "output": "main.out"
+ }
+ }
+}
diff --git a/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/check.out b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/check.out
new file mode 100644
index 000000000..cbd7740a9
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/check.out
@@ -0,0 +1,8 @@
+Download http://localhost:4260/@denotest%2fdual-cjs-esm
+Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
+Initialize @denotest/dual-cjs-esm@1.0.0
+Check file:///[WILDLINE]/main.ts
+error: TS2322 [ERROR]: Type '"cjs"' is not assignable to type '"other"'.
+const kind: "other" = mod.getKind();
+ ~~~~
+ at file:///[WILDLINE]/main.ts:3:7
diff --git a/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.out b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.out
new file mode 100644
index 000000000..62ddbf479
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.out
@@ -0,0 +1,4 @@
+Download http://localhost:4260/@denotest%2fdual-cjs-esm
+Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
+Initialize @denotest/dual-cjs-esm@1.0.0
+cjs
diff --git a/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.ts b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.ts
new file mode 100644
index 000000000..b8dd343f8
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/main.ts
@@ -0,0 +1,4 @@
+import mod = require("@denotest/dual-cjs-esm");
+
+const kind: "other" = mod.getKind();
+console.log(kind);
diff --git a/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/package.json b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/package.json
new file mode 100644
index 000000000..419d3d9f1
--- /dev/null
+++ b/tests/specs/npm/dual_cjs_esm/ts_referrer_type_cjs/package.json
@@ -0,0 +1,6 @@
+{
+ "type": "commonjs",
+ "dependencies": {
+ "@denotest/dual-cjs-esm": "*"
+ }
+}
diff --git a/tests/specs/npm/permissions_outside_package/__test__.jsonc b/tests/specs/npm/permissions_outside_package/__test__.jsonc
index 56228296b..d5f6bf490 100644
--- a/tests/specs/npm/permissions_outside_package/__test__.jsonc
+++ b/tests/specs/npm/permissions_outside_package/__test__.jsonc
@@ -1,4 +1,5 @@
{
- "args": "run --allow-read permissions_outside_package/main.ts",
- "output": "permissions_outside_package/main.out"
+ "tempDir": true,
+ "args": "run --allow-read --node-modules-dir=none main.ts",
+ "output": "main.out"
}
diff --git a/tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/config.js b/tests/specs/npm/permissions_outside_package/foo/config.js
index e667790d2..e667790d2 100644
--- a/tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/config.js
+++ b/tests/specs/npm/permissions_outside_package/foo/config.js
diff --git a/tests/specs/npm/permissions_outside_package/foo/package.json b/tests/specs/npm/permissions_outside_package/foo/package.json
new file mode 100644
index 000000000..95b43077e
--- /dev/null
+++ b/tests/specs/npm/permissions_outside_package/foo/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "foobar",
+ "version": "0.0.1",
+ "type": "commonjs"
+}
diff --git a/tests/specs/npm/permissions_outside_package/permissions_outside_package/main.out b/tests/specs/npm/permissions_outside_package/main.out
index 0fde8cf87..0fde8cf87 100644
--- a/tests/specs/npm/permissions_outside_package/permissions_outside_package/main.out
+++ b/tests/specs/npm/permissions_outside_package/main.out
diff --git a/tests/specs/npm/permissions_outside_package/permissions_outside_package/main.ts b/tests/specs/npm/permissions_outside_package/main.ts
index 934a3eebc..a80713fa7 100644
--- a/tests/specs/npm/permissions_outside_package/permissions_outside_package/main.ts
+++ b/tests/specs/npm/permissions_outside_package/main.ts
@@ -1,5 +1,5 @@
import { loadConfigFile } from "npm:@denotest/permissions-outside-package";
-const fileName = `${Deno.cwd()}/permissions_outside_package/foo/config.js`;
+const fileName = `${Deno.cwd()}/foo/config.js`;
const config = loadConfigFile(fileName);
console.log(config);
diff --git a/tests/specs/npm/permissions_outside_package/package.json b/tests/specs/npm/permissions_outside_package/package.json
new file mode 100644
index 000000000..2c63c0851
--- /dev/null
+++ b/tests/specs/npm/permissions_outside_package/package.json
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/package.json b/tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/package.json
deleted file mode 100644
index cc049e6ce..000000000
--- a/tests/specs/npm/permissions_outside_package/permissions_outside_package/foo/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "foobar",
- "version": "0.0.1"
-}
diff --git a/tests/specs/run/import_common_js/__test__.jsonc b/tests/specs/run/import_common_js/__test__.jsonc
index 6510dbad7..0602a09ba 100644
--- a/tests/specs/run/import_common_js/__test__.jsonc
+++ b/tests/specs/run/import_common_js/__test__.jsonc
@@ -1,21 +1,27 @@
{
- "steps": [
- { "args": "run -R index.cjs", "output": "index.out" },
- { "args": "run -R main.ts", "output": "main.out" },
- {
+ "tests": {
+ "cjs_entrypoint": {
+ "args": "run -R index.cjs",
+ "output": "index.out"
+ },
+ "esm_entrypoint": {
+ "args": "run -R main.ts",
+ "output": "main.out"
+ },
+ "module_error": {
"args": "run module_error.js",
"output": "module_error.out",
"exitCode": 1
},
- {
+ "exports_error": {
"args": "run exports_error.js",
"output": "exports_error.out",
"exitCode": 1
},
- {
+ "require_error": {
"args": "run require_error.js",
"output": "require_error.out",
"exitCode": 1
}
- ]
+ }
}
diff --git a/tests/specs/run/import_common_js/a.js b/tests/specs/run/import_common_js/a.js
deleted file mode 100644
index c465ab588..000000000
--- a/tests/specs/run/import_common_js/a.js
+++ /dev/null
@@ -1,7 +0,0 @@
-function foobar() {
- console.log("foobar");
-}
-
-module.exports = {
- foobar,
-};
diff --git a/tests/specs/run/import_common_js/exports_error.out b/tests/specs/run/import_common_js/exports_error.out
index b979cce5c..baa44682b 100644
--- a/tests/specs/run/import_common_js/exports_error.out
+++ b/tests/specs/run/import_common_js/exports_error.out
@@ -3,10 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
^
at [WILDCARD]exports_error.js:1:23
- info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
- with "type": "commonjs" option and --unstable-detect-cjs flag is used.
+ info: Deno supports CommonJS modules in .cjs files, or when the closest
+ package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM,
or change the file extension to .cjs,
- or add package.json next to the file with "type": "commonjs" option
- and pass --unstable-detect-cjs flag.
+ or add package.json next to the file with "type": "commonjs" option.
docs: https://docs.deno.com/go/commonjs
diff --git a/tests/specs/run/import_common_js/index.cjs b/tests/specs/run/import_common_js/index.cjs
index 18caf81e9..0026e237d 100644
--- a/tests/specs/run/import_common_js/index.cjs
+++ b/tests/specs/run/import_common_js/index.cjs
@@ -1,9 +1,7 @@
const process = require("process");
-const a = require("./a");
console.log(process.cwd());
module.exports = {
cwd: process.cwd,
- foobar: a.foobar,
};
diff --git a/tests/specs/run/import_common_js/index.out b/tests/specs/run/import_common_js/index.out
index 3650631b7..6a734b994 100644
--- a/tests/specs/run/import_common_js/index.out
+++ b/tests/specs/run/import_common_js/index.out
@@ -1 +1 @@
-[WILDCARD]import_common_js
+[WILDLINE]import_common_js
diff --git a/tests/specs/run/import_common_js/main.out b/tests/specs/run/import_common_js/main.out
index 03301b362..9df312975 100644
--- a/tests/specs/run/import_common_js/main.out
+++ b/tests/specs/run/import_common_js/main.out
@@ -1,5 +1,3 @@
hello from foo node module
[WILDCARD]import_common_js
cjsModule.cwd() [WILDCARD]import_common_js
-foobar
-cjsModule.foobar() undefined
diff --git a/tests/specs/run/import_common_js/module_error.out b/tests/specs/run/import_common_js/module_error.out
index 654ee838d..957b19cb1 100644
--- a/tests/specs/run/import_common_js/module_error.out
+++ b/tests/specs/run/import_common_js/module_error.out
@@ -3,10 +3,9 @@ module.exports = {
^
at [WILDCARD]module_error.js:1:1
- info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
- with "type": "commonjs" option and --unstable-detect-cjs flag is used.
+ info: Deno supports CommonJS modules in .cjs files, or when the closest
+ package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM,
or change the file extension to .cjs,
- or add package.json next to the file with "type": "commonjs" option
- and pass --unstable-detect-cjs flag.
+ or add package.json next to the file with "type": "commonjs" option.
docs: https://docs.deno.com/go/commonjs
diff --git a/tests/specs/run/import_common_js/node_modules/foo/index.mjs b/tests/specs/run/import_common_js/node_modules/foo/index.mjs
index cc93554c7..7a11d39ae 100644
--- a/tests/specs/run/import_common_js/node_modules/foo/index.mjs
+++ b/tests/specs/run/import_common_js/node_modules/foo/index.mjs
@@ -10,5 +10,4 @@ export default async function () {
const cjsModule = await import(url.pathToFileURL(cjsFileToImport));
console.log("cjsModule.cwd()", cjsModule.cwd());
- console.log("cjsModule.foobar()", cjsModule.foobar());
}
diff --git a/tests/specs/run/import_common_js/require_error.out b/tests/specs/run/import_common_js/require_error.out
index 81ffd6591..e13db85e8 100644
--- a/tests/specs/run/import_common_js/require_error.out
+++ b/tests/specs/run/import_common_js/require_error.out
@@ -3,10 +3,9 @@ const process = require("process");
^
at [WILDCARD]require_error.js:1:17
- info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
- with "type": "commonjs" option and --unstable-detect-cjs flag is used.
+ info: Deno supports CommonJS modules in .cjs files, or when the closest
+ package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM,
or change the file extension to .cjs,
- or add package.json next to the file with "type": "commonjs" option
- and pass --unstable-detect-cjs flag.
+ or add package.json next to the file with "type": "commonjs" option.
docs: https://docs.deno.com/go/commonjs
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/__test__.jsonc b/tests/specs/run/npm_pkg_requires_esm_js/__test__.jsonc
new file mode 100644
index 000000000..3da8db404
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/__test__.jsonc
@@ -0,0 +1,5 @@
+{
+ "args": "run -A main.js",
+ "output": "output.out",
+ "exitCode": 1
+}
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/file.js b/tests/specs/run/npm_pkg_requires_esm_js/file.js
new file mode 100644
index 000000000..d9536a69b
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/file.js
@@ -0,0 +1 @@
+console.log(import.meta.url);
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/logs_require.js b/tests/specs/run/npm_pkg_requires_esm_js/logs_require.js
new file mode 100644
index 000000000..984e1f3e7
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/logs_require.js
@@ -0,0 +1 @@
+console.log(require);
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/main.js b/tests/specs/run/npm_pkg_requires_esm_js/main.js
new file mode 100644
index 000000000..3704c8bf6
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/main.js
@@ -0,0 +1,5 @@
+import doRequire from "package";
+import path from "node:path";
+
+doRequire(path.resolve(import.meta.dirname, "file.js"));
+doRequire(path.resolve(import.meta.dirname, "logs_require.js"));
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/index.js b/tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/index.js
new file mode 100644
index 000000000..5d7872371
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/index.js
@@ -0,0 +1,3 @@
+module.exports = (file) => {
+ return require(file);
+};
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/package.json b/tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/package.json
new file mode 100644
index 000000000..5723987e9
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/node_modules/package/package.json
@@ -0,0 +1,4 @@
+{
+ "name": "package",
+ "version": "1.0.0"
+} \ No newline at end of file
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/output.out b/tests/specs/run/npm_pkg_requires_esm_js/output.out
new file mode 100644
index 000000000..2cae7108b
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/output.out
@@ -0,0 +1,12 @@
+file:///[WILDLINE]/file.js
+error: Uncaught (in promise) ReferenceError: require is not defined
+console.log(require);
+ ^
+ at [WILDCARD]
+
+ info: Deno supports CommonJS modules in .cjs files, or when the closest
+ package.json has a "type": "commonjs" option.
+ hint: Rewrite this module to ESM,
+ or change the file extension to .cjs,
+ or add package.json next to the file with "type": "commonjs" option.
+ docs: https://docs.deno.com/go/commonjs
diff --git a/tests/specs/run/npm_pkg_requires_esm_js/package.json b/tests/specs/run/npm_pkg_requires_esm_js/package.json
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/specs/run/npm_pkg_requires_esm_js/package.json
diff --git a/tests/specs/run/package_json_type/commonjs/basic/deno.jsonc b/tests/specs/run/package_json_type/commonjs/basic/deno.jsonc
deleted file mode 100644
index 35f64c86f..000000000
--- a/tests/specs/run/package_json_type/commonjs/basic/deno.jsonc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "unstable": [
- "detect-cjs"
- ]
-}
diff --git a/tests/specs/run/package_json_type/commonjs/basic/main_mix.out b/tests/specs/run/package_json_type/commonjs/basic/main_mix.out
index 78f421644..65671fd61 100644
--- a/tests/specs/run/package_json_type/commonjs/basic/main_mix.out
+++ b/tests/specs/run/package_json_type/commonjs/basic/main_mix.out
@@ -4,10 +4,9 @@ console.log(require("./add").add(1, 2));
^
at file:///[WILDLINE]main_mix.js:[WILDLINE]
- info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
- with "type": "commonjs" option and --unstable-detect-cjs flag is used.
+ info: Deno supports CommonJS modules in .cjs files, or when the closest
+ package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM,
or change the file extension to .cjs,
- or add package.json next to the file with "type": "commonjs" option
- and pass --unstable-detect-cjs flag.
+ or add package.json next to the file with "type": "commonjs" option.
docs: https://docs.deno.com/go/commonjs
diff --git a/tests/specs/run/package_json_type/commonjs/jsx/deno.jsonc b/tests/specs/run/package_json_type/commonjs/jsx/deno.jsonc
index 192ddb98c..31d05ffb7 100644
--- a/tests/specs/run/package_json_type/commonjs/jsx/deno.jsonc
+++ b/tests/specs/run/package_json_type/commonjs/jsx/deno.jsonc
@@ -3,8 +3,5 @@
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
- },
- "unstable": [
- "detect-cjs"
- ]
+ }
}
diff --git a/tests/specs/run/package_json_type/none/deno.jsonc b/tests/specs/run/package_json_type/none/deno.jsonc
deleted file mode 100644
index 35f64c86f..000000000
--- a/tests/specs/run/package_json_type/none/deno.jsonc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "unstable": [
- "detect-cjs"
- ]
-}
diff --git a/tests/specs/run/package_json_type/none/main_cjs.out b/tests/specs/run/package_json_type/none/main_cjs.out
index 8d34808fb..afa5028f4 100644
--- a/tests/specs/run/package_json_type/none/main_cjs.out
+++ b/tests/specs/run/package_json_type/none/main_cjs.out
@@ -3,10 +3,9 @@ const { add } = require("./add");
^
at file:///[WILDLINE]
- info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
- with "type": "commonjs" option and --unstable-detect-cjs flag is used.
+ info: Deno supports CommonJS modules in .cjs files, or when the closest
+ package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM,
or change the file extension to .cjs,
- or add package.json next to the file with "type": "commonjs" option
- and pass --unstable-detect-cjs flag.
+ or add package.json next to the file with "type": "commonjs" option.
docs: https://docs.deno.com/go/commonjs
diff --git a/tests/specs/run/require_esm/main.out b/tests/specs/run/require_esm/main.out
index 57b842b34..4890e1a49 100644
--- a/tests/specs/run/require_esm/main.out
+++ b/tests/specs/run/require_esm/main.out
@@ -1,13 +1,4 @@
[Module: null prototype] { sync_js: 1 }
[Module: null prototype] { sync_mjs: 1 }
error: Uncaught (in promise) Error: Top-level await is not allowed in synchronous evaluation
- at loadESMFromCJS (node:module:[WILDCARD])
- at Module._compile (node:module:[WILDCARD])
- at Object.Module._extensions..js (node:module:[WILDCARD])
- at Module.load (node:module:[WILDCARD])
- at Function.Module._load (node:module:[WILDCARD])
- at Module.require (node:module:[WILDCARD])
- at require (node:module:[WILDCARD])
- at Object.<anonymous> (file:[WILDCARD]/tests/specs/run/require_esm/main.cjs:[WILDCARD])
- at Object.<anonymous> (file:[WILDCARD]/tests/specs/run/require_esm/main.cjs:[WILDCARD])
- at Module._compile (node:module:[WILDCARD])
+ at [WILDCARD]
diff --git a/tests/specs/run/stdin_type_cjs/__test__.jsonc b/tests/specs/run/stdin_type_cjs/__test__.jsonc
new file mode 100644
index 000000000..e60af4a80
--- /dev/null
+++ b/tests/specs/run/stdin_type_cjs/__test__.jsonc
@@ -0,0 +1,5 @@
+{
+ "args": "run --quiet -",
+ "output": "1\n",
+ "input": "console.log(1)"
+}
diff --git a/tests/specs/run/stdin_type_cjs/package.json b/tests/specs/run/stdin_type_cjs/package.json
new file mode 100644
index 000000000..5bbefffba
--- /dev/null
+++ b/tests/specs/run/stdin_type_cjs/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "commonjs"
+}
diff --git a/tests/specs/run/stdin_type_cjs/stdin_read_all.ts b/tests/specs/run/stdin_type_cjs/stdin_read_all.ts
new file mode 100644
index 000000000..2ecae40b7
--- /dev/null
+++ b/tests/specs/run/stdin_type_cjs/stdin_read_all.ts
@@ -0,0 +1 @@
+Deno.stdin.readable.pipeTo(Deno.stdout.writable);
diff --git a/tests/specs/schema.json b/tests/specs/schema.json
index 8f3953ee4..2b35d9bd7 100644
--- a/tests/specs/schema.json
+++ b/tests/specs/schema.json
@@ -36,6 +36,9 @@
"flaky": {
"type": "boolean"
},
+ "symlinkedTempDir": {
+ "type": "boolean"
+ },
"if": {
"type": "string",
"examples": [
diff --git a/tests/util/server/src/servers/mod.rs b/tests/util/server/src/servers/mod.rs
index d9adde542..0b1d99aeb 100644
--- a/tests/util/server/src/servers/mod.rs
+++ b/tests/util/server/src/servers/mod.rs
@@ -807,17 +807,17 @@ async fn main_server(
(_, "/jsx/jsx-runtime") | (_, "/jsx/jsx-dev-runtime") => {
let mut res = Response::new(string_body(
r#"export function jsx(
- _type,
- _props,
- _key,
- _source,
- _self,
- ) {}
- export const jsxs = jsx;
- export const jsxDEV = jsx;
- export const Fragment = Symbol("Fragment");
- console.log("imported", import.meta.url);
- "#,
+ _type,
+ _props,
+ _key,
+ _source,
+ _self,
+) {}
+export const jsxs = jsx;
+export const jsxDEV = jsx;
+export const Fragment = Symbol("Fragment");
+console.log("imported", import.meta.url);
+"#,
));
res.headers_mut().insert(
"Content-type",