1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-30 16:40:57 -05:00

refactor(ext/node): CjsCodeAnalyzer - analyze_cjs optionally pass source text (#19896)

This commit is contained in:
David Sherret 2023-07-24 15:35:13 -04:00 committed by Matt Mastracci
parent e14281cf51
commit 36cce3f287
4 changed files with 43 additions and 29 deletions

View file

@ -475,7 +475,8 @@ impl CliFactory {
let caches = self.caches()?; let caches = self.caches()?;
let node_analysis_cache = let node_analysis_cache =
NodeAnalysisCache::new(caches.node_analysis_db()); NodeAnalysisCache::new(caches.node_analysis_db());
let cjs_esm_analyzer = CliCjsCodeAnalyzer::new(node_analysis_cache); let cjs_esm_analyzer =
CliCjsCodeAnalyzer::new(node_analysis_cache, self.fs().clone());
Ok(Arc::new(NodeCodeTranslator::new( Ok(Arc::new(NodeCodeTranslator::new(
cjs_esm_analyzer, cjs_esm_analyzer,

View file

@ -1,9 +1,12 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow;
use deno_ast::CjsAnalysis; use deno_ast::CjsAnalysis;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_ast::ModuleSpecifier; use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::analyze::CjsAnalysis as ExtNodeCjsAnalysis; use deno_runtime::deno_node::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
use deno_runtime::deno_node::analyze::CjsCodeAnalyzer; use deno_runtime::deno_node::analyze::CjsCodeAnalyzer;
use deno_runtime::deno_node::analyze::NodeCodeTranslator; use deno_runtime::deno_node::analyze::NodeCodeTranslator;
@ -34,11 +37,12 @@ pub fn resolve_specifier_into_node_modules(
pub struct CliCjsCodeAnalyzer { pub struct CliCjsCodeAnalyzer {
cache: NodeAnalysisCache, cache: NodeAnalysisCache,
fs: deno_fs::FileSystemRc,
} }
impl CliCjsCodeAnalyzer { impl CliCjsCodeAnalyzer {
pub fn new(cache: NodeAnalysisCache) -> Self { pub fn new(cache: NodeAnalysisCache, fs: deno_fs::FileSystemRc) -> Self {
Self { cache } Self { cache, fs }
} }
fn inner_cjs_analysis( fn inner_cjs_analysis(
@ -83,9 +87,15 @@ impl CjsCodeAnalyzer for CliCjsCodeAnalyzer {
fn analyze_cjs( fn analyze_cjs(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
source: &str, source: Option<&str>,
) -> Result<ExtNodeCjsAnalysis, AnyError> { ) -> Result<ExtNodeCjsAnalysis, AnyError> {
let analysis = self.inner_cjs_analysis(specifier, source)?; let source = match source {
Some(source) => Cow::Borrowed(source),
None => {
Cow::Owned(self.fs.read_to_string(&specifier.to_file_path().unwrap())?)
}
};
let analysis = self.inner_cjs_analysis(specifier, &source)?;
Ok(ExtNodeCjsAnalysis { Ok(ExtNodeCjsAnalysis {
exports: analysis.exports, exports: analysis.exports,
reexports: analysis.reexports, reexports: analysis.reexports,

View file

@ -366,7 +366,8 @@ pub async fn run(
let cjs_resolutions = Arc::new(CjsResolutionStore::default()); let cjs_resolutions = Arc::new(CjsResolutionStore::default());
let cache_db = Caches::new(deno_dir_provider.clone()); let cache_db = Caches::new(deno_dir_provider.clone());
let node_analysis_cache = NodeAnalysisCache::new(cache_db.node_analysis_db()); let node_analysis_cache = NodeAnalysisCache::new(cache_db.node_analysis_db());
let cjs_esm_code_analyzer = CliCjsCodeAnalyzer::new(node_analysis_cache); let cjs_esm_code_analyzer =
CliCjsCodeAnalyzer::new(node_analysis_cache, fs.clone());
let node_code_translator = Arc::new(NodeCodeTranslator::new( let node_code_translator = Arc::new(NodeCodeTranslator::new(
cjs_esm_code_analyzer, cjs_esm_code_analyzer,
fs.clone(), fs.clone(),

View file

@ -29,10 +29,15 @@ pub struct CjsAnalysis {
pub trait CjsCodeAnalyzer { pub trait CjsCodeAnalyzer {
/// Analyzes CommonJs code for exports and reexports, which is /// Analyzes CommonJs code for exports and reexports, which is
/// then used to determine the wrapper ESM module exports. /// then used to determine the wrapper ESM module exports.
///
/// Note that the source is provided by the caller when the caller
/// already has it. If the source is needed by the implementation,
/// then it can use the provided source, or otherwise load it if
/// necessary.
fn analyze_cjs( fn analyze_cjs(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
source: &str, maybe_source: Option<&str>,
) -> Result<CjsAnalysis, AnyError>; ) -> Result<CjsAnalysis, AnyError>;
} }
@ -73,7 +78,9 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
let mut temp_var_count = 0; let mut temp_var_count = 0;
let mut handled_reexports: HashSet<String> = HashSet::default(); let mut handled_reexports: HashSet<String> = HashSet::default();
let analysis = self.cjs_code_analyzer.analyze_cjs(specifier, source)?; let analysis = self
.cjs_code_analyzer
.analyze_cjs(specifier, Some(source))?;
let mut source = vec![ let mut source = vec![
r#"import {createRequire as __internalCreateRequire} from "node:module"; r#"import {createRequire as __internalCreateRequire} from "node:module";
@ -100,7 +107,7 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
handled_reexports.insert(reexport.to_string()); handled_reexports.insert(reexport.to_string());
// First, resolve relate reexport specifier // First, resolve the reexport specifier
let resolved_reexport = self.resolve( let resolved_reexport = self.resolve(
&reexport, &reexport,
&referrer, &referrer,
@ -110,35 +117,30 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
NodeResolutionMode::Execution, NodeResolutionMode::Execution,
permissions, permissions,
)?; )?;
// Second, read the source code from disk
// Second, resolve its exports and re-exports
let reexport_specifier = let reexport_specifier =
ModuleSpecifier::from_file_path(&resolved_reexport).unwrap(); ModuleSpecifier::from_file_path(&resolved_reexport).unwrap();
let reexport_file_text = self let analysis = self
.fs .cjs_code_analyzer
.read_to_string(&resolved_reexport) .analyze_cjs(&reexport_specifier, None)
.map_err(AnyError::from)
.with_context(|| { .with_context(|| {
format!( format!(
"Could not find '{}' ({}) referenced from {}", "Could not load '{}' ({}) referenced from {}",
reexport, reexport_specifier, referrer reexport, reexport_specifier, referrer
) )
})?; })?;
{
let analysis = self
.cjs_code_analyzer
.analyze_cjs(&reexport_specifier, &reexport_file_text)?;
for reexport in analysis.reexports { for reexport in analysis.reexports {
reexports_to_handle.push_back((reexport, reexport_specifier.clone())); reexports_to_handle.push_back((reexport, reexport_specifier.clone()));
}
all_exports.extend(
analysis
.exports
.into_iter()
.filter(|e| e.as_str() != "default"),
);
} }
all_exports.extend(
analysis
.exports
.into_iter()
.filter(|e| e.as_str() != "default"),
);
} }
source.push(format!( source.push(format!(