diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2022-09-08 22:01:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-08 22:01:48 +0200 |
commit | 6c179daff07fe60d478142ea86231a34dc9ee1fd (patch) | |
tree | 39ff8701af61eec0674827b4ef62de1d4087e407 /cli/node/mod.rs | |
parent | 93cbac69e8a53fbb393fc7a2f12654b223cf01ad (diff) |
fix(npm): recursive translation of reexports, remove window global in node code (#15806)
Co-authored-by: David Sherret <dsherret@gmail.com>
Diffstat (limited to 'cli/node/mod.rs')
-rw-r--r-- | cli/node/mod.rs | 121 |
1 files changed, 71 insertions, 50 deletions
diff --git a/cli/node/mod.rs b/cli/node/mod.rs index 14cc49473..9bc5b4a96 100644 --- a/cli/node/mod.rs +++ b/cli/node/mod.rs @@ -1,10 +1,12 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use std::collections::HashSet; +use std::collections::VecDeque; use std::path::Path; use std::path::PathBuf; use crate::deno_std::CURRENT_STD_URL; +use deno_ast::CjsAnalysis; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; @@ -25,6 +27,7 @@ use deno_runtime::deno_node::DenoDirNpmResolver; use deno_runtime::deno_node::NodeModuleKind; use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_node::DEFAULT_CONDITIONS; +use deno_runtime::deno_node::NODE_GLOBAL_THIS_NAME; use once_cell::sync::Lazy; use path_clean::PathClean; use regex::Regex; @@ -326,11 +329,12 @@ pub async fn initialize_runtime( js_runtime: &mut JsRuntime, ) -> Result<(), AnyError> { let source_code = &format!( - r#"(async function loadBuiltinNodeModules(moduleAllUrl) {{ + r#"(async function loadBuiltinNodeModules(moduleAllUrl, nodeGlobalThisName) {{ const moduleAll = await import(moduleAllUrl); - Deno[Deno.internal].node.initialize(moduleAll.default); - }})('{}');"#, + Deno[Deno.internal].node.initialize(moduleAll.default, nodeGlobalThisName); + }})('{}', '{}');"#, MODULE_ALL_URL.as_str(), + NODE_GLOBAL_THIS_NAME.as_str(), ); let value = @@ -710,32 +714,60 @@ pub fn translate_cjs_to_esm( media_type: MediaType, npm_resolver: &GlobalNpmPackageResolver, ) -> Result<String, AnyError> { - let parsed_source = deno_ast::parse_script(deno_ast::ParseParams { - specifier: specifier.to_string(), - text_info: deno_ast::SourceTextInfo::new(code.into()), - media_type, - capture_tokens: true, - scope_analysis: false, - maybe_syntax: None, - })?; - let analysis = parsed_source.analyze_cjs(); + fn perform_cjs_analysis( + specifier: &str, + media_type: MediaType, + code: String, + ) -> Result<CjsAnalysis, AnyError> { + let parsed_source = deno_ast::parse_script(deno_ast::ParseParams { + specifier: specifier.to_string(), + text_info: deno_ast::SourceTextInfo::new(code.into()), + media_type, + capture_tokens: true, + scope_analysis: false, + maybe_syntax: None, + })?; + Ok(parsed_source.analyze_cjs()) + } + + let mut temp_var_count = 0; + let mut handled_reexports: HashSet<String> = HashSet::default(); + + let mut source = vec![ + r#"var window = undefined;"#.to_string(), + r#"const require = Deno[Deno.internal].require.Module.createRequire(import.meta.url);"#.to_string(), + ]; + + let analysis = perform_cjs_analysis(specifier.as_str(), media_type, code)?; + let root_exports = analysis .exports .iter() .map(|s| s.as_str()) .collect::<HashSet<_>>(); - let mut temp_var_count = 0; + let mut all_exports = analysis + .exports + .iter() + .map(|s| s.to_string()) + .collect::<HashSet<_>>(); - let mut source = vec![ - r#"const require = Deno[Deno.internal].require.Module.createRequire(import.meta.url);"#.to_string(), - ]; + // (request, referrer) + let mut reexports_to_handle = VecDeque::new(); + for reexport in analysis.reexports { + reexports_to_handle.push_back((reexport, specifier.clone())); + } + + while let Some((reexport, referrer)) = reexports_to_handle.pop_front() { + if handled_reexports.contains(&reexport) { + continue; + } + + handled_reexports.insert(reexport.to_string()); - // if there are reexports, handle them first - for (idx, reexport) in analysis.reexports.iter().enumerate() { - // Firstly, resolve relate reexport specifier + // First, resolve relate reexport specifier let resolved_reexport = resolve( - reexport, - specifier, + &reexport, + &referrer, // FIXME(bartlomieju): check if these conditions are okay, probably // should be `deno-require`, because `deno` is already used in `esm_resolver.rs` &["deno", "require", "default"], @@ -743,35 +775,26 @@ pub fn translate_cjs_to_esm( )?; let reexport_specifier = ModuleSpecifier::from_file_path(&resolved_reexport).unwrap(); - // Secondly, read the source code from disk + // Second, read the source code from disk let reexport_file = file_fetcher.get_source(&reexport_specifier).unwrap(); - // Now perform analysis again + { - let parsed_source = deno_ast::parse_script(deno_ast::ParseParams { - specifier: reexport_specifier.to_string(), - text_info: deno_ast::SourceTextInfo::new(reexport_file.source), - media_type: reexport_file.media_type, - capture_tokens: true, - scope_analysis: false, - maybe_syntax: None, - })?; - let analysis = parsed_source.analyze_cjs(); - - source.push(format!( - "const reexport{} = require(\"{}\");", - idx, reexport - )); - - for export in analysis.exports.iter().filter(|e| { - e.as_str() != "default" && !root_exports.contains(e.as_str()) - }) { - add_export( - &mut source, - export, - &format!("Deno[Deno.internal].require.bindExport(reexport{0}[\"{1}\"], reexport{0})", idx, export), - &mut temp_var_count, - ); + let analysis = perform_cjs_analysis( + reexport_specifier.as_str(), + reexport_file.media_type, + reexport_file.source.to_string(), + )?; + + for reexport in analysis.reexports { + reexports_to_handle.push_back((reexport, reexport_specifier.clone())); } + + all_exports.extend( + analysis + .exports + .into_iter() + .filter(|e| e.as_str() != "default"), + ); } } @@ -788,7 +811,7 @@ pub fn translate_cjs_to_esm( )); let mut had_default = false; - for export in analysis.exports.iter() { + for export in &all_exports { if export.as_str() == "default" { if root_exports.contains("__esModule") { source.push(format!( @@ -880,7 +903,6 @@ fn resolve( return Ok(module_dir.join("index.js").clean()); } } - Err(not_found(specifier, &referrer_path)) } @@ -988,7 +1010,6 @@ fn file_extension_probe( return Ok(p_js); } } - Err(not_found(&p.to_string_lossy(), referrer)) } |