diff --git a/cli/factory.rs b/cli/factory.rs index 6d14475b26..0f49546d07 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 766da1c014..a3cee8ddee 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, } 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, + ) -> 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 = 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 1b1635d598..bab2667347 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 78753bf223..6176398d54 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 e79f5a654b..5b0980c310 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 0000000000..cb0ff5c3b5 --- /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 0000000000..d10933e86f --- /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 0000000000..c9ba97ff52 --- /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 0000000000..f7a81572c3 --- /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 0000000000..243eb216e4 --- /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 57b842b345..d17b1ead55 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])