summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsnek <snek@deno.com>2024-09-19 21:10:34 -0700
committerGitHub <noreply@github.com>2024-09-19 21:10:34 -0700
commita01dce3a25e0bf671c6c21bd6ff57861be613087 (patch)
treebecb8a7c90e5a21e83c81160eec9d91e1281bc92
parentf1ba26661346a83b6e7fe5e7ffeed4553a9571ae (diff)
fix: cjs resolution cases (#25739)
Fixes cjs modules being loaded as esm.
-rw-r--r--cli/factory.rs8
-rw-r--r--cli/node.rs39
-rw-r--r--cli/standalone/mod.rs19
-rw-r--r--cli/worker.rs3
-rw-r--r--ext/node/polyfills/01_require.js7
-rw-r--r--tests/registry/npm/@denotest/type-commonjs/1.0.0/index.js1
-rw-r--r--tests/registry/npm/@denotest/type-commonjs/1.0.0/package.json5
-rw-r--r--tests/specs/npm/require_type_commonjs/__test__.jsonc5
-rw-r--r--tests/specs/npm/require_type_commonjs/main.out10
-rw-r--r--tests/specs/npm/require_type_commonjs/main.ts1
-rw-r--r--tests/specs/run/require_esm/main.out2
11 files changed, 83 insertions, 17 deletions
diff --git a/cli/factory.rs b/cli/factory.rs
index 6d14475b2..0f49546d0 100644
--- a/cli/factory.rs
+++ b/cli/factory.rs
@@ -572,8 +572,12 @@ impl CliFactory {
let caches = self.caches()?;
let node_analysis_cache =
NodeAnalysisCache::new(caches.node_analysis_db());
- let cjs_esm_analyzer =
- CliCjsCodeAnalyzer::new(node_analysis_cache, self.fs().clone());
+ let node_resolver = self.cli_node_resolver().await?.clone();
+ let cjs_esm_analyzer = CliCjsCodeAnalyzer::new(
+ node_analysis_cache,
+ self.fs().clone(),
+ node_resolver,
+ );
Ok(Arc::new(NodeCodeTranslator::new(
cjs_esm_analyzer,
diff --git a/cli/node.rs b/cli/node.rs
index 766da1c01..a3cee8dde 100644
--- a/cli/node.rs
+++ b/cli/node.rs
@@ -16,6 +16,7 @@ use serde::Serialize;
use crate::cache::CacheDBHash;
use crate::cache::NodeAnalysisCache;
+use crate::resolver::CliNodeResolver;
use crate::util::fs::canonicalize_path_maybe_not_exists;
pub type CliNodeCodeTranslator =
@@ -54,11 +55,20 @@ pub enum CliCjsAnalysis {
pub struct CliCjsCodeAnalyzer {
cache: NodeAnalysisCache,
fs: deno_fs::FileSystemRc,
+ node_resolver: Arc<CliNodeResolver>,
}
impl CliCjsCodeAnalyzer {
- pub fn new(cache: NodeAnalysisCache, fs: deno_fs::FileSystemRc) -> Self {
- Self { cache, fs }
+ pub fn new(
+ cache: NodeAnalysisCache,
+ fs: deno_fs::FileSystemRc,
+ node_resolver: Arc<CliNodeResolver>,
+ ) -> Self {
+ Self {
+ cache,
+ fs,
+ node_resolver,
+ }
}
async fn inner_cjs_analysis(
@@ -73,7 +83,7 @@ impl CliCjsCodeAnalyzer {
return Ok(analysis);
}
- let media_type = MediaType::from_specifier(specifier);
+ let mut media_type = MediaType::from_specifier(specifier);
if media_type == MediaType::Json {
return Ok(CliCjsAnalysis::Cjs {
exports: vec![],
@@ -81,6 +91,22 @@ impl CliCjsCodeAnalyzer {
});
}
+ if media_type == MediaType::JavaScript {
+ if let Some(package_json) =
+ self.node_resolver.get_closest_package_json(specifier)?
+ {
+ match package_json.typ.as_str() {
+ "commonjs" => {
+ media_type = MediaType::Cjs;
+ }
+ "module" => {
+ media_type = MediaType::Mjs;
+ }
+ _ => {}
+ }
+ }
+ }
+
let analysis = deno_core::unsync::spawn_blocking({
let specifier = specifier.clone();
let source: Arc<str> = source.into();
@@ -99,6 +125,13 @@ impl CliCjsCodeAnalyzer {
exports: analysis.exports,
reexports: analysis.reexports,
})
+ } else if media_type == MediaType::Cjs {
+ // FIXME: `deno_ast` should internally handle MediaType::Cjs implying that
+ // the result must never be Esm
+ Ok(CliCjsAnalysis::Cjs {
+ exports: vec![],
+ reexports: vec![],
+ })
} else {
Ok(CliCjsAnalysis::Esm)
}
diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs
index 1b1635d59..bab266734 100644
--- a/cli/standalone/mod.rs
+++ b/cli/standalone/mod.rs
@@ -580,8 +580,17 @@ pub async fn run(
let cjs_resolutions = Arc::new(CjsResolutionStore::default());
let cache_db = Caches::new(deno_dir_provider.clone());
let node_analysis_cache = NodeAnalysisCache::new(cache_db.node_analysis_db());
- let cjs_esm_code_analyzer =
- CliCjsCodeAnalyzer::new(node_analysis_cache, fs.clone());
+ let cli_node_resolver = Arc::new(CliNodeResolver::new(
+ cjs_resolutions.clone(),
+ fs.clone(),
+ node_resolver.clone(),
+ npm_resolver.clone(),
+ ));
+ let cjs_esm_code_analyzer = CliCjsCodeAnalyzer::new(
+ node_analysis_cache,
+ fs.clone(),
+ cli_node_resolver.clone(),
+ );
let node_code_translator = Arc::new(NodeCodeTranslator::new(
cjs_esm_code_analyzer,
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
@@ -637,12 +646,6 @@ pub async fn run(
metadata.workspace_resolver.pkg_json_resolution,
)
};
- let cli_node_resolver = Arc::new(CliNodeResolver::new(
- cjs_resolutions.clone(),
- fs.clone(),
- node_resolver.clone(),
- npm_resolver.clone(),
- ));
let module_loader_factory = StandaloneModuleLoaderFactory {
shared: Arc::new(SharedModuleLoaderState {
eszip: WorkspaceEszip {
diff --git a/cli/worker.rs b/cli/worker.rs
index 78753bf22..6176398d5 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -526,7 +526,8 @@ impl CliMainWorkerFactory {
let is_main_cjs = matches!(node_resolution, NodeResolution::CommonJs(_));
(node_resolution.into_url(), is_main_cjs)
} else {
- (main_module, false)
+ let is_cjs = main_module.path().ends_with(".cjs");
+ (main_module, is_cjs)
};
let ModuleLoaderAndSourceMapGetter { module_loader } =
diff --git a/ext/node/polyfills/01_require.js b/ext/node/polyfills/01_require.js
index e79f5a654..5b0980c31 100644
--- a/ext/node/polyfills/01_require.js
+++ b/ext/node/polyfills/01_require.js
@@ -1007,7 +1007,10 @@ Module.prototype._compile = function (content, filename, format) {
try {
compiledWrapper = wrapSafe(filename, content, this, format);
} catch (err) {
- if (err instanceof SyntaxError && op_require_can_parse_as_esm(content)) {
+ if (
+ format !== "commonjs" && err instanceof SyntaxError &&
+ op_require_can_parse_as_esm(content)
+ ) {
return loadESMFromCJS(this, filename, content);
}
throw err;
@@ -1067,7 +1070,7 @@ Module._extensions[".js"] = function (module, filename) {
let format;
if (StringPrototypeEndsWith(filename, ".js")) {
const pkg = op_require_read_closest_package_json(filename);
- if (pkg?.typ === "module") {
+ if (pkg?.type === "module") {
format = "module";
} else if (pkg?.type === "commonjs") {
format = "commonjs";
diff --git a/tests/registry/npm/@denotest/type-commonjs/1.0.0/index.js b/tests/registry/npm/@denotest/type-commonjs/1.0.0/index.js
new file mode 100644
index 000000000..cb0ff5c3b
--- /dev/null
+++ b/tests/registry/npm/@denotest/type-commonjs/1.0.0/index.js
@@ -0,0 +1 @@
+export {};
diff --git a/tests/registry/npm/@denotest/type-commonjs/1.0.0/package.json b/tests/registry/npm/@denotest/type-commonjs/1.0.0/package.json
new file mode 100644
index 000000000..d10933e86
--- /dev/null
+++ b/tests/registry/npm/@denotest/type-commonjs/1.0.0/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "@denotest/type-commonjs",
+ "version": "1.0.0",
+ "type": "commonjs"
+}
diff --git a/tests/specs/npm/require_type_commonjs/__test__.jsonc b/tests/specs/npm/require_type_commonjs/__test__.jsonc
new file mode 100644
index 000000000..c9ba97ff5
--- /dev/null
+++ b/tests/specs/npm/require_type_commonjs/__test__.jsonc
@@ -0,0 +1,5 @@
+{
+ "args": "run --allow-read --quiet main.ts",
+ "output": "main.out",
+ "exitCode": 1
+}
diff --git a/tests/specs/npm/require_type_commonjs/main.out b/tests/specs/npm/require_type_commonjs/main.out
new file mode 100644
index 000000000..f7a81572c
--- /dev/null
+++ b/tests/specs/npm/require_type_commonjs/main.out
@@ -0,0 +1,10 @@
+error: Uncaught (in promise) SyntaxError: Unexpected token 'export'
+ at Object.evalContext (ext:core/01_core.js:[WILDCARD])
+ at wrapSafe (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 file:///[WILDCARD]/@denotest/type-commonjs/1.0.0/index.js:3:13
diff --git a/tests/specs/npm/require_type_commonjs/main.ts b/tests/specs/npm/require_type_commonjs/main.ts
new file mode 100644
index 000000000..243eb216e
--- /dev/null
+++ b/tests/specs/npm/require_type_commonjs/main.ts
@@ -0,0 +1 @@
+import "npm:@denotest/type-commonjs";
diff --git a/tests/specs/run/require_esm/main.out b/tests/specs/run/require_esm/main.out
index 57b842b34..d17b1ead5 100644
--- a/tests/specs/run/require_esm/main.out
+++ b/tests/specs/run/require_esm/main.out
@@ -1,6 +1,6 @@
[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
+error: Uncaught 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])