2025-01-17 15:39:29 -05:00
|
|
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
|
|
|
|
|
|
use std::borrow::Cow;
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
use deno_core::url::Url;
|
|
|
|
use deno_error::JsErrorBox;
|
|
|
|
use deno_lib::loader::NpmModuleLoader;
|
2025-01-19 14:23:07 -05:00
|
|
|
use deno_lib::standalone::binary::CjsExportAnalysisEntry;
|
2025-01-17 15:39:29 -05:00
|
|
|
use deno_media_type::MediaType;
|
|
|
|
use deno_resolver::npm::DenoInNpmPackageChecker;
|
|
|
|
use deno_resolver::npm::NpmReqResolver;
|
2025-01-19 14:23:07 -05:00
|
|
|
use deno_runtime::deno_fs::FileSystem;
|
2025-01-17 15:39:29 -05:00
|
|
|
use node_resolver::analyze::CjsAnalysis;
|
|
|
|
use node_resolver::analyze::CjsAnalysisExports;
|
|
|
|
use node_resolver::analyze::NodeCodeTranslator;
|
2025-01-23 18:52:55 -05:00
|
|
|
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
2025-01-17 15:39:29 -05:00
|
|
|
|
2025-01-19 14:23:07 -05:00
|
|
|
use crate::binary::StandaloneModules;
|
2025-01-17 15:39:29 -05:00
|
|
|
use crate::file_system::DenoRtSys;
|
|
|
|
|
|
|
|
pub type DenoRtCjsTracker =
|
|
|
|
deno_resolver::cjs::CjsTracker<DenoInNpmPackageChecker, DenoRtSys>;
|
|
|
|
pub type DenoRtNpmResolver = deno_resolver::npm::NpmResolver<DenoRtSys>;
|
|
|
|
pub type DenoRtNpmModuleLoader = NpmModuleLoader<
|
|
|
|
CjsCodeAnalyzer,
|
|
|
|
DenoInNpmPackageChecker,
|
2025-01-23 18:52:55 -05:00
|
|
|
DenoIsBuiltInNodeModuleChecker,
|
2025-01-17 15:39:29 -05:00
|
|
|
DenoRtNpmResolver,
|
|
|
|
DenoRtSys,
|
|
|
|
>;
|
|
|
|
pub type DenoRtNodeCodeTranslator = NodeCodeTranslator<
|
|
|
|
CjsCodeAnalyzer,
|
|
|
|
DenoInNpmPackageChecker,
|
2025-01-23 18:52:55 -05:00
|
|
|
DenoIsBuiltInNodeModuleChecker,
|
2025-01-17 15:39:29 -05:00
|
|
|
DenoRtNpmResolver,
|
|
|
|
DenoRtSys,
|
|
|
|
>;
|
|
|
|
pub type DenoRtNodeResolver = deno_runtime::deno_node::NodeResolver<
|
|
|
|
DenoInNpmPackageChecker,
|
|
|
|
DenoRtNpmResolver,
|
|
|
|
DenoRtSys,
|
|
|
|
>;
|
|
|
|
pub type DenoRtNpmReqResolver = NpmReqResolver<
|
|
|
|
DenoInNpmPackageChecker,
|
2025-01-23 18:52:55 -05:00
|
|
|
DenoIsBuiltInNodeModuleChecker,
|
2025-01-17 15:39:29 -05:00
|
|
|
DenoRtNpmResolver,
|
|
|
|
DenoRtSys,
|
|
|
|
>;
|
|
|
|
|
|
|
|
pub struct CjsCodeAnalyzer {
|
|
|
|
cjs_tracker: Arc<DenoRtCjsTracker>,
|
2025-01-19 14:23:07 -05:00
|
|
|
modules: Arc<StandaloneModules>,
|
|
|
|
sys: DenoRtSys,
|
2025-01-17 15:39:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl CjsCodeAnalyzer {
|
|
|
|
pub fn new(
|
|
|
|
cjs_tracker: Arc<DenoRtCjsTracker>,
|
2025-01-19 14:23:07 -05:00
|
|
|
modules: Arc<StandaloneModules>,
|
|
|
|
sys: DenoRtSys,
|
2025-01-17 15:39:29 -05:00
|
|
|
) -> Self {
|
2025-01-19 14:23:07 -05:00
|
|
|
Self {
|
|
|
|
cjs_tracker,
|
|
|
|
modules,
|
|
|
|
sys,
|
|
|
|
}
|
2025-01-17 15:39:29 -05:00
|
|
|
}
|
|
|
|
|
2025-01-19 14:23:07 -05:00
|
|
|
fn inner_cjs_analysis<'a>(
|
2025-01-17 15:39:29 -05:00
|
|
|
&self,
|
|
|
|
specifier: &Url,
|
|
|
|
source: Cow<'a, str>,
|
|
|
|
) -> Result<CjsAnalysis<'a>, JsErrorBox> {
|
|
|
|
let media_type = MediaType::from_specifier(specifier);
|
|
|
|
if media_type == MediaType::Json {
|
|
|
|
return Ok(CjsAnalysis::Cjs(CjsAnalysisExports {
|
|
|
|
exports: vec![],
|
|
|
|
reexports: vec![],
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
let cjs_tracker = self.cjs_tracker.clone();
|
|
|
|
let is_maybe_cjs = cjs_tracker
|
|
|
|
.is_maybe_cjs(specifier, media_type)
|
|
|
|
.map_err(JsErrorBox::from_err)?;
|
|
|
|
let analysis = if is_maybe_cjs {
|
2025-01-19 14:23:07 -05:00
|
|
|
let data = self
|
|
|
|
.modules
|
|
|
|
.read(specifier)?
|
|
|
|
.and_then(|d| d.cjs_export_analysis);
|
|
|
|
match data {
|
|
|
|
Some(data) => {
|
|
|
|
let data: CjsExportAnalysisEntry = bincode::deserialize(&data)
|
|
|
|
.map_err(|err| JsErrorBox::generic(err.to_string()))?;
|
|
|
|
match data {
|
|
|
|
CjsExportAnalysisEntry::Esm => {
|
|
|
|
cjs_tracker.set_is_known_script(specifier, false);
|
|
|
|
CjsAnalysis::Esm(source)
|
|
|
|
}
|
|
|
|
CjsExportAnalysisEntry::Cjs(analysis) => {
|
|
|
|
cjs_tracker.set_is_known_script(specifier, true);
|
|
|
|
CjsAnalysis::Cjs(analysis)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
if log::log_enabled!(log::Level::Debug) {
|
|
|
|
if self.sys.is_specifier_in_vfs(specifier) {
|
|
|
|
log::debug!(
|
|
|
|
"No CJS export analysis was stored for '{}'. Assuming ESM. This might indicate a bug in Deno.",
|
|
|
|
specifier
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
log::debug!(
|
|
|
|
"Analyzing potentially CommonJS files is not supported at runtime in a compiled executable ({}). Assuming ESM.",
|
|
|
|
specifier
|
|
|
|
);
|
|
|
|
}
|
2025-01-17 15:39:29 -05:00
|
|
|
}
|
2025-01-19 14:23:07 -05:00
|
|
|
// assume ESM as we don't have access to swc here
|
|
|
|
CjsAnalysis::Esm(source)
|
2025-01-17 15:39:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CjsAnalysis::Esm(source)
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(analysis)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait::async_trait(?Send)]
|
|
|
|
impl node_resolver::analyze::CjsCodeAnalyzer for CjsCodeAnalyzer {
|
|
|
|
async fn analyze_cjs<'a>(
|
|
|
|
&self,
|
|
|
|
specifier: &Url,
|
|
|
|
source: Option<Cow<'a, str>>,
|
|
|
|
) -> Result<CjsAnalysis<'a>, JsErrorBox> {
|
|
|
|
let source = match source {
|
|
|
|
Some(source) => source,
|
|
|
|
None => {
|
2025-01-19 14:23:07 -05:00
|
|
|
if let Ok(path) = deno_path_util::url_to_file_path(specifier) {
|
|
|
|
// todo(dsherret): should this use the sync method instead?
|
2025-01-17 15:39:29 -05:00
|
|
|
if let Ok(source_from_file) =
|
2025-01-19 14:23:07 -05:00
|
|
|
self.sys.read_text_file_lossy_async(path, None).await
|
2025-01-17 15:39:29 -05:00
|
|
|
{
|
|
|
|
source_from_file
|
|
|
|
} else {
|
|
|
|
return Ok(CjsAnalysis::Cjs(CjsAnalysisExports {
|
|
|
|
exports: vec![],
|
|
|
|
reexports: vec![],
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Ok(CjsAnalysis::Cjs(CjsAnalysisExports {
|
|
|
|
exports: vec![],
|
|
|
|
reexports: vec![],
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2025-01-19 14:23:07 -05:00
|
|
|
self.inner_cjs_analysis(specifier, source)
|
2025-01-17 15:39:29 -05:00
|
|
|
}
|
|
|
|
}
|