summaryrefslogtreecommitdiff
path: root/cli/node.rs
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2023-07-19 10:30:04 +0200
committerGitHub <noreply@github.com>2023-07-19 10:30:04 +0200
commite511022c7445cc22193edb1626c77d9674935425 (patch)
tree521b30eac14cd19a506c9cdfa52cde1da7211dcf /cli/node.rs
parentbf4e99cbd77087706e7ea7034bd90079c2218e2b (diff)
feat(ext/node): properly segregate node globals (#19307)
Code run within Deno-mode and Node-mode should have access to a slightly different set of globals. Previously this was done through a compile time code-transform for Node-mode, but this is not ideal and has many edge cases, for example Node's globalThis having a different identity than Deno's globalThis. This commit makes the `globalThis` of the entire runtime a semi-proxy. This proxy returns a different set of globals depending on the caller's mode. This is not a full proxy, because it is shadowed by "real" properties on globalThis. This is done to avoid the overhead of a full proxy for all globalThis operations. The globals between Deno-mode and Node-mode are now properly segregated. This means that code running in Deno-mode will not have access to Node's globals, and vice versa. Deleting a managed global in Deno-mode will NOT delete the corresponding global in Node-mode, and vice versa. --------- Co-authored-by: Bartek IwaƄczuk <biwanczuk@gmail.com> Co-authored-by: Aapo Alasuutari <aapo.alasuutari@gmail.com>
Diffstat (limited to 'cli/node.rs')
-rw-r--r--cli/node.rs117
1 files changed, 5 insertions, 112 deletions
diff --git a/cli/node.rs b/cli/node.rs
index 8b54d0d42..75e0d9ef9 100644
--- a/cli/node.rs
+++ b/cli/node.rs
@@ -1,24 +1,17 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use std::collections::HashSet;
-
-use deno_ast::swc::common::SyntaxContext;
-use deno_ast::view::Node;
-use deno_ast::view::NodeTrait;
use deno_ast::CjsAnalysis;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
-use deno_ast::ParsedSource;
-use deno_ast::SourceRanged;
use deno_core::error::AnyError;
use deno_runtime::deno_node::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
-use deno_runtime::deno_node::analyze::CjsEsmCodeAnalyzer;
+use deno_runtime::deno_node::analyze::CjsCodeAnalyzer;
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
use crate::cache::NodeAnalysisCache;
use crate::util::fs::canonicalize_path_maybe_not_exists;
-pub type CliNodeCodeTranslator = NodeCodeTranslator<CliCjsEsmCodeAnalyzer>;
+pub type CliNodeCodeTranslator = NodeCodeTranslator<CliCjsCodeAnalyzer>;
/// Resolves a specifier that is pointing into a node_modules folder.
///
@@ -39,11 +32,11 @@ pub fn resolve_specifier_into_node_modules(
.unwrap_or_else(|| specifier.clone())
}
-pub struct CliCjsEsmCodeAnalyzer {
+pub struct CliCjsCodeAnalyzer {
cache: NodeAnalysisCache,
}
-impl CliCjsEsmCodeAnalyzer {
+impl CliCjsCodeAnalyzer {
pub fn new(cache: NodeAnalysisCache) -> Self {
Self { cache }
}
@@ -86,7 +79,7 @@ impl CliCjsEsmCodeAnalyzer {
}
}
-impl CjsEsmCodeAnalyzer for CliCjsEsmCodeAnalyzer {
+impl CjsCodeAnalyzer for CliCjsCodeAnalyzer {
fn analyze_cjs(
&self,
specifier: &ModuleSpecifier,
@@ -98,104 +91,4 @@ impl CjsEsmCodeAnalyzer for CliCjsEsmCodeAnalyzer {
reexports: analysis.reexports,
})
}
-
- fn analyze_esm_top_level_decls(
- &self,
- specifier: &ModuleSpecifier,
- source: &str,
- ) -> Result<HashSet<String>, AnyError> {
- // TODO(dsherret): this code is way more inefficient than it needs to be.
- //
- // In the future, we should disable capturing tokens & scope analysis
- // and instead only use swc's APIs to go through the portions of the tree
- // that we know will affect the global scope while still ensuring that
- // `var` decls are taken into consideration.
- let source_hash = NodeAnalysisCache::compute_source_hash(source);
- if let Some(decls) = self
- .cache
- .get_esm_analysis(specifier.as_str(), &source_hash)
- {
- Ok(HashSet::from_iter(decls))
- } else {
- let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
- specifier: specifier.to_string(),
- text_info: deno_ast::SourceTextInfo::from_string(source.to_string()),
- media_type: deno_ast::MediaType::from_specifier(specifier),
- capture_tokens: true,
- scope_analysis: true,
- maybe_syntax: None,
- })?;
- let top_level_decls = analyze_top_level_decls(&parsed_source)?;
- self.cache.set_esm_analysis(
- specifier.as_str(),
- &source_hash,
- &top_level_decls.clone().into_iter().collect::<Vec<_>>(),
- );
- Ok(top_level_decls)
- }
- }
-}
-
-fn analyze_top_level_decls(
- parsed_source: &ParsedSource,
-) -> Result<HashSet<String>, AnyError> {
- fn visit_children(
- node: Node,
- top_level_context: SyntaxContext,
- results: &mut HashSet<String>,
- ) {
- if let Node::Ident(ident) = node {
- if ident.ctxt() == top_level_context && is_local_declaration_ident(node) {
- results.insert(ident.sym().to_string());
- }
- }
-
- for child in node.children() {
- visit_children(child, top_level_context, results);
- }
- }
-
- let top_level_context = parsed_source.top_level_context();
-
- parsed_source.with_view(|program| {
- let mut results = HashSet::new();
- visit_children(program.into(), top_level_context, &mut results);
- Ok(results)
- })
-}
-
-fn is_local_declaration_ident(node: Node) -> bool {
- if let Some(parent) = node.parent() {
- match parent {
- Node::BindingIdent(decl) => decl.id.range().contains(&node.range()),
- Node::ClassDecl(decl) => decl.ident.range().contains(&node.range()),
- Node::ClassExpr(decl) => decl
- .ident
- .as_ref()
- .map(|i| i.range().contains(&node.range()))
- .unwrap_or(false),
- Node::TsInterfaceDecl(decl) => decl.id.range().contains(&node.range()),
- Node::FnDecl(decl) => decl.ident.range().contains(&node.range()),
- Node::FnExpr(decl) => decl
- .ident
- .as_ref()
- .map(|i| i.range().contains(&node.range()))
- .unwrap_or(false),
- Node::TsModuleDecl(decl) => decl.id.range().contains(&node.range()),
- Node::TsNamespaceDecl(decl) => decl.id.range().contains(&node.range()),
- Node::VarDeclarator(decl) => decl.name.range().contains(&node.range()),
- Node::ImportNamedSpecifier(decl) => {
- decl.local.range().contains(&node.range())
- }
- Node::ImportDefaultSpecifier(decl) => {
- decl.local.range().contains(&node.range())
- }
- Node::ImportStarAsSpecifier(decl) => decl.range().contains(&node.range()),
- Node::KeyValuePatProp(decl) => decl.key.range().contains(&node.range()),
- Node::AssignPatProp(decl) => decl.key.range().contains(&node.range()),
- _ => false,
- }
- } else {
- false
- }
}