mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 20:38:55 +00:00
feat(node): stabilize detecting if CJS via "type": "commonjs"
in a package.json (#26439)
This will respect `"type": "commonjs"` in a package.json to determine if `.js`/`.jsx`/`.ts`/.tsx` files are CJS or ESM. If the file is found to be ESM it will be loaded as ESM though.
This commit is contained in:
parent
6a4c6d83ba
commit
f091d1ad69
@ -576,7 +576,6 @@ pub struct UnstableConfig {
|
||||
// TODO(bartlomieju): remove in Deno 2.5
|
||||
pub legacy_flag_enabled: bool, // --unstable
|
||||
pub bare_node_builtins: bool,
|
||||
pub detect_cjs: bool,
|
||||
pub sloppy_imports: bool,
|
||||
pub features: Vec<String>, // --unstabe-kv --unstable-cron
|
||||
}
|
||||
@ -5720,7 +5719,6 @@ fn unstable_args_parse(
|
||||
|
||||
flags.unstable_config.bare_node_builtins =
|
||||
matches.get_flag("unstable-bare-node-builtins");
|
||||
flags.unstable_config.detect_cjs = matches.get_flag("unstable-detect-cjs");
|
||||
flags.unstable_config.sloppy_imports =
|
||||
matches.get_flag("unstable-sloppy-imports");
|
||||
|
||||
|
@ -7,6 +7,7 @@ mod import_map;
|
||||
mod lockfile;
|
||||
mod package_json;
|
||||
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::SourceMapOption;
|
||||
use deno_config::deno_json::NodeModulesDirMode;
|
||||
use deno_config::workspace::CreateResolverOptions;
|
||||
@ -34,7 +35,6 @@ use import_map::resolve_import_map_value_from_specifier;
|
||||
pub use deno_config::deno_json::BenchConfig;
|
||||
pub use deno_config::deno_json::ConfigFile;
|
||||
pub use deno_config::deno_json::FmtOptionsConfig;
|
||||
pub use deno_config::deno_json::JsxImportSourceConfig;
|
||||
pub use deno_config::deno_json::LintRulesConfig;
|
||||
pub use deno_config::deno_json::ProseWrap;
|
||||
pub use deno_config::deno_json::TsConfig;
|
||||
@ -1155,21 +1155,34 @@ impl CliOptions {
|
||||
self
|
||||
.main_module_cell
|
||||
.get_or_init(|| {
|
||||
let main_module = match &self.flags.subcommand {
|
||||
Ok(match &self.flags.subcommand {
|
||||
DenoSubcommand::Compile(compile_flags) => {
|
||||
resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Eval(_) => {
|
||||
resolve_url_or_path("./$deno$eval.ts", self.initial_cwd())?
|
||||
resolve_url_or_path("./$deno$eval.mts", self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Repl(_) => {
|
||||
resolve_url_or_path("./$deno$repl.ts", self.initial_cwd())?
|
||||
resolve_url_or_path("./$deno$repl.mts", self.initial_cwd())?
|
||||
}
|
||||
DenoSubcommand::Run(run_flags) => {
|
||||
if run_flags.is_stdin() {
|
||||
resolve_url_or_path("./$deno$stdin.ts", self.initial_cwd())?
|
||||
resolve_url_or_path("./$deno$stdin.mts", self.initial_cwd())?
|
||||
} else {
|
||||
resolve_url_or_path(&run_flags.script, self.initial_cwd())?
|
||||
let url =
|
||||
resolve_url_or_path(&run_flags.script, self.initial_cwd())?;
|
||||
if self.is_node_main()
|
||||
&& url.scheme() == "file"
|
||||
&& MediaType::from_specifier(&url) == MediaType::Unknown
|
||||
{
|
||||
try_resolve_node_binary_main_entrypoint(
|
||||
&run_flags.script,
|
||||
self.initial_cwd(),
|
||||
)?
|
||||
.unwrap_or(url)
|
||||
} else {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
DenoSubcommand::Serve(run_flags) => {
|
||||
@ -1178,9 +1191,7 @@ impl CliOptions {
|
||||
_ => {
|
||||
bail!("No main module.")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(main_module)
|
||||
})
|
||||
})
|
||||
.as_ref()
|
||||
.map_err(|err| deno_core::anyhow::anyhow!("{}", err))
|
||||
@ -1229,7 +1240,7 @@ impl CliOptions {
|
||||
// This is triggered via a secret environment variable which is used
|
||||
// for functionality like child_process.fork. Users should NOT depend
|
||||
// on this functionality.
|
||||
pub fn is_npm_main(&self) -> bool {
|
||||
pub fn is_node_main(&self) -> bool {
|
||||
NPM_PROCESS_STATE.is_some()
|
||||
}
|
||||
|
||||
@ -1607,9 +1618,11 @@ impl CliOptions {
|
||||
|| self.workspace().has_unstable("bare-node-builtins")
|
||||
}
|
||||
|
||||
pub fn unstable_detect_cjs(&self) -> bool {
|
||||
self.flags.unstable_config.detect_cjs
|
||||
|| self.workspace().has_unstable("detect-cjs")
|
||||
pub fn detect_cjs(&self) -> bool {
|
||||
// only enabled when there's a package.json in order to not have a
|
||||
// perf penalty for non-npm Deno projects of searching for the closest
|
||||
// package.json beside each module
|
||||
self.workspace().package_jsons().next().is_some() || self.is_node_main()
|
||||
}
|
||||
|
||||
fn byonm_enabled(&self) -> bool {
|
||||
@ -1673,7 +1686,6 @@ impl CliOptions {
|
||||
"byonm",
|
||||
"bare-node-builtins",
|
||||
"fmt-component",
|
||||
"detect-cjs",
|
||||
])
|
||||
.collect();
|
||||
|
||||
@ -1811,6 +1823,36 @@ fn resolve_node_modules_folder(
|
||||
Ok(Some(canonicalize_path_maybe_not_exists(&path)?))
|
||||
}
|
||||
|
||||
fn try_resolve_node_binary_main_entrypoint(
|
||||
specifier: &str,
|
||||
initial_cwd: &Path,
|
||||
) -> Result<Option<Url>, AnyError> {
|
||||
// node allows running files at paths without a `.js` extension
|
||||
// or at directories with an index.js file
|
||||
let path = deno_core::normalize_path(initial_cwd.join(specifier));
|
||||
if path.is_dir() {
|
||||
let index_file = path.join("index.js");
|
||||
Ok(if index_file.is_file() {
|
||||
Some(deno_path_util::url_from_file_path(&index_file)?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
} else {
|
||||
let path = path.with_extension(
|
||||
path
|
||||
.extension()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(|s| format!("{}.js", s))
|
||||
.unwrap_or("js".to_string()),
|
||||
);
|
||||
if path.is_file() {
|
||||
Ok(Some(deno_path_util::url_from_file_path(&path)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_import_map_specifier(
|
||||
maybe_import_map_path: Option<&str>,
|
||||
maybe_config_file: Option<&ConfigFile>,
|
||||
|
@ -181,7 +181,6 @@ impl Emitter {
|
||||
pub async fn load_and_emit_for_hmr(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
module_kind: deno_ast::ModuleKind,
|
||||
) -> Result<String, AnyError> {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
let source_code = tokio::fs::read_to_string(
|
||||
@ -203,11 +202,16 @@ impl Emitter {
|
||||
// this statement is probably wrong)
|
||||
let mut options = self.transpile_and_emit_options.1.clone();
|
||||
options.source_map = SourceMapOption::None;
|
||||
let is_cjs = self.cjs_tracker.is_cjs_with_known_is_script(
|
||||
specifier,
|
||||
media_type,
|
||||
parsed_source.compute_is_script(),
|
||||
)?;
|
||||
let transpiled_source = parsed_source
|
||||
.transpile(
|
||||
&self.transpile_and_emit_options.0,
|
||||
&deno_ast::TranspileModuleOptions {
|
||||
module_kind: Some(module_kind),
|
||||
module_kind: Some(ModuleKind::from_is_cjs(is_cjs)),
|
||||
},
|
||||
&options,
|
||||
)?
|
||||
|
@ -42,12 +42,12 @@ use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::CreateInNpmPkgCheckerOptions;
|
||||
use crate::resolver::CjsTracker;
|
||||
use crate::resolver::CjsTrackerOptions;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliGraphResolverOptions;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::CliResolverOptions;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::IsCjsResolverOptions;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::standalone::DenoCompileBinaryWriter;
|
||||
@ -201,7 +201,7 @@ struct CliFactoryServices {
|
||||
parsed_source_cache: Deferred<Arc<ParsedSourceCache>>,
|
||||
permission_desc_parser: Deferred<Arc<RuntimePermissionDescriptorParser>>,
|
||||
pkg_json_resolver: Deferred<Arc<PackageJsonResolver>>,
|
||||
resolver: Deferred<Arc<CliGraphResolver>>,
|
||||
resolver: Deferred<Arc<CliResolver>>,
|
||||
root_cert_store_provider: Deferred<Arc<dyn RootCertStoreProvider>>,
|
||||
root_permissions_container: Deferred<PermissionsContainer>,
|
||||
sloppy_imports_resolver: Deferred<Option<Arc<CliSloppyImportsResolver>>>,
|
||||
@ -523,14 +523,14 @@ impl CliFactory {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn resolver(&self) -> Result<&Arc<CliGraphResolver>, AnyError> {
|
||||
pub async fn resolver(&self) -> Result<&Arc<CliResolver>, AnyError> {
|
||||
self
|
||||
.services
|
||||
.resolver
|
||||
.get_or_try_init_async(
|
||||
async {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
||||
Ok(Arc::new(CliResolver::new(CliResolverOptions {
|
||||
sloppy_imports_resolver: self.sloppy_imports_resolver()?.cloned(),
|
||||
node_resolver: Some(self.cli_node_resolver().await?.clone()),
|
||||
npm_resolver: if cli_options.no_npm() {
|
||||
@ -541,9 +541,6 @@ impl CliFactory {
|
||||
workspace_resolver: self.workspace_resolver().await?.clone(),
|
||||
bare_node_builtins_enabled: cli_options
|
||||
.unstable_bare_node_builtins(),
|
||||
maybe_jsx_import_source_config: cli_options
|
||||
.workspace()
|
||||
.to_maybe_jsx_import_source_config()?,
|
||||
maybe_vendor_dir: cli_options.vendor_dir_path(),
|
||||
})))
|
||||
}
|
||||
@ -652,7 +649,6 @@ impl CliFactory {
|
||||
self.cjs_tracker()?.clone(),
|
||||
self.fs().clone(),
|
||||
Some(self.parsed_source_cache().clone()),
|
||||
self.cli_options()?.is_npm_main(),
|
||||
);
|
||||
|
||||
Ok(Arc::new(NodeCodeTranslator::new(
|
||||
@ -706,6 +702,7 @@ impl CliFactory {
|
||||
let cli_options = self.cli_options()?;
|
||||
Ok(Arc::new(ModuleGraphBuilder::new(
|
||||
self.caches()?.clone(),
|
||||
self.cjs_tracker()?.clone(),
|
||||
cli_options.clone(),
|
||||
self.file_fetcher()?.clone(),
|
||||
self.fs().clone(),
|
||||
@ -794,8 +791,9 @@ impl CliFactory {
|
||||
Ok(Arc::new(CjsTracker::new(
|
||||
self.in_npm_pkg_checker()?.clone(),
|
||||
self.pkg_json_resolver().clone(),
|
||||
CjsTrackerOptions {
|
||||
unstable_detect_cjs: options.unstable_detect_cjs(),
|
||||
IsCjsResolverOptions {
|
||||
detect_cjs: options.detect_cjs(),
|
||||
is_node_main: options.is_node_main(),
|
||||
},
|
||||
)))
|
||||
})
|
||||
@ -809,7 +807,6 @@ impl CliFactory {
|
||||
.cli_node_resolver
|
||||
.get_or_try_init_async(async {
|
||||
Ok(Arc::new(CliNodeResolver::new(
|
||||
self.cjs_tracker()?.clone(),
|
||||
self.fs().clone(),
|
||||
self.in_npm_pkg_checker()?.clone(),
|
||||
self.node_resolver().await?.clone(),
|
||||
@ -950,10 +947,8 @@ impl CliFactory {
|
||||
let create_hmr_runner = if cli_options.has_hmr() {
|
||||
let watcher_communicator = self.watcher_communicator.clone().unwrap();
|
||||
let emitter = self.emitter()?.clone();
|
||||
let cjs_tracker = self.cjs_tracker()?.clone();
|
||||
let fn_: crate::worker::CreateHmrRunnerCb = Box::new(move |session| {
|
||||
Box::new(HmrRunner::new(
|
||||
cjs_tracker.clone(),
|
||||
emitter.clone(),
|
||||
session,
|
||||
watcher_communicator.clone(),
|
||||
|
@ -13,16 +13,19 @@ use crate::colors;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CjsTracker;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::CliSloppyImportsResolver;
|
||||
use crate::resolver::SloppyImportsCachedFs;
|
||||
use crate::tools::check;
|
||||
use crate::tools::check::TypeChecker;
|
||||
use crate::util::file_watcher::WatcherCommunicator;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
use deno_config::deno_json::JsxImportSourceConfig;
|
||||
use deno_config::workspace::JsrPackageConfig;
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_graph::source::LoaderChecksum;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::FillFromLockfileOptions;
|
||||
use deno_graph::JsrLoadError;
|
||||
use deno_graph::ModuleLoadError;
|
||||
@ -379,6 +382,7 @@ pub struct BuildFastCheckGraphOptions<'a> {
|
||||
|
||||
pub struct ModuleGraphBuilder {
|
||||
caches: Arc<cache::Caches>,
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
cli_options: Arc<CliOptions>,
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
fs: Arc<dyn FileSystem>,
|
||||
@ -389,7 +393,7 @@ pub struct ModuleGraphBuilder {
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
}
|
||||
|
||||
@ -397,6 +401,7 @@ impl ModuleGraphBuilder {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
caches: Arc<cache::Caches>,
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
cli_options: Arc<CliOptions>,
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
fs: Arc<dyn FileSystem>,
|
||||
@ -407,11 +412,12 @@ impl ModuleGraphBuilder {
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
) -> Self {
|
||||
Self {
|
||||
caches,
|
||||
cjs_tracker,
|
||||
cli_options,
|
||||
file_fetcher,
|
||||
fs,
|
||||
@ -518,7 +524,7 @@ impl ModuleGraphBuilder {
|
||||
None => MutLoaderRef::Owned(self.create_graph_loader()),
|
||||
};
|
||||
let cli_resolver = &self.resolver;
|
||||
let graph_resolver = cli_resolver.as_graph_resolver();
|
||||
let graph_resolver = self.create_graph_resolver()?;
|
||||
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver();
|
||||
let maybe_file_watcher_reporter = self
|
||||
.maybe_file_watcher_reporter
|
||||
@ -543,7 +549,7 @@ impl ModuleGraphBuilder {
|
||||
npm_resolver: Some(&graph_npm_resolver),
|
||||
module_analyzer: &analyzer,
|
||||
reporter: maybe_file_watcher_reporter,
|
||||
resolver: Some(graph_resolver),
|
||||
resolver: Some(&graph_resolver),
|
||||
locker: locker.as_mut().map(|l| l as _),
|
||||
},
|
||||
)
|
||||
@ -666,7 +672,7 @@ impl ModuleGraphBuilder {
|
||||
};
|
||||
let parser = self.parsed_source_cache.as_capturing_parser();
|
||||
let cli_resolver = &self.resolver;
|
||||
let graph_resolver = cli_resolver.as_graph_resolver();
|
||||
let graph_resolver = self.create_graph_resolver()?;
|
||||
let graph_npm_resolver = cli_resolver.create_graph_npm_resolver();
|
||||
|
||||
graph.build_fast_check_type_graph(
|
||||
@ -675,7 +681,7 @@ impl ModuleGraphBuilder {
|
||||
fast_check_cache: fast_check_cache.as_ref().map(|c| c as _),
|
||||
fast_check_dts: false,
|
||||
jsr_url_provider: &CliJsrUrlProvider,
|
||||
resolver: Some(graph_resolver),
|
||||
resolver: Some(&graph_resolver),
|
||||
npm_resolver: Some(&graph_npm_resolver),
|
||||
workspace_fast_check: options.workspace_fast_check,
|
||||
},
|
||||
@ -739,6 +745,18 @@ impl ModuleGraphBuilder {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn create_graph_resolver(&self) -> Result<CliGraphResolver, AnyError> {
|
||||
let jsx_import_source_config = self
|
||||
.cli_options
|
||||
.workspace()
|
||||
.to_maybe_jsx_import_source_config()?;
|
||||
Ok(CliGraphResolver {
|
||||
cjs_tracker: &self.cjs_tracker,
|
||||
resolver: &self.resolver,
|
||||
jsx_import_source_config,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds more explanatory information to a resolution error.
|
||||
@ -1143,6 +1161,53 @@ fn format_deno_graph_error(err: &dyn Error) -> String {
|
||||
message
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CliGraphResolver<'a> {
|
||||
cjs_tracker: &'a CjsTracker,
|
||||
resolver: &'a CliResolver,
|
||||
jsx_import_source_config: Option<JsxImportSourceConfig>,
|
||||
}
|
||||
|
||||
impl<'a> deno_graph::source::Resolver for CliGraphResolver<'a> {
|
||||
fn default_jsx_import_source(&self) -> Option<String> {
|
||||
self
|
||||
.jsx_import_source_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.default_specifier.clone())
|
||||
}
|
||||
|
||||
fn default_jsx_import_source_types(&self) -> Option<String> {
|
||||
self
|
||||
.jsx_import_source_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.default_types_specifier.clone())
|
||||
}
|
||||
|
||||
fn jsx_import_source_module(&self) -> &str {
|
||||
self
|
||||
.jsx_import_source_config
|
||||
.as_ref()
|
||||
.map(|c| c.module.as_str())
|
||||
.unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer_range: &deno_graph::Range,
|
||||
mode: ResolutionMode,
|
||||
) -> Result<ModuleSpecifier, ResolveError> {
|
||||
self.resolver.resolve(
|
||||
raw_specifier,
|
||||
referrer_range,
|
||||
self
|
||||
.cjs_tracker
|
||||
.get_referrer_kind(&referrer_range.specifier),
|
||||
mode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::Arc;
|
||||
|
@ -39,6 +39,7 @@ use deno_semver::package::PackageReq;
|
||||
use deno_semver::package::PackageReqReference;
|
||||
use deno_semver::Version;
|
||||
use import_map::ImportMap;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::borrow::Cow;
|
||||
@ -467,6 +468,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
) -> Option<String> {
|
||||
let specifier_stem = specifier.strip_suffix(".js").unwrap_or(specifier);
|
||||
let specifiers = std::iter::once(Cow::Borrowed(specifier)).chain(
|
||||
@ -477,7 +479,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
||||
for specifier in specifiers {
|
||||
if let Some(specifier) = self
|
||||
.resolver
|
||||
.as_graph_resolver(Some(&self.file_referrer))
|
||||
.as_cli_resolver(Some(&self.file_referrer))
|
||||
.resolve(
|
||||
&specifier,
|
||||
&deno_graph::Range {
|
||||
@ -485,6 +487,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
referrer_kind,
|
||||
ResolutionMode::Types,
|
||||
)
|
||||
.ok()
|
||||
@ -507,10 +510,11 @@ impl<'a> TsResponseImportMapper<'a> {
|
||||
&self,
|
||||
specifier_text: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
) -> bool {
|
||||
self
|
||||
.resolver
|
||||
.as_graph_resolver(Some(&self.file_referrer))
|
||||
.as_cli_resolver(Some(&self.file_referrer))
|
||||
.resolve(
|
||||
specifier_text,
|
||||
&deno_graph::Range {
|
||||
@ -518,6 +522,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
referrer_kind,
|
||||
deno_graph::source::ResolutionMode::Types,
|
||||
)
|
||||
.is_ok()
|
||||
@ -586,6 +591,7 @@ fn try_reverse_map_package_json_exports(
|
||||
/// like an import and rewrite the import specifier to include the extension
|
||||
pub fn fix_ts_import_changes(
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
changes: &[tsc::FileTextChanges],
|
||||
language_server: &language_server::Inner,
|
||||
) -> Result<Vec<tsc::FileTextChanges>, AnyError> {
|
||||
@ -602,8 +608,8 @@ pub fn fix_ts_import_changes(
|
||||
if let Some(captures) = IMPORT_SPECIFIER_RE.captures(line) {
|
||||
let specifier =
|
||||
captures.iter().skip(1).find_map(|s| s).unwrap().as_str();
|
||||
if let Some(new_specifier) =
|
||||
import_mapper.check_unresolved_specifier(specifier, referrer)
|
||||
if let Some(new_specifier) = import_mapper
|
||||
.check_unresolved_specifier(specifier, referrer, referrer_kind)
|
||||
{
|
||||
line.replace(specifier, &new_specifier)
|
||||
} else {
|
||||
@ -633,6 +639,7 @@ pub fn fix_ts_import_changes(
|
||||
/// resolution by Deno (includes the extension).
|
||||
fn fix_ts_import_action<'a>(
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
action: &'a tsc::CodeFixAction,
|
||||
language_server: &language_server::Inner,
|
||||
) -> Option<Cow<'a, tsc::CodeFixAction>> {
|
||||
@ -652,7 +659,7 @@ fn fix_ts_import_action<'a>(
|
||||
};
|
||||
let import_mapper = language_server.get_ts_response_import_mapper(referrer);
|
||||
if let Some(new_specifier) =
|
||||
import_mapper.check_unresolved_specifier(specifier, referrer)
|
||||
import_mapper.check_unresolved_specifier(specifier, referrer, referrer_kind)
|
||||
{
|
||||
let description = action.description.replace(specifier, &new_specifier);
|
||||
let changes = action
|
||||
@ -683,7 +690,7 @@ fn fix_ts_import_action<'a>(
|
||||
fix_id: None,
|
||||
fix_all_description: None,
|
||||
}))
|
||||
} else if !import_mapper.is_valid_import(specifier, referrer) {
|
||||
} else if !import_mapper.is_valid_import(specifier, referrer, referrer_kind) {
|
||||
None
|
||||
} else {
|
||||
Some(Cow::Borrowed(action))
|
||||
@ -1017,6 +1024,7 @@ impl CodeActionCollection {
|
||||
pub fn add_ts_fix_action(
|
||||
&mut self,
|
||||
specifier: &ModuleSpecifier,
|
||||
specifier_kind: NodeModuleKind,
|
||||
action: &tsc::CodeFixAction,
|
||||
diagnostic: &lsp::Diagnostic,
|
||||
language_server: &language_server::Inner,
|
||||
@ -1034,7 +1042,8 @@ impl CodeActionCollection {
|
||||
"The action returned from TypeScript is unsupported.",
|
||||
));
|
||||
}
|
||||
let Some(action) = fix_ts_import_action(specifier, action, language_server)
|
||||
let Some(action) =
|
||||
fix_ts_import_action(specifier, specifier_kind, action, language_server)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
@ -1276,6 +1285,9 @@ impl CodeActionCollection {
|
||||
import_start_from_specifier(document, i)
|
||||
})?;
|
||||
let referrer = document.specifier();
|
||||
let referrer_kind = language_server
|
||||
.is_cjs_resolver
|
||||
.get_doc_module_kind(document);
|
||||
let file_referrer = document.file_referrer();
|
||||
let config_data = language_server
|
||||
.config
|
||||
@ -1298,10 +1310,11 @@ impl CodeActionCollection {
|
||||
if !config_data.byonm {
|
||||
return None;
|
||||
}
|
||||
if !language_server
|
||||
.resolver
|
||||
.is_bare_package_json_dep(&dep_key, referrer)
|
||||
{
|
||||
if !language_server.resolver.is_bare_package_json_dep(
|
||||
&dep_key,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
NpmPackageReqReference::from_str(&format!("npm:{}", &dep_key)).ok()?
|
||||
@ -1320,7 +1333,7 @@ impl CodeActionCollection {
|
||||
}
|
||||
if language_server
|
||||
.resolver
|
||||
.npm_to_file_url(&npm_ref, document.specifier(), file_referrer)
|
||||
.npm_to_file_url(&npm_ref, referrer, referrer_kind, file_referrer)
|
||||
.is_some()
|
||||
{
|
||||
// The package import has types.
|
||||
|
@ -9,6 +9,7 @@ use super::jsr::CliJsrSearchApi;
|
||||
use super::lsp_custom;
|
||||
use super::npm::CliNpmSearchApi;
|
||||
use super::registries::ModuleRegistry;
|
||||
use super::resolver::LspIsCjsResolver;
|
||||
use super::resolver::LspResolver;
|
||||
use super::search::PackageSearchApi;
|
||||
use super::tsc;
|
||||
@ -35,6 +36,7 @@ use deno_semver::package::PackageNv;
|
||||
use import_map::ImportMap;
|
||||
use indexmap::IndexSet;
|
||||
use lsp_types::CompletionList;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use tower_lsp::lsp_types as lsp;
|
||||
@ -159,15 +161,17 @@ pub async fn get_import_completions(
|
||||
jsr_search_api: &CliJsrSearchApi,
|
||||
npm_search_api: &CliNpmSearchApi,
|
||||
documents: &Documents,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: &LspResolver,
|
||||
maybe_import_map: Option<&ImportMap>,
|
||||
) -> Option<lsp::CompletionResponse> {
|
||||
let document = documents.get(specifier)?;
|
||||
let specifier_kind = is_cjs_resolver.get_doc_module_kind(&document);
|
||||
let file_referrer = document.file_referrer();
|
||||
let (text, _, range) = document.get_maybe_dependency(position)?;
|
||||
let range = to_narrow_lsp_range(document.text_info(), &range);
|
||||
let resolved = resolver
|
||||
.as_graph_resolver(file_referrer)
|
||||
.as_cli_resolver(file_referrer)
|
||||
.resolve(
|
||||
&text,
|
||||
&Range {
|
||||
@ -175,6 +179,7 @@ pub async fn get_import_completions(
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
specifier_kind,
|
||||
ResolutionMode::Execution,
|
||||
)
|
||||
.ok();
|
||||
@ -201,7 +206,7 @@ pub async fn get_import_completions(
|
||||
// completions for import map specifiers
|
||||
Some(lsp::CompletionResponse::List(completion_list))
|
||||
} else if let Some(completion_list) =
|
||||
get_local_completions(specifier, &text, &range, resolver)
|
||||
get_local_completions(specifier, specifier_kind, &text, &range, resolver)
|
||||
{
|
||||
// completions for local relative modules
|
||||
Some(lsp::CompletionResponse::List(completion_list))
|
||||
@ -355,24 +360,26 @@ fn get_import_map_completions(
|
||||
|
||||
/// Return local completions that are relative to the base specifier.
|
||||
fn get_local_completions(
|
||||
base: &ModuleSpecifier,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
text: &str,
|
||||
range: &lsp::Range,
|
||||
resolver: &LspResolver,
|
||||
) -> Option<CompletionList> {
|
||||
if base.scheme() != "file" {
|
||||
if referrer.scheme() != "file" {
|
||||
return None;
|
||||
}
|
||||
let parent = &text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1];
|
||||
let resolved_parent = resolver
|
||||
.as_graph_resolver(Some(base))
|
||||
.as_cli_resolver(Some(referrer))
|
||||
.resolve(
|
||||
parent,
|
||||
&Range {
|
||||
specifier: base.clone(),
|
||||
specifier: referrer.clone(),
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
referrer_kind,
|
||||
ResolutionMode::Execution,
|
||||
)
|
||||
.ok()?;
|
||||
@ -385,7 +392,7 @@ fn get_local_completions(
|
||||
let de = de.ok()?;
|
||||
let label = de.path().file_name()?.to_string_lossy().to_string();
|
||||
let entry_specifier = resolve_path(de.path().to_str()?, &cwd).ok()?;
|
||||
if entry_specifier == *base {
|
||||
if entry_specifier == *referrer {
|
||||
return None;
|
||||
}
|
||||
let full_text = format!("{parent}{label}");
|
||||
@ -905,6 +912,7 @@ mod tests {
|
||||
ModuleSpecifier::from_file_path(file_c).expect("could not create");
|
||||
let actual = get_local_completions(
|
||||
&specifier,
|
||||
NodeModuleKind::Esm,
|
||||
"./",
|
||||
&lsp::Range {
|
||||
start: lsp::Position {
|
||||
|
@ -4,6 +4,7 @@ use deno_ast::MediaType;
|
||||
use deno_config::deno_json::DenoJsonCache;
|
||||
use deno_config::deno_json::FmtConfig;
|
||||
use deno_config::deno_json::FmtOptionsConfig;
|
||||
use deno_config::deno_json::JsxImportSourceConfig;
|
||||
use deno_config::deno_json::LintConfig;
|
||||
use deno_config::deno_json::NodeModulesDirMode;
|
||||
use deno_config::deno_json::TestConfig;
|
||||
@ -1654,6 +1655,17 @@ impl ConfigData {
|
||||
self.member_dir.maybe_pkg_json()
|
||||
}
|
||||
|
||||
pub fn maybe_jsx_import_source_config(
|
||||
&self,
|
||||
) -> Option<JsxImportSourceConfig> {
|
||||
self
|
||||
.member_dir
|
||||
.workspace
|
||||
.to_maybe_jsx_import_source_config()
|
||||
.ok()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn scope_contains_specifier(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
specifier.as_str().starts_with(self.scope.as_str())
|
||||
|| self
|
||||
|
@ -1707,6 +1707,7 @@ mod tests {
|
||||
documents: Arc::new(documents),
|
||||
assets: Default::default(),
|
||||
config: Arc::new(config),
|
||||
is_cjs_resolver: Default::default(),
|
||||
resolver,
|
||||
},
|
||||
)
|
||||
|
@ -3,7 +3,9 @@
|
||||
use super::cache::calculate_fs_version;
|
||||
use super::cache::LspCache;
|
||||
use super::config::Config;
|
||||
use super::resolver::LspIsCjsResolver;
|
||||
use super::resolver::LspResolver;
|
||||
use super::resolver::SingleReferrerGraphResolver;
|
||||
use super::testing::TestCollector;
|
||||
use super::testing::TestModule;
|
||||
use super::text::LineIndex;
|
||||
@ -33,6 +35,7 @@ use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
@ -293,6 +296,8 @@ pub struct Document {
|
||||
/// Contains the last-known-good set of dependencies from parsing the module.
|
||||
config: Arc<Config>,
|
||||
dependencies: Arc<IndexMap<String, deno_graph::Dependency>>,
|
||||
/// If this is maybe a CJS script and maybe not an ES module.
|
||||
is_script: Option<bool>,
|
||||
// TODO(nayeemrmn): This is unused, use it for scope attribution for remote
|
||||
// modules.
|
||||
file_referrer: Option<ModuleSpecifier>,
|
||||
@ -323,6 +328,7 @@ impl Document {
|
||||
maybe_lsp_version: Option<i32>,
|
||||
maybe_language_id: Option<LanguageId>,
|
||||
maybe_headers: Option<HashMap<String, String>>,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: Arc<LspResolver>,
|
||||
config: Arc<Config>,
|
||||
cache: &Arc<LspCache>,
|
||||
@ -342,6 +348,7 @@ impl Document {
|
||||
maybe_headers.as_ref(),
|
||||
media_type,
|
||||
file_referrer.as_ref(),
|
||||
is_cjs_resolver,
|
||||
&resolver,
|
||||
)
|
||||
} else {
|
||||
@ -367,6 +374,7 @@ impl Document {
|
||||
file_referrer.as_ref(),
|
||||
),
|
||||
file_referrer,
|
||||
is_script: maybe_module.as_ref().map(|m| m.is_script),
|
||||
maybe_types_dependency,
|
||||
line_index,
|
||||
maybe_language_id,
|
||||
@ -388,6 +396,7 @@ impl Document {
|
||||
|
||||
fn with_new_config(
|
||||
&self,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: Arc<LspResolver>,
|
||||
config: Arc<Config>,
|
||||
) -> Arc<Self> {
|
||||
@ -399,6 +408,7 @@ impl Document {
|
||||
let dependencies;
|
||||
let maybe_types_dependency;
|
||||
let maybe_parsed_source;
|
||||
let is_script;
|
||||
let maybe_test_module_fut;
|
||||
if media_type != self.media_type {
|
||||
let parsed_source_result =
|
||||
@ -408,6 +418,7 @@ impl Document {
|
||||
&parsed_source_result,
|
||||
self.maybe_headers.as_ref(),
|
||||
self.file_referrer.as_ref(),
|
||||
is_cjs_resolver,
|
||||
&resolver,
|
||||
)
|
||||
.ok();
|
||||
@ -415,6 +426,7 @@ impl Document {
|
||||
.as_ref()
|
||||
.map(|m| Arc::new(m.dependencies.clone()))
|
||||
.unwrap_or_default();
|
||||
is_script = maybe_module.as_ref().map(|m| m.is_script);
|
||||
maybe_types_dependency = maybe_module
|
||||
.as_ref()
|
||||
.and_then(|m| Some(Arc::new(m.maybe_types_dependency.clone()?)));
|
||||
@ -422,10 +434,19 @@ impl Document {
|
||||
maybe_test_module_fut =
|
||||
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &config);
|
||||
} else {
|
||||
let graph_resolver =
|
||||
resolver.as_graph_resolver(self.file_referrer.as_ref());
|
||||
let cli_resolver = resolver.as_cli_resolver(self.file_referrer.as_ref());
|
||||
let npm_resolver =
|
||||
resolver.create_graph_npm_resolver(self.file_referrer.as_ref());
|
||||
let config_data = resolver.as_config_data(self.file_referrer.as_ref());
|
||||
let jsx_import_source_config =
|
||||
config_data.and_then(|d| d.maybe_jsx_import_source_config());
|
||||
let resolver = SingleReferrerGraphResolver {
|
||||
valid_referrer: &self.specifier,
|
||||
referrer_kind: is_cjs_resolver
|
||||
.get_lsp_referrer_kind(&self.specifier, self.is_script),
|
||||
cli_resolver,
|
||||
jsx_import_source_config: jsx_import_source_config.as_ref(),
|
||||
};
|
||||
dependencies = Arc::new(
|
||||
self
|
||||
.dependencies
|
||||
@ -436,7 +457,7 @@ impl Document {
|
||||
d.with_new_resolver(
|
||||
s,
|
||||
&CliJsrUrlProvider,
|
||||
Some(graph_resolver),
|
||||
Some(&resolver),
|
||||
Some(&npm_resolver),
|
||||
),
|
||||
)
|
||||
@ -446,10 +467,11 @@ impl Document {
|
||||
maybe_types_dependency = self.maybe_types_dependency.as_ref().map(|d| {
|
||||
Arc::new(d.with_new_resolver(
|
||||
&CliJsrUrlProvider,
|
||||
Some(graph_resolver),
|
||||
Some(&resolver),
|
||||
Some(&npm_resolver),
|
||||
))
|
||||
});
|
||||
is_script = self.is_script;
|
||||
maybe_parsed_source = self.maybe_parsed_source().cloned();
|
||||
maybe_test_module_fut = self
|
||||
.maybe_test_module_fut
|
||||
@ -461,6 +483,7 @@ impl Document {
|
||||
// updated properties
|
||||
dependencies,
|
||||
file_referrer: self.file_referrer.clone(),
|
||||
is_script,
|
||||
maybe_types_dependency,
|
||||
maybe_navigation_tree: Mutex::new(None),
|
||||
// maintain - this should all be copies/clones
|
||||
@ -485,6 +508,7 @@ impl Document {
|
||||
|
||||
fn with_change(
|
||||
&self,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
version: i32,
|
||||
changes: Vec<lsp::TextDocumentContentChangeEvent>,
|
||||
) -> Result<Arc<Self>, AnyError> {
|
||||
@ -518,6 +542,7 @@ impl Document {
|
||||
self.maybe_headers.as_ref(),
|
||||
media_type,
|
||||
self.file_referrer.as_ref(),
|
||||
is_cjs_resolver,
|
||||
self.resolver.as_ref(),
|
||||
)
|
||||
} else {
|
||||
@ -541,6 +566,7 @@ impl Document {
|
||||
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &self.config);
|
||||
Ok(Arc::new(Self {
|
||||
config: self.config.clone(),
|
||||
is_script: maybe_module.as_ref().map(|m| m.is_script),
|
||||
specifier: self.specifier.clone(),
|
||||
file_referrer: self.file_referrer.clone(),
|
||||
maybe_fs_version: self.maybe_fs_version.clone(),
|
||||
@ -575,6 +601,7 @@ impl Document {
|
||||
),
|
||||
maybe_language_id: self.maybe_language_id,
|
||||
dependencies: self.dependencies.clone(),
|
||||
is_script: self.is_script,
|
||||
maybe_types_dependency: self.maybe_types_dependency.clone(),
|
||||
text: self.text.clone(),
|
||||
text_info_cell: once_cell::sync::OnceCell::new(),
|
||||
@ -602,6 +629,7 @@ impl Document {
|
||||
),
|
||||
maybe_language_id: self.maybe_language_id,
|
||||
dependencies: self.dependencies.clone(),
|
||||
is_script: self.is_script,
|
||||
maybe_types_dependency: self.maybe_types_dependency.clone(),
|
||||
text: self.text.clone(),
|
||||
text_info_cell: once_cell::sync::OnceCell::new(),
|
||||
@ -650,6 +678,13 @@ impl Document {
|
||||
})
|
||||
}
|
||||
|
||||
/// If this is maybe a CJS script and maybe not an ES module.
|
||||
///
|
||||
/// Use `LspIsCjsResolver` to determine for sure.
|
||||
pub fn is_script(&self) -> Option<bool> {
|
||||
self.is_script
|
||||
}
|
||||
|
||||
pub fn line_index(&self) -> Arc<LineIndex> {
|
||||
self.line_index.clone()
|
||||
}
|
||||
@ -797,6 +832,7 @@ impl FileSystemDocuments {
|
||||
pub fn get(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: &Arc<LspResolver>,
|
||||
config: &Arc<Config>,
|
||||
cache: &Arc<LspCache>,
|
||||
@ -820,7 +856,14 @@ impl FileSystemDocuments {
|
||||
};
|
||||
if dirty {
|
||||
// attempt to update the file on the file system
|
||||
self.refresh_document(specifier, resolver, config, cache, file_referrer)
|
||||
self.refresh_document(
|
||||
specifier,
|
||||
is_cjs_resolver,
|
||||
resolver,
|
||||
config,
|
||||
cache,
|
||||
file_referrer,
|
||||
)
|
||||
} else {
|
||||
old_doc
|
||||
}
|
||||
@ -831,6 +874,7 @@ impl FileSystemDocuments {
|
||||
fn refresh_document(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: &Arc<LspResolver>,
|
||||
config: &Arc<Config>,
|
||||
cache: &Arc<LspCache>,
|
||||
@ -847,6 +891,7 @@ impl FileSystemDocuments {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
is_cjs_resolver,
|
||||
resolver.clone(),
|
||||
config.clone(),
|
||||
cache,
|
||||
@ -863,6 +908,7 @@ impl FileSystemDocuments {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
is_cjs_resolver,
|
||||
resolver.clone(),
|
||||
config.clone(),
|
||||
cache,
|
||||
@ -890,6 +936,7 @@ impl FileSystemDocuments {
|
||||
None,
|
||||
None,
|
||||
maybe_headers,
|
||||
is_cjs_resolver,
|
||||
resolver.clone(),
|
||||
config.clone(),
|
||||
cache,
|
||||
@ -930,6 +977,11 @@ pub struct Documents {
|
||||
/// The DENO_DIR that the documents looks for non-file based modules.
|
||||
cache: Arc<LspCache>,
|
||||
config: Arc<Config>,
|
||||
/// Resolver for detecting if a document is CJS or ESM.
|
||||
is_cjs_resolver: Arc<LspIsCjsResolver>,
|
||||
/// A resolver that takes into account currently loaded import map and JSX
|
||||
/// settings.
|
||||
resolver: Arc<LspResolver>,
|
||||
/// A flag that indicates that stated data is potentially invalid and needs to
|
||||
/// be recalculated before being considered valid.
|
||||
dirty: bool,
|
||||
@ -937,9 +989,6 @@ pub struct Documents {
|
||||
open_docs: HashMap<ModuleSpecifier, Arc<Document>>,
|
||||
/// Documents stored on the file system.
|
||||
file_system_docs: Arc<FileSystemDocuments>,
|
||||
/// A resolver that takes into account currently loaded import map and JSX
|
||||
/// settings.
|
||||
resolver: Arc<LspResolver>,
|
||||
/// The npm package requirements found in npm specifiers.
|
||||
npm_reqs_by_scope:
|
||||
Arc<BTreeMap<Option<ModuleSpecifier>, BTreeSet<PackageReq>>>,
|
||||
@ -970,6 +1019,7 @@ impl Documents {
|
||||
// the cache for remote modules here in order to get the
|
||||
// x-typescript-types?
|
||||
None,
|
||||
&self.is_cjs_resolver,
|
||||
self.resolver.clone(),
|
||||
self.config.clone(),
|
||||
&self.cache,
|
||||
@ -1004,7 +1054,7 @@ impl Documents {
|
||||
))
|
||||
})?;
|
||||
self.dirty = true;
|
||||
let doc = doc.with_change(version, changes)?;
|
||||
let doc = doc.with_change(&self.is_cjs_resolver, version, changes)?;
|
||||
self.open_docs.insert(doc.specifier().clone(), doc.clone());
|
||||
Ok(doc)
|
||||
}
|
||||
@ -1133,6 +1183,7 @@ impl Documents {
|
||||
if let Some(old_doc) = old_doc {
|
||||
self.file_system_docs.get(
|
||||
specifier,
|
||||
&self.is_cjs_resolver,
|
||||
&self.resolver,
|
||||
&self.config,
|
||||
&self.cache,
|
||||
@ -1157,6 +1208,7 @@ impl Documents {
|
||||
} else {
|
||||
self.file_system_docs.get(
|
||||
&specifier,
|
||||
&self.is_cjs_resolver,
|
||||
&self.resolver,
|
||||
&self.config,
|
||||
&self.cache,
|
||||
@ -1215,12 +1267,15 @@ impl Documents {
|
||||
referrer: &ModuleSpecifier,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
|
||||
let document = self.get(referrer);
|
||||
let file_referrer = document
|
||||
let referrer_doc = self.get(referrer);
|
||||
let file_referrer = referrer_doc
|
||||
.as_ref()
|
||||
.and_then(|d| d.file_referrer())
|
||||
.or(file_referrer);
|
||||
let dependencies = document.as_ref().map(|d| d.dependencies());
|
||||
let dependencies = referrer_doc.as_ref().map(|d| d.dependencies());
|
||||
let referrer_kind = self
|
||||
.is_cjs_resolver
|
||||
.get_maybe_doc_module_kind(referrer, referrer_doc.as_deref());
|
||||
let mut results = Vec::new();
|
||||
for raw_specifier in raw_specifiers {
|
||||
if raw_specifier.starts_with("asset:") {
|
||||
@ -1237,31 +1292,35 @@ impl Documents {
|
||||
results.push(self.resolve_dependency(
|
||||
specifier,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
file_referrer,
|
||||
));
|
||||
} else if let Some(specifier) = dep.maybe_code.maybe_specifier() {
|
||||
results.push(self.resolve_dependency(
|
||||
specifier,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
file_referrer,
|
||||
));
|
||||
} else {
|
||||
results.push(None);
|
||||
}
|
||||
} else if let Ok(specifier) =
|
||||
self.resolver.as_graph_resolver(file_referrer).resolve(
|
||||
self.resolver.as_cli_resolver(file_referrer).resolve(
|
||||
raw_specifier,
|
||||
&deno_graph::Range {
|
||||
specifier: referrer.clone(),
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
referrer_kind,
|
||||
ResolutionMode::Types,
|
||||
)
|
||||
{
|
||||
results.push(self.resolve_dependency(
|
||||
&specifier,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
file_referrer,
|
||||
));
|
||||
} else {
|
||||
@ -1280,7 +1339,11 @@ impl Documents {
|
||||
) {
|
||||
self.config = Arc::new(config.clone());
|
||||
self.cache = Arc::new(cache.clone());
|
||||
self.is_cjs_resolver = Arc::new(LspIsCjsResolver::new(cache));
|
||||
self.resolver = resolver.clone();
|
||||
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
|
||||
{
|
||||
let fs_docs = &self.file_system_docs;
|
||||
// Clean up non-existent documents.
|
||||
@ -1300,14 +1363,21 @@ impl Documents {
|
||||
if !config.specifier_enabled(doc.specifier()) {
|
||||
continue;
|
||||
}
|
||||
*doc = doc.with_new_config(self.resolver.clone(), self.config.clone());
|
||||
*doc = doc.with_new_config(
|
||||
&self.is_cjs_resolver,
|
||||
self.resolver.clone(),
|
||||
self.config.clone(),
|
||||
);
|
||||
}
|
||||
for mut doc in self.file_system_docs.docs.iter_mut() {
|
||||
if !config.specifier_enabled(doc.specifier()) {
|
||||
continue;
|
||||
}
|
||||
*doc.value_mut() =
|
||||
doc.with_new_config(self.resolver.clone(), self.config.clone());
|
||||
*doc.value_mut() = doc.with_new_config(
|
||||
&self.is_cjs_resolver,
|
||||
self.resolver.clone(),
|
||||
self.config.clone(),
|
||||
);
|
||||
}
|
||||
self.open_docs = open_docs;
|
||||
let mut preload_count = 0;
|
||||
@ -1324,6 +1394,7 @@ impl Documents {
|
||||
{
|
||||
fs_docs.refresh_document(
|
||||
specifier,
|
||||
&self.is_cjs_resolver,
|
||||
&self.resolver,
|
||||
&self.config,
|
||||
&self.cache,
|
||||
@ -1409,6 +1480,7 @@ impl Documents {
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Option<(ModuleSpecifier, MediaType)> {
|
||||
if let Some(module_name) = specifier.as_str().strip_prefix("node:") {
|
||||
@ -1422,10 +1494,12 @@ impl Documents {
|
||||
let mut specifier = specifier.clone();
|
||||
let mut media_type = None;
|
||||
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&specifier) {
|
||||
let (s, mt) =
|
||||
self
|
||||
.resolver
|
||||
.npm_to_file_url(&npm_ref, referrer, file_referrer)?;
|
||||
let (s, mt) = self.resolver.npm_to_file_url(
|
||||
&npm_ref,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
file_referrer,
|
||||
)?;
|
||||
specifier = s;
|
||||
media_type = Some(mt);
|
||||
}
|
||||
@ -1435,7 +1509,8 @@ impl Documents {
|
||||
return Some((specifier, media_type));
|
||||
};
|
||||
if let Some(types) = doc.maybe_types_dependency().maybe_specifier() {
|
||||
self.resolve_dependency(types, &specifier, file_referrer)
|
||||
let specifier_kind = self.is_cjs_resolver.get_doc_module_kind(&doc);
|
||||
self.resolve_dependency(types, &specifier, specifier_kind, file_referrer)
|
||||
} else {
|
||||
Some((doc.specifier().clone(), doc.media_type()))
|
||||
}
|
||||
@ -1503,6 +1578,7 @@ fn parse_and_analyze_module(
|
||||
maybe_headers: Option<&HashMap<String, String>>,
|
||||
media_type: MediaType,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: &LspResolver,
|
||||
) -> (Option<ParsedSourceResult>, Option<ModuleResult>) {
|
||||
let parsed_source_result = parse_source(specifier.clone(), text, media_type);
|
||||
@ -1511,6 +1587,7 @@ fn parse_and_analyze_module(
|
||||
&parsed_source_result,
|
||||
maybe_headers,
|
||||
file_referrer,
|
||||
is_cjs_resolver,
|
||||
resolver,
|
||||
);
|
||||
(Some(parsed_source_result), Some(module_result))
|
||||
@ -1536,11 +1613,26 @@ fn analyze_module(
|
||||
parsed_source_result: &ParsedSourceResult,
|
||||
maybe_headers: Option<&HashMap<String, String>>,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
is_cjs_resolver: &LspIsCjsResolver,
|
||||
resolver: &LspResolver,
|
||||
) -> ModuleResult {
|
||||
match parsed_source_result {
|
||||
Ok(parsed_source) => {
|
||||
let npm_resolver = resolver.create_graph_npm_resolver(file_referrer);
|
||||
let cli_resolver = resolver.as_cli_resolver(file_referrer);
|
||||
let config_data = resolver.as_config_data(file_referrer);
|
||||
let valid_referrer = specifier.clone();
|
||||
let jsx_import_source_config =
|
||||
config_data.and_then(|d| d.maybe_jsx_import_source_config());
|
||||
let resolver = SingleReferrerGraphResolver {
|
||||
valid_referrer: &valid_referrer,
|
||||
referrer_kind: is_cjs_resolver.get_lsp_referrer_kind(
|
||||
&specifier,
|
||||
Some(parsed_source.compute_is_script()),
|
||||
),
|
||||
cli_resolver,
|
||||
jsx_import_source_config: jsx_import_source_config.as_ref(),
|
||||
};
|
||||
Ok(deno_graph::parse_module_from_ast(
|
||||
deno_graph::ParseModuleFromAstOptions {
|
||||
graph_kind: deno_graph::GraphKind::TypesOnly,
|
||||
@ -1551,7 +1643,7 @@ fn analyze_module(
|
||||
// dynamic imports like import(`./dir/${something}`) in the LSP
|
||||
file_system: &deno_graph::source::NullFileSystem,
|
||||
jsr_url_provider: &CliJsrUrlProvider,
|
||||
maybe_resolver: Some(resolver.as_graph_resolver(file_referrer)),
|
||||
maybe_resolver: Some(&resolver),
|
||||
maybe_npm_resolver: Some(&npm_resolver),
|
||||
},
|
||||
))
|
||||
|
@ -22,6 +22,7 @@ use deno_semver::jsr::JsrPackageReqReference;
|
||||
use indexmap::Equivalent;
|
||||
use indexmap::IndexSet;
|
||||
use log::error;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use serde::Deserialize;
|
||||
use serde_json::from_value;
|
||||
use std::collections::BTreeMap;
|
||||
@ -77,6 +78,7 @@ use super::parent_process_checker;
|
||||
use super::performance::Performance;
|
||||
use super::refactor;
|
||||
use super::registries::ModuleRegistry;
|
||||
use super::resolver::LspIsCjsResolver;
|
||||
use super::resolver::LspResolver;
|
||||
use super::testing;
|
||||
use super::text;
|
||||
@ -144,6 +146,7 @@ pub struct StateSnapshot {
|
||||
pub project_version: usize,
|
||||
pub assets: AssetsSnapshot,
|
||||
pub config: Arc<Config>,
|
||||
pub is_cjs_resolver: Arc<LspIsCjsResolver>,
|
||||
pub documents: Arc<Documents>,
|
||||
pub resolver: Arc<LspResolver>,
|
||||
}
|
||||
@ -203,6 +206,7 @@ pub struct Inner {
|
||||
pub documents: Documents,
|
||||
http_client_provider: Arc<HttpClientProvider>,
|
||||
initial_cwd: PathBuf,
|
||||
pub is_cjs_resolver: Arc<LspIsCjsResolver>,
|
||||
jsr_search_api: CliJsrSearchApi,
|
||||
/// Handles module registries, which allow discovery of modules
|
||||
module_registry: ModuleRegistry,
|
||||
@ -480,6 +484,7 @@ impl Inner {
|
||||
let initial_cwd = std::env::current_dir().unwrap_or_else(|_| {
|
||||
panic!("Could not resolve current working directory")
|
||||
});
|
||||
let is_cjs_resolver = Arc::new(LspIsCjsResolver::new(&cache));
|
||||
|
||||
Self {
|
||||
assets,
|
||||
@ -491,6 +496,7 @@ impl Inner {
|
||||
documents,
|
||||
http_client_provider,
|
||||
initial_cwd: initial_cwd.clone(),
|
||||
is_cjs_resolver,
|
||||
jsr_search_api,
|
||||
project_version: 0,
|
||||
task_queue: Default::default(),
|
||||
@ -601,6 +607,7 @@ impl Inner {
|
||||
project_version: self.project_version,
|
||||
assets: self.assets.snapshot(),
|
||||
config: Arc::new(self.config.clone()),
|
||||
is_cjs_resolver: self.is_cjs_resolver.clone(),
|
||||
documents: Arc::new(self.documents.clone()),
|
||||
resolver: self.resolver.snapshot(),
|
||||
})
|
||||
@ -622,6 +629,7 @@ impl Inner {
|
||||
}
|
||||
});
|
||||
self.cache = LspCache::new(global_cache_url);
|
||||
self.is_cjs_resolver = Arc::new(LspIsCjsResolver::new(&self.cache));
|
||||
let deno_dir = self.cache.deno_dir();
|
||||
let workspace_settings = self.config.workspace_settings();
|
||||
let maybe_root_path = self
|
||||
@ -982,7 +990,7 @@ impl Inner {
|
||||
spawn(async move {
|
||||
let specifier = {
|
||||
let inner = ls.inner.read().await;
|
||||
let resolver = inner.resolver.as_graph_resolver(Some(&referrer));
|
||||
let resolver = inner.resolver.as_cli_resolver(Some(&referrer));
|
||||
let Ok(specifier) = resolver.resolve(
|
||||
&specifier,
|
||||
&deno_graph::Range {
|
||||
@ -990,6 +998,7 @@ impl Inner {
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
NodeModuleKind::Esm,
|
||||
deno_graph::source::ResolutionMode::Types,
|
||||
) else {
|
||||
return;
|
||||
@ -1622,6 +1631,10 @@ impl Inner {
|
||||
let file_diagnostics = self
|
||||
.diagnostics_server
|
||||
.get_ts_diagnostics(&specifier, asset_or_doc.document_lsp_version());
|
||||
let specifier_kind = asset_or_doc
|
||||
.document()
|
||||
.map(|d| self.is_cjs_resolver.get_doc_module_kind(d))
|
||||
.unwrap_or(NodeModuleKind::Esm);
|
||||
let mut includes_no_cache = false;
|
||||
for diagnostic in &fixable_diagnostics {
|
||||
match diagnostic.source.as_deref() {
|
||||
@ -1660,7 +1673,13 @@ impl Inner {
|
||||
.await;
|
||||
for action in actions {
|
||||
code_actions
|
||||
.add_ts_fix_action(&specifier, &action, diagnostic, self)
|
||||
.add_ts_fix_action(
|
||||
&specifier,
|
||||
specifier_kind,
|
||||
&action,
|
||||
diagnostic,
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
error!("Unable to convert fix: {:#}", err);
|
||||
LspError::internal_error()
|
||||
@ -1806,10 +1825,9 @@ impl Inner {
|
||||
error!("Unable to decode code action data: {:#}", err);
|
||||
LspError::invalid_params("The CodeAction's data is invalid.")
|
||||
})?;
|
||||
let scope = self
|
||||
.get_asset_or_document(&code_action_data.specifier)
|
||||
.ok()
|
||||
.and_then(|d| d.scope().cloned());
|
||||
let maybe_asset_or_doc =
|
||||
self.get_asset_or_document(&code_action_data.specifier).ok();
|
||||
let scope = maybe_asset_or_doc.as_ref().and_then(|d| d.scope().cloned());
|
||||
let combined_code_actions = self
|
||||
.ts_server
|
||||
.get_combined_code_fix(
|
||||
@ -1836,6 +1854,11 @@ impl Inner {
|
||||
let changes = if code_action_data.fix_id == "fixMissingImport" {
|
||||
fix_ts_import_changes(
|
||||
&code_action_data.specifier,
|
||||
maybe_asset_or_doc
|
||||
.as_ref()
|
||||
.and_then(|d| d.document())
|
||||
.map(|d| self.is_cjs_resolver.get_doc_module_kind(d))
|
||||
.unwrap_or(NodeModuleKind::Esm),
|
||||
&combined_code_actions.changes,
|
||||
self,
|
||||
)
|
||||
@ -1889,6 +1912,10 @@ impl Inner {
|
||||
if kind_suffix == ".rewrite.function.returnType" {
|
||||
refactor_edit_info.edits = fix_ts_import_changes(
|
||||
&action_data.specifier,
|
||||
asset_or_doc
|
||||
.document()
|
||||
.map(|d| self.is_cjs_resolver.get_doc_module_kind(d))
|
||||
.unwrap_or(NodeModuleKind::Esm),
|
||||
&refactor_edit_info.edits,
|
||||
self,
|
||||
)
|
||||
@ -2238,6 +2265,7 @@ impl Inner {
|
||||
&self.jsr_search_api,
|
||||
&self.npm_search_api,
|
||||
&self.documents,
|
||||
&self.is_cjs_resolver,
|
||||
self.resolver.as_ref(),
|
||||
self
|
||||
.config
|
||||
|
@ -263,7 +263,7 @@ impl ReplLanguageServer {
|
||||
}
|
||||
|
||||
fn get_document_uri(&self) -> Uri {
|
||||
uri_parse_unencoded(self.cwd_uri.join("$deno$repl.ts").unwrap().as_str())
|
||||
uri_parse_unencoded(self.cwd_uri.join("$deno$repl.mts").unwrap().as_str())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,18 @@
|
||||
|
||||
use dashmap::DashMap;
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ParsedSource;
|
||||
use deno_cache_dir::npm::NpmCacheDir;
|
||||
use deno_cache_dir::HttpCache;
|
||||
use deno_config::deno_json::JsxImportSourceConfig;
|
||||
use deno_config::workspace::PackageJsonDepResolution;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::source::Resolver;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::GraphImport;
|
||||
use deno_graph::ModuleSpecifier;
|
||||
use deno_graph::Range;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_path_util::url_from_directory_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
@ -24,6 +26,7 @@ use deno_semver::package::PackageReq;
|
||||
use indexmap::IndexMap;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::InNpmPackageChecker;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
@ -33,6 +36,7 @@ use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::cache::LspCache;
|
||||
use super::documents::Document;
|
||||
use super::jsr::JsrCacheResolver;
|
||||
use crate::args::create_default_npmrc;
|
||||
use crate::args::CacheSetting;
|
||||
@ -53,21 +57,20 @@ use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::CreateInNpmPkgCheckerOptions;
|
||||
use crate::npm::ManagedCliNpmResolver;
|
||||
use crate::resolver::CjsTracker;
|
||||
use crate::resolver::CjsTrackerOptions;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliGraphResolverOptions;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::CliResolverOptions;
|
||||
use crate::resolver::IsCjsResolver;
|
||||
use crate::resolver::WorkerCliNpmGraphResolver;
|
||||
use crate::tsc::into_specifier_and_media_type;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct LspScopeResolver {
|
||||
cjs_tracker: Option<Arc<LspCjsTracker>>,
|
||||
graph_resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
jsr_resolver: Option<Arc<JsrCacheResolver>>,
|
||||
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
@ -81,8 +84,7 @@ struct LspScopeResolver {
|
||||
impl Default for LspScopeResolver {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cjs_tracker: None,
|
||||
graph_resolver: create_graph_resolver(None, None, None),
|
||||
resolver: create_cli_resolver(None, None, None),
|
||||
jsr_resolver: None,
|
||||
npm_resolver: None,
|
||||
node_resolver: None,
|
||||
@ -103,7 +105,6 @@ impl LspScopeResolver {
|
||||
) -> Self {
|
||||
let mut npm_resolver = None;
|
||||
let mut node_resolver = None;
|
||||
let mut lsp_cjs_tracker = None;
|
||||
let fs = Arc::new(deno_fs::RealFs);
|
||||
let pkg_json_resolver = Arc::new(PackageJsonResolver::new(
|
||||
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
|
||||
@ -118,14 +119,7 @@ impl LspScopeResolver {
|
||||
.await;
|
||||
if let Some(npm_resolver) = &npm_resolver {
|
||||
let in_npm_pkg_checker = create_in_npm_pkg_checker(npm_resolver);
|
||||
let cjs_tracker = create_cjs_tracker(
|
||||
in_npm_pkg_checker.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
);
|
||||
lsp_cjs_tracker =
|
||||
Some(Arc::new(LspCjsTracker::new(cjs_tracker.clone())));
|
||||
node_resolver = Some(create_node_resolver(
|
||||
cjs_tracker,
|
||||
fs.clone(),
|
||||
in_npm_pkg_checker,
|
||||
npm_resolver,
|
||||
@ -133,7 +127,7 @@ impl LspScopeResolver {
|
||||
));
|
||||
}
|
||||
}
|
||||
let graph_resolver = create_graph_resolver(
|
||||
let cli_resolver = create_cli_resolver(
|
||||
config_data.map(|d| d.as_ref()),
|
||||
npm_resolver.as_ref(),
|
||||
node_resolver.as_ref(),
|
||||
@ -146,7 +140,9 @@ impl LspScopeResolver {
|
||||
cache.for_specifier(config_data.map(|d| d.scope.as_ref())),
|
||||
config_data.and_then(|d| d.lockfile.clone()),
|
||||
)));
|
||||
let npm_graph_resolver = graph_resolver.create_graph_npm_resolver();
|
||||
let npm_graph_resolver = cli_resolver.create_graph_npm_resolver();
|
||||
let maybe_jsx_import_source_config =
|
||||
config_data.and_then(|d| d.maybe_jsx_import_source_config());
|
||||
let graph_imports = config_data
|
||||
.and_then(|d| d.member_dir.workspace.to_compiler_option_types().ok())
|
||||
.map(|imports| {
|
||||
@ -154,11 +150,18 @@ impl LspScopeResolver {
|
||||
imports
|
||||
.into_iter()
|
||||
.map(|(referrer, imports)| {
|
||||
let resolver = SingleReferrerGraphResolver {
|
||||
valid_referrer: &referrer,
|
||||
referrer_kind: NodeModuleKind::Esm,
|
||||
cli_resolver: &cli_resolver,
|
||||
jsx_import_source_config: maybe_jsx_import_source_config
|
||||
.as_ref(),
|
||||
};
|
||||
let graph_import = GraphImport::new(
|
||||
&referrer,
|
||||
imports,
|
||||
&CliJsrUrlProvider,
|
||||
Some(graph_resolver.as_ref()),
|
||||
Some(&resolver),
|
||||
Some(&npm_graph_resolver),
|
||||
);
|
||||
(referrer, graph_import)
|
||||
@ -182,6 +185,8 @@ impl LspScopeResolver {
|
||||
.resolve_req_reference(
|
||||
&req_ref,
|
||||
&referrer,
|
||||
// todo(dsherret): this is wrong because it doesn't consider CJS referrers
|
||||
NodeModuleKind::Esm,
|
||||
NodeResolutionMode::Types,
|
||||
)
|
||||
.ok()?,
|
||||
@ -195,8 +200,7 @@ impl LspScopeResolver {
|
||||
let package_json_deps_by_resolution =
|
||||
Arc::new(package_json_deps_by_resolution.unwrap_or_default());
|
||||
Self {
|
||||
cjs_tracker: lsp_cjs_tracker,
|
||||
graph_resolver,
|
||||
resolver: cli_resolver,
|
||||
jsr_resolver,
|
||||
npm_resolver,
|
||||
node_resolver,
|
||||
@ -216,30 +220,22 @@ impl LspScopeResolver {
|
||||
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
|
||||
));
|
||||
let mut node_resolver = None;
|
||||
let mut lsp_cjs_tracker = None;
|
||||
if let Some(npm_resolver) = &npm_resolver {
|
||||
let in_npm_pkg_checker = create_in_npm_pkg_checker(npm_resolver);
|
||||
let cjs_tracker = create_cjs_tracker(
|
||||
in_npm_pkg_checker.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
);
|
||||
lsp_cjs_tracker = Some(Arc::new(LspCjsTracker::new(cjs_tracker.clone())));
|
||||
node_resolver = Some(create_node_resolver(
|
||||
cjs_tracker,
|
||||
fs,
|
||||
in_npm_pkg_checker,
|
||||
npm_resolver,
|
||||
pkg_json_resolver.clone(),
|
||||
));
|
||||
}
|
||||
let graph_resolver = create_graph_resolver(
|
||||
let graph_resolver = create_cli_resolver(
|
||||
self.config_data.as_deref(),
|
||||
npm_resolver.as_ref(),
|
||||
node_resolver.as_ref(),
|
||||
);
|
||||
Arc::new(Self {
|
||||
cjs_tracker: lsp_cjs_tracker,
|
||||
graph_resolver,
|
||||
resolver: graph_resolver,
|
||||
jsr_resolver: self.jsr_resolver.clone(),
|
||||
npm_resolver,
|
||||
node_resolver,
|
||||
@ -334,12 +330,12 @@ impl LspResolver {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_graph_resolver(
|
||||
pub fn as_cli_resolver(
|
||||
&self,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> &dyn Resolver {
|
||||
) -> &CliResolver {
|
||||
let resolver = self.get_scope_resolver(file_referrer);
|
||||
resolver.graph_resolver.as_ref()
|
||||
resolver.resolver.as_ref()
|
||||
}
|
||||
|
||||
pub fn create_graph_npm_resolver(
|
||||
@ -347,15 +343,15 @@ impl LspResolver {
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> WorkerCliNpmGraphResolver {
|
||||
let resolver = self.get_scope_resolver(file_referrer);
|
||||
resolver.graph_resolver.create_graph_npm_resolver()
|
||||
resolver.resolver.create_graph_npm_resolver()
|
||||
}
|
||||
|
||||
pub fn maybe_cjs_tracker(
|
||||
pub fn as_config_data(
|
||||
&self,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Option<&Arc<LspCjsTracker>> {
|
||||
) -> Option<&Arc<ConfigData>> {
|
||||
let resolver = self.get_scope_resolver(file_referrer);
|
||||
resolver.cjs_tracker.as_ref()
|
||||
resolver.config_data.as_ref()
|
||||
}
|
||||
|
||||
pub fn maybe_node_resolver(
|
||||
@ -429,13 +425,19 @@ impl LspResolver {
|
||||
&self,
|
||||
req_ref: &NpmPackageReqReference,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
file_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Option<(ModuleSpecifier, MediaType)> {
|
||||
let resolver = self.get_scope_resolver(file_referrer);
|
||||
let node_resolver = resolver.node_resolver.as_ref()?;
|
||||
Some(into_specifier_and_media_type(Some(
|
||||
node_resolver
|
||||
.resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
|
||||
.resolve_req_reference(
|
||||
req_ref,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Types,
|
||||
)
|
||||
.ok()?,
|
||||
)))
|
||||
}
|
||||
@ -478,6 +480,7 @@ impl LspResolver {
|
||||
&self,
|
||||
specifier_text: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
) -> bool {
|
||||
let resolver = self.get_scope_resolver(Some(referrer));
|
||||
let Some(node_resolver) = resolver.node_resolver.as_ref() else {
|
||||
@ -487,6 +490,7 @@ impl LspResolver {
|
||||
.resolve_if_for_npm_pkg(
|
||||
specifier_text,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Types,
|
||||
)
|
||||
.ok()
|
||||
@ -615,21 +619,6 @@ async fn create_npm_resolver(
|
||||
Some(create_cli_npm_resolver_for_lsp(options).await)
|
||||
}
|
||||
|
||||
fn create_cjs_tracker(
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
pkg_json_resolver: Arc<PackageJsonResolver>,
|
||||
) -> Arc<CjsTracker> {
|
||||
Arc::new(CjsTracker::new(
|
||||
in_npm_pkg_checker,
|
||||
pkg_json_resolver,
|
||||
CjsTrackerOptions {
|
||||
// todo(dsherret): support in the lsp by stabilizing the feature
|
||||
// so that we don't have to pipe the config in here
|
||||
unstable_detect_cjs: false,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn create_in_npm_pkg_checker(
|
||||
npm_resolver: &Arc<dyn CliNpmResolver>,
|
||||
) -> Arc<dyn InNpmPackageChecker> {
|
||||
@ -649,7 +638,6 @@ fn create_in_npm_pkg_checker(
|
||||
}
|
||||
|
||||
fn create_node_resolver(
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
npm_resolver: &Arc<dyn CliNpmResolver>,
|
||||
@ -662,7 +650,6 @@ fn create_node_resolver(
|
||||
pkg_json_resolver.clone(),
|
||||
));
|
||||
Arc::new(CliNodeResolver::new(
|
||||
cjs_tracker.clone(),
|
||||
fs,
|
||||
in_npm_pkg_checker,
|
||||
node_resolver_inner,
|
||||
@ -670,13 +657,12 @@ fn create_node_resolver(
|
||||
))
|
||||
}
|
||||
|
||||
fn create_graph_resolver(
|
||||
fn create_cli_resolver(
|
||||
config_data: Option<&ConfigData>,
|
||||
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
||||
node_resolver: Option<&Arc<CliNodeResolver>>,
|
||||
) -> Arc<CliGraphResolver> {
|
||||
let workspace = config_data.map(|d| &d.member_dir.workspace);
|
||||
Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
||||
) -> Arc<CliResolver> {
|
||||
Arc::new(CliResolver::new(CliResolverOptions {
|
||||
node_resolver: node_resolver.cloned(),
|
||||
npm_resolver: npm_resolver.cloned(),
|
||||
workspace_resolver: config_data.map(|d| d.resolver.clone()).unwrap_or_else(
|
||||
@ -691,9 +677,6 @@ fn create_graph_resolver(
|
||||
))
|
||||
},
|
||||
),
|
||||
maybe_jsx_import_source_config: workspace.and_then(|workspace| {
|
||||
workspace.to_maybe_jsx_import_source_config().ok().flatten()
|
||||
}),
|
||||
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
|
||||
bare_node_builtins_enabled: config_data
|
||||
.is_some_and(|d| d.unstable.contains("bare-node-builtins")),
|
||||
@ -726,6 +709,141 @@ impl std::fmt::Debug for RedirectResolver {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LspIsCjsResolver {
|
||||
inner: IsCjsResolver,
|
||||
}
|
||||
|
||||
impl Default for LspIsCjsResolver {
|
||||
fn default() -> Self {
|
||||
LspIsCjsResolver::new(&Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl LspIsCjsResolver {
|
||||
pub fn new(cache: &LspCache) -> Self {
|
||||
#[derive(Debug)]
|
||||
struct LspInNpmPackageChecker {
|
||||
global_cache_dir: ModuleSpecifier,
|
||||
}
|
||||
|
||||
impl LspInNpmPackageChecker {
|
||||
pub fn new(cache: &LspCache) -> Self {
|
||||
let npm_folder_path = cache.deno_dir().npm_folder_path();
|
||||
Self {
|
||||
global_cache_dir: url_from_directory_path(
|
||||
&canonicalize_path_maybe_not_exists(&npm_folder_path)
|
||||
.unwrap_or(npm_folder_path),
|
||||
)
|
||||
.unwrap_or_else(|_| {
|
||||
ModuleSpecifier::parse("file:///invalid/").unwrap()
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InNpmPackageChecker for LspInNpmPackageChecker {
|
||||
fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
if specifier.scheme() != "file" {
|
||||
return false;
|
||||
}
|
||||
if specifier
|
||||
.as_str()
|
||||
.starts_with(self.global_cache_dir.as_str())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
specifier.as_str().contains("/node_modules/")
|
||||
}
|
||||
}
|
||||
|
||||
let fs = Arc::new(deno_fs::RealFs);
|
||||
let pkg_json_resolver = Arc::new(PackageJsonResolver::new(
|
||||
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
|
||||
));
|
||||
|
||||
LspIsCjsResolver {
|
||||
inner: IsCjsResolver::new(
|
||||
Arc::new(LspInNpmPackageChecker::new(cache)),
|
||||
pkg_json_resolver,
|
||||
crate::resolver::IsCjsResolverOptions {
|
||||
detect_cjs: true,
|
||||
is_node_main: false,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_maybe_doc_module_kind(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
maybe_document: Option<&Document>,
|
||||
) -> NodeModuleKind {
|
||||
self.get_lsp_referrer_kind(
|
||||
specifier,
|
||||
maybe_document.and_then(|d| d.is_script()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_doc_module_kind(&self, document: &Document) -> NodeModuleKind {
|
||||
self.get_lsp_referrer_kind(document.specifier(), document.is_script())
|
||||
}
|
||||
|
||||
pub fn get_lsp_referrer_kind(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
is_script: Option<bool>,
|
||||
) -> NodeModuleKind {
|
||||
self.inner.get_lsp_referrer_kind(specifier, is_script)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SingleReferrerGraphResolver<'a> {
|
||||
pub valid_referrer: &'a ModuleSpecifier,
|
||||
pub referrer_kind: NodeModuleKind,
|
||||
pub cli_resolver: &'a CliResolver,
|
||||
pub jsx_import_source_config: Option<&'a JsxImportSourceConfig>,
|
||||
}
|
||||
|
||||
impl<'a> deno_graph::source::Resolver for SingleReferrerGraphResolver<'a> {
|
||||
fn default_jsx_import_source(&self) -> Option<String> {
|
||||
self
|
||||
.jsx_import_source_config
|
||||
.and_then(|c| c.default_specifier.clone())
|
||||
}
|
||||
|
||||
fn default_jsx_import_source_types(&self) -> Option<String> {
|
||||
self
|
||||
.jsx_import_source_config
|
||||
.and_then(|c| c.default_types_specifier.clone())
|
||||
}
|
||||
|
||||
fn jsx_import_source_module(&self) -> &str {
|
||||
self
|
||||
.jsx_import_source_config
|
||||
.map(|c| c.module.as_str())
|
||||
.unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
specifier_text: &str,
|
||||
referrer_range: &Range,
|
||||
mode: ResolutionMode,
|
||||
) -> Result<ModuleSpecifier, deno_graph::source::ResolveError> {
|
||||
// this resolver assumes it will only be used with a single referrer
|
||||
// with the provided referrer kind
|
||||
debug_assert_eq!(referrer_range.specifier, *self.valid_referrer);
|
||||
self.cli_resolver.resolve(
|
||||
specifier_text,
|
||||
referrer_range,
|
||||
self.referrer_kind,
|
||||
mode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RedirectResolver {
|
||||
fn new(
|
||||
cache: Arc<dyn HttpCache>,
|
||||
@ -842,45 +960,6 @@ impl RedirectResolver {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LspCjsTracker {
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
}
|
||||
|
||||
impl LspCjsTracker {
|
||||
pub fn new(cjs_tracker: Arc<CjsTracker>) -> Self {
|
||||
Self { cjs_tracker }
|
||||
}
|
||||
|
||||
pub fn is_cjs(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
maybe_parsed_source: Option<&ParsedSource>,
|
||||
) -> bool {
|
||||
if let Some(module_kind) =
|
||||
self.cjs_tracker.get_known_kind(specifier, media_type)
|
||||
{
|
||||
module_kind.is_cjs()
|
||||
} else {
|
||||
let maybe_is_script = maybe_parsed_source.map(|p| p.compute_is_script());
|
||||
maybe_is_script
|
||||
.and_then(|is_script| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_cjs_with_known_is_script(specifier, media_type, is_script)
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(specifier, media_type)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -69,6 +69,7 @@ use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use lazy_regex::lazy_regex;
|
||||
use log::error;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Captures;
|
||||
use regex::Regex;
|
||||
@ -4401,25 +4402,15 @@ fn op_load<'s>(
|
||||
None
|
||||
} else {
|
||||
let asset_or_document = state.get_asset_or_document(&specifier);
|
||||
asset_or_document.map(|doc| {
|
||||
let maybe_cjs_tracker = state
|
||||
.state_snapshot
|
||||
.resolver
|
||||
.maybe_cjs_tracker(Some(&specifier));
|
||||
LoadResponse {
|
||||
data: doc.text(),
|
||||
script_kind: crate::tsc::as_ts_script_kind(doc.media_type()),
|
||||
version: state.script_version(&specifier),
|
||||
is_cjs: maybe_cjs_tracker
|
||||
.map(|t| {
|
||||
t.is_cjs(
|
||||
&specifier,
|
||||
doc.media_type(),
|
||||
doc.maybe_parsed_source().and_then(|p| p.as_ref().ok()),
|
||||
)
|
||||
})
|
||||
.unwrap_or(false),
|
||||
}
|
||||
asset_or_document.map(|doc| LoadResponse {
|
||||
data: doc.text(),
|
||||
script_kind: crate::tsc::as_ts_script_kind(doc.media_type()),
|
||||
version: state.script_version(&specifier),
|
||||
is_cjs: doc
|
||||
.document()
|
||||
.map(|d| state.state_snapshot.is_cjs_resolver.get_doc_module_kind(d))
|
||||
.unwrap_or(NodeModuleKind::Esm)
|
||||
== NodeModuleKind::Cjs,
|
||||
})
|
||||
};
|
||||
|
||||
@ -4662,6 +4653,10 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
|
||||
let (types, _) = documents.resolve_dependency(
|
||||
types,
|
||||
specifier,
|
||||
state
|
||||
.state_snapshot
|
||||
.is_cjs_resolver
|
||||
.get_doc_module_kind(doc),
|
||||
doc.file_referrer(),
|
||||
)?;
|
||||
let types_doc = documents.get_or_load(&types, doc.file_referrer())?;
|
||||
@ -5544,6 +5539,7 @@ mod tests {
|
||||
documents: Arc::new(documents),
|
||||
assets: Default::default(),
|
||||
config: Arc::new(config),
|
||||
is_cjs_resolver: Default::default(),
|
||||
resolver,
|
||||
});
|
||||
let performance = Arc::new(Performance::default());
|
||||
|
@ -27,8 +27,8 @@ use crate::node;
|
||||
use crate::node::CliNodeCodeTranslator;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CjsTracker;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::ModuleCodeStringSource;
|
||||
use crate::resolver::NotSupportedKindInNpmError;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
@ -60,7 +60,6 @@ use deno_core::RequestedModuleType;
|
||||
use deno_core::ResolutionKind;
|
||||
use deno_core::SourceCodeCacheInfo;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::source::Resolver;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_graph::JsModule;
|
||||
use deno_graph::JsonModule;
|
||||
@ -73,6 +72,7 @@ use deno_runtime::deno_node::create_host_defined_options;
|
||||
use deno_runtime::deno_node::NodeRequireLoader;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::InNpmPackageChecker;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
|
||||
@ -206,7 +206,6 @@ struct SharedCliModuleLoaderState {
|
||||
lib_worker: TsTypeLib,
|
||||
initial_cwd: PathBuf,
|
||||
is_inspecting: bool,
|
||||
is_npm_main: bool,
|
||||
is_repl: bool,
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
code_cache: Option<Arc<CodeCache>>,
|
||||
@ -220,7 +219,7 @@ struct SharedCliModuleLoaderState {
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
}
|
||||
|
||||
pub struct CliModuleLoaderFactory {
|
||||
@ -243,7 +242,7 @@ impl CliModuleLoaderFactory {
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
npm_module_loader: NpmModuleLoader,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared: Arc::new(SharedCliModuleLoaderState {
|
||||
@ -252,7 +251,6 @@ impl CliModuleLoaderFactory {
|
||||
lib_worker: options.ts_type_lib_worker(),
|
||||
initial_cwd: options.initial_cwd().to_path_buf(),
|
||||
is_inspecting: options.is_inspecting(),
|
||||
is_npm_main: options.is_npm_main(),
|
||||
is_repl: matches!(
|
||||
options.sub_command(),
|
||||
DenoSubcommand::Repl(_) | DenoSubcommand::Jupyter(_)
|
||||
@ -286,7 +284,6 @@ impl CliModuleLoaderFactory {
|
||||
Rc::new(CliModuleLoader(Rc::new(CliModuleLoaderInner {
|
||||
lib,
|
||||
is_worker,
|
||||
is_npm_main: self.shared.is_npm_main,
|
||||
parent_permissions,
|
||||
permissions,
|
||||
graph_container: graph_container.clone(),
|
||||
@ -295,13 +292,14 @@ impl CliModuleLoaderFactory {
|
||||
parsed_source_cache: self.shared.parsed_source_cache.clone(),
|
||||
shared: self.shared.clone(),
|
||||
})));
|
||||
let node_require_loader = Rc::new(CliNodeRequireLoader::new(
|
||||
self.shared.emitter.clone(),
|
||||
self.shared.fs.clone(),
|
||||
let node_require_loader = Rc::new(CliNodeRequireLoader {
|
||||
cjs_tracker: self.shared.cjs_tracker.clone(),
|
||||
emitter: self.shared.emitter.clone(),
|
||||
fs: self.shared.fs.clone(),
|
||||
graph_container,
|
||||
self.shared.in_npm_pkg_checker.clone(),
|
||||
self.shared.npm_resolver.clone(),
|
||||
));
|
||||
in_npm_pkg_checker: self.shared.in_npm_pkg_checker.clone(),
|
||||
npm_resolver: self.shared.npm_resolver.clone(),
|
||||
});
|
||||
CreateModuleLoaderResult {
|
||||
module_loader,
|
||||
node_require_loader,
|
||||
@ -343,7 +341,6 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
|
||||
|
||||
struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
|
||||
lib: TsTypeLib,
|
||||
is_npm_main: bool,
|
||||
is_worker: bool,
|
||||
/// The initial set of permissions used to resolve the static imports in the
|
||||
/// worker. These are "allow all" for main worker, and parent thread
|
||||
@ -450,7 +447,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||
let referrer = if referrer.is_empty() && self.shared.is_repl {
|
||||
// FIXME(bartlomieju): this is a hacky way to provide compatibility with REPL
|
||||
// and `Deno.core.evalContext` API. Ideally we should always have a referrer filled
|
||||
"./$deno$repl.ts"
|
||||
"./$deno$repl.mts"
|
||||
} else {
|
||||
referrer
|
||||
};
|
||||
@ -478,7 +475,12 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||
self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve(raw_specifier, referrer, NodeResolutionMode::Execution)?
|
||||
.resolve(
|
||||
raw_specifier,
|
||||
referrer,
|
||||
self.shared.cjs_tracker.get_referrer_kind(referrer),
|
||||
NodeResolutionMode::Execution,
|
||||
)?
|
||||
.into_url(),
|
||||
);
|
||||
}
|
||||
@ -508,6 +510,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||
start: deno_graph::Position::zeroed(),
|
||||
end: deno_graph::Position::zeroed(),
|
||||
},
|
||||
self.shared.cjs_tracker.get_referrer_kind(referrer),
|
||||
ResolutionMode::Execution,
|
||||
)?),
|
||||
};
|
||||
@ -518,6 +521,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||
return self.shared.node_resolver.resolve_req_reference(
|
||||
&reference,
|
||||
referrer,
|
||||
self.shared.cjs_tracker.get_referrer_kind(referrer),
|
||||
NodeResolutionMode::Execution,
|
||||
);
|
||||
}
|
||||
@ -538,6 +542,7 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||
&package_folder,
|
||||
module.nv_reference.sub_path(),
|
||||
Some(referrer),
|
||||
self.shared.cjs_tracker.get_referrer_kind(referrer),
|
||||
NodeResolutionMode::Execution,
|
||||
)
|
||||
.with_context(|| {
|
||||
@ -668,14 +673,11 @@ impl<TGraphContainer: ModuleGraphContainer>
|
||||
is_script,
|
||||
..
|
||||
})) => {
|
||||
// todo(dsherret): revert in https://github.com/denoland/deno/pull/26439
|
||||
if self.is_npm_main && *is_script
|
||||
|| self.shared.cjs_tracker.is_cjs_with_known_is_script(
|
||||
specifier,
|
||||
*media_type,
|
||||
*is_script,
|
||||
)?
|
||||
{
|
||||
if self.shared.cjs_tracker.is_cjs_with_known_is_script(
|
||||
specifier,
|
||||
*media_type,
|
||||
*is_script,
|
||||
)? {
|
||||
return Ok(Some(CodeOrDeferredEmit::Cjs {
|
||||
specifier,
|
||||
media_type: *media_type,
|
||||
@ -1031,6 +1033,7 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
emitter: Arc<Emitter>,
|
||||
fs: Arc<dyn FileSystem>,
|
||||
graph_container: TGraphContainer,
|
||||
@ -1038,26 +1041,6 @@ struct CliNodeRequireLoader<TGraphContainer: ModuleGraphContainer> {
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
}
|
||||
|
||||
impl<TGraphContainer: ModuleGraphContainer>
|
||||
CliNodeRequireLoader<TGraphContainer>
|
||||
{
|
||||
pub fn new(
|
||||
emitter: Arc<Emitter>,
|
||||
fs: Arc<dyn FileSystem>,
|
||||
graph_container: TGraphContainer,
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
) -> Self {
|
||||
Self {
|
||||
emitter,
|
||||
fs,
|
||||
graph_container,
|
||||
in_npm_pkg_checker,
|
||||
npm_resolver,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
|
||||
for CliNodeRequireLoader<TGraphContainer>
|
||||
{
|
||||
@ -1103,4 +1086,12 @@ impl<TGraphContainer: ModuleGraphContainer> NodeRequireLoader
|
||||
Ok(text)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_maybe_cjs(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<bool, ClosestPkgJsonError> {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
self.cjs_tracker.is_maybe_cjs(specifier, media_type)
|
||||
}
|
||||
}
|
||||
|
12
cli/node.rs
12
cli/node.rs
@ -62,10 +62,6 @@ pub struct CliCjsCodeAnalyzer {
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
fs: deno_fs::FileSystemRc,
|
||||
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
|
||||
// todo(dsherret): hack, remove in https://github.com/denoland/deno/pull/26439
|
||||
// For example, this does not properly handle if cjs analysis was already done
|
||||
// and has been cached.
|
||||
is_npm_main: bool,
|
||||
}
|
||||
|
||||
impl CliCjsCodeAnalyzer {
|
||||
@ -74,14 +70,12 @@ impl CliCjsCodeAnalyzer {
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
fs: deno_fs::FileSystemRc,
|
||||
parsed_source_cache: Option<Arc<ParsedSourceCache>>,
|
||||
is_npm_main: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
cache,
|
||||
cjs_tracker,
|
||||
fs,
|
||||
parsed_source_cache,
|
||||
is_npm_main,
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,9 +100,7 @@ impl CliCjsCodeAnalyzer {
|
||||
}
|
||||
|
||||
let cjs_tracker = self.cjs_tracker.clone();
|
||||
let is_npm_main = self.is_npm_main;
|
||||
let is_maybe_cjs =
|
||||
cjs_tracker.is_maybe_cjs(specifier, media_type)? || is_npm_main;
|
||||
let is_maybe_cjs = cjs_tracker.is_maybe_cjs(specifier, media_type)?;
|
||||
let analysis = if is_maybe_cjs {
|
||||
let maybe_parsed_source = self
|
||||
.parsed_source_cache
|
||||
@ -135,7 +127,7 @@ impl CliCjsCodeAnalyzer {
|
||||
parsed_source.specifier(),
|
||||
media_type,
|
||||
is_script,
|
||||
)? || is_script && is_npm_main;
|
||||
)?;
|
||||
if is_cjs {
|
||||
let analysis = parsed_source.analyze_cjs();
|
||||
Ok(CliCjsAnalysis::Cjs {
|
||||
|
289
cli/resolver.rs
289
cli/resolver.rs
@ -4,7 +4,6 @@ use async_trait::async_trait;
|
||||
use dashmap::DashMap;
|
||||
use dashmap::DashSet;
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ModuleKind;
|
||||
use deno_config::workspace::MappedResolution;
|
||||
use deno_config::workspace::MappedResolutionDiagnostic;
|
||||
use deno_config::workspace::MappedResolutionError;
|
||||
@ -17,9 +16,7 @@ use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::source::ResolveError;
|
||||
use deno_graph::source::Resolver;
|
||||
use deno_graph::source::UnknownBuiltInNodeModuleError;
|
||||
use deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE;
|
||||
use deno_graph::NpmLoadError;
|
||||
use deno_graph::NpmResolvePkgReqsResult;
|
||||
use deno_npm::resolution::NpmResolutionError;
|
||||
@ -52,7 +49,6 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::args::JsxImportSourceConfig;
|
||||
use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS;
|
||||
use crate::node::CliNodeCodeTranslator;
|
||||
use crate::npm::CliNpmResolver;
|
||||
@ -108,7 +104,6 @@ impl deno_resolver::fs::DenoResolverFs for CliDenoResolverFs {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CliNodeResolver {
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
@ -117,14 +112,12 @@ pub struct CliNodeResolver {
|
||||
|
||||
impl CliNodeResolver {
|
||||
pub fn new(
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
fs: Arc<dyn deno_fs::FileSystem>,
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
node_resolver: Arc<NodeResolver>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_tracker,
|
||||
fs,
|
||||
in_npm_pkg_checker,
|
||||
node_resolver,
|
||||
@ -140,9 +133,11 @@ impl CliNodeResolver {
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<Option<NodeResolution>, AnyError> {
|
||||
let resolution_result = self.resolve(specifier, referrer, mode);
|
||||
let resolution_result =
|
||||
self.resolve(specifier, referrer, referrer_kind, mode);
|
||||
match resolution_result {
|
||||
Ok(res) => Ok(Some(res)),
|
||||
Err(err) => {
|
||||
@ -213,35 +208,26 @@ impl CliNodeResolver {
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<NodeResolution, NodeResolveError> {
|
||||
let referrer_kind = if self
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(referrer, MediaType::from_specifier(referrer))
|
||||
.map_err(|err| NodeResolveErrorKind::PackageResolve(err.into()))?
|
||||
{
|
||||
NodeModuleKind::Cjs
|
||||
} else {
|
||||
NodeModuleKind::Esm
|
||||
};
|
||||
|
||||
let res =
|
||||
self
|
||||
.node_resolver
|
||||
.resolve(specifier, referrer, referrer_kind, mode)?;
|
||||
Ok(res)
|
||||
self
|
||||
.node_resolver
|
||||
.resolve(specifier, referrer, referrer_kind, mode)
|
||||
}
|
||||
|
||||
pub fn resolve_req_reference(
|
||||
&self,
|
||||
req_ref: &NpmPackageReqReference,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, AnyError> {
|
||||
self.resolve_req_with_sub_path(
|
||||
req_ref.req(),
|
||||
req_ref.sub_path(),
|
||||
referrer,
|
||||
referrer_kind,
|
||||
mode,
|
||||
)
|
||||
}
|
||||
@ -251,6 +237,7 @@ impl CliNodeResolver {
|
||||
req: &PackageReq,
|
||||
sub_path: Option<&str>,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, AnyError> {
|
||||
let package_folder = self
|
||||
@ -260,6 +247,7 @@ impl CliNodeResolver {
|
||||
&package_folder,
|
||||
sub_path,
|
||||
Some(referrer),
|
||||
referrer_kind,
|
||||
mode,
|
||||
);
|
||||
match resolution_result {
|
||||
@ -284,12 +272,14 @@ impl CliNodeResolver {
|
||||
package_folder: &Path,
|
||||
sub_path: Option<&str>,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageSubpathResolveError> {
|
||||
self.node_resolver.resolve_package_subpath_from_deno_module(
|
||||
package_folder,
|
||||
sub_path,
|
||||
maybe_referrer,
|
||||
referrer_kind,
|
||||
mode,
|
||||
)
|
||||
}
|
||||
@ -419,10 +409,6 @@ impl NpmModuleLoader {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CjsTrackerOptions {
|
||||
pub unstable_detect_cjs: bool,
|
||||
}
|
||||
|
||||
/// Keeps track of what module specifiers were resolved as CJS.
|
||||
///
|
||||
/// Modules that are `.js` or `.ts` are only known to be CJS or
|
||||
@ -430,22 +416,22 @@ pub struct CjsTrackerOptions {
|
||||
/// will be "maybe CJS" until they're loaded.
|
||||
#[derive(Debug)]
|
||||
pub struct CjsTracker {
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
pkg_json_resolver: Arc<PackageJsonResolver>,
|
||||
unstable_detect_cjs: bool,
|
||||
known: DashMap<ModuleSpecifier, ModuleKind>,
|
||||
is_cjs_resolver: IsCjsResolver,
|
||||
known: DashMap<ModuleSpecifier, NodeModuleKind>,
|
||||
}
|
||||
|
||||
impl CjsTracker {
|
||||
pub fn new(
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
pkg_json_resolver: Arc<PackageJsonResolver>,
|
||||
options: CjsTrackerOptions,
|
||||
options: IsCjsResolverOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
in_npm_pkg_checker,
|
||||
pkg_json_resolver,
|
||||
unstable_detect_cjs: options.unstable_detect_cjs,
|
||||
is_cjs_resolver: IsCjsResolver::new(
|
||||
in_npm_pkg_checker,
|
||||
pkg_json_resolver,
|
||||
options,
|
||||
),
|
||||
known: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -485,47 +471,90 @@ impl CjsTracker {
|
||||
.get_known_kind_with_is_script(specifier, media_type, is_script)
|
||||
{
|
||||
Some(kind) => kind,
|
||||
None => self.check_based_on_pkg_json(specifier)?,
|
||||
None => self.is_cjs_resolver.check_based_on_pkg_json(specifier)?,
|
||||
};
|
||||
Ok(kind.is_cjs())
|
||||
Ok(kind == NodeModuleKind::Cjs)
|
||||
}
|
||||
|
||||
pub fn get_known_kind(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
) -> Option<ModuleKind> {
|
||||
) -> Option<NodeModuleKind> {
|
||||
self.get_known_kind_with_is_script(specifier, media_type, None)
|
||||
}
|
||||
|
||||
pub fn get_referrer_kind(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> NodeModuleKind {
|
||||
if specifier.scheme() != "file" {
|
||||
return NodeModuleKind::Esm;
|
||||
}
|
||||
self
|
||||
.get_known_kind(specifier, MediaType::from_specifier(specifier))
|
||||
.unwrap_or(NodeModuleKind::Esm)
|
||||
}
|
||||
|
||||
fn get_known_kind_with_is_script(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
is_script: Option<bool>,
|
||||
) -> Option<ModuleKind> {
|
||||
if specifier.scheme() != "file" {
|
||||
return Some(ModuleKind::Esm);
|
||||
}
|
||||
) -> Option<NodeModuleKind> {
|
||||
self.is_cjs_resolver.get_known_kind_with_is_script(
|
||||
specifier,
|
||||
media_type,
|
||||
is_script,
|
||||
&self.known,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
match media_type {
|
||||
MediaType::Mts | MediaType::Mjs | MediaType::Dmts => Some(ModuleKind::Esm),
|
||||
MediaType::Cjs | MediaType::Cts | MediaType::Dcts => Some(ModuleKind::Cjs),
|
||||
#[derive(Debug)]
|
||||
pub struct IsCjsResolverOptions {
|
||||
pub detect_cjs: bool,
|
||||
pub is_node_main: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IsCjsResolver {
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
pkg_json_resolver: Arc<PackageJsonResolver>,
|
||||
options: IsCjsResolverOptions,
|
||||
}
|
||||
|
||||
impl IsCjsResolver {
|
||||
pub fn new(
|
||||
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
|
||||
pkg_json_resolver: Arc<PackageJsonResolver>,
|
||||
options: IsCjsResolverOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
in_npm_pkg_checker,
|
||||
pkg_json_resolver,
|
||||
options,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_lsp_referrer_kind(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
is_script: Option<bool>,
|
||||
) -> NodeModuleKind {
|
||||
if specifier.scheme() != "file" {
|
||||
return NodeModuleKind::Esm;
|
||||
}
|
||||
match MediaType::from_specifier(specifier) {
|
||||
MediaType::Mts | MediaType::Mjs | MediaType::Dmts => NodeModuleKind::Esm,
|
||||
MediaType::Cjs | MediaType::Cts | MediaType::Dcts => NodeModuleKind::Cjs,
|
||||
MediaType::Dts => {
|
||||
// dts files are always determined based on the package.json because
|
||||
// they contain imports/exports even when considered CJS
|
||||
if let Some(value) = self.known.get(specifier).map(|v| *v) {
|
||||
Some(value)
|
||||
} else {
|
||||
let value = self.check_based_on_pkg_json(specifier).ok();
|
||||
if let Some(value) = value {
|
||||
self.known.insert(specifier.clone(), value);
|
||||
}
|
||||
Some(value.unwrap_or(ModuleKind::Esm))
|
||||
}
|
||||
self.check_based_on_pkg_json(specifier).unwrap_or(NodeModuleKind::Esm)
|
||||
}
|
||||
MediaType::Wasm |
|
||||
MediaType::Json => Some(ModuleKind::Esm),
|
||||
MediaType::Json => NodeModuleKind::Esm,
|
||||
MediaType::JavaScript
|
||||
| MediaType::Jsx
|
||||
| MediaType::TypeScript
|
||||
@ -534,18 +563,63 @@ impl CjsTracker {
|
||||
| MediaType::Css
|
||||
| MediaType::SourceMap
|
||||
| MediaType::Unknown => {
|
||||
if let Some(value) = self.known.get(specifier).map(|v| *v) {
|
||||
if value.is_cjs() && is_script == Some(false) {
|
||||
match is_script {
|
||||
Some(true) => self.check_based_on_pkg_json(specifier).unwrap_or(NodeModuleKind::Esm),
|
||||
Some(false) | None => NodeModuleKind::Esm,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_known_kind_with_is_script(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
is_script: Option<bool>,
|
||||
known_cache: &DashMap<ModuleSpecifier, NodeModuleKind>,
|
||||
) -> Option<NodeModuleKind> {
|
||||
if specifier.scheme() != "file" {
|
||||
return Some(NodeModuleKind::Esm);
|
||||
}
|
||||
|
||||
match media_type {
|
||||
MediaType::Mts | MediaType::Mjs | MediaType::Dmts => Some(NodeModuleKind::Esm),
|
||||
MediaType::Cjs | MediaType::Cts | MediaType::Dcts => Some(NodeModuleKind::Cjs),
|
||||
MediaType::Dts => {
|
||||
// dts files are always determined based on the package.json because
|
||||
// they contain imports/exports even when considered CJS
|
||||
if let Some(value) = known_cache.get(specifier).map(|v| *v) {
|
||||
Some(value)
|
||||
} else {
|
||||
let value = self.check_based_on_pkg_json(specifier).ok();
|
||||
if let Some(value) = value {
|
||||
known_cache.insert(specifier.clone(), value);
|
||||
}
|
||||
Some(value.unwrap_or(NodeModuleKind::Esm))
|
||||
}
|
||||
}
|
||||
MediaType::Wasm |
|
||||
MediaType::Json => Some(NodeModuleKind::Esm),
|
||||
MediaType::JavaScript
|
||||
| MediaType::Jsx
|
||||
| MediaType::TypeScript
|
||||
| MediaType::Tsx
|
||||
// treat these as unknown
|
||||
| MediaType::Css
|
||||
| MediaType::SourceMap
|
||||
| MediaType::Unknown => {
|
||||
if let Some(value) = known_cache.get(specifier).map(|v| *v) {
|
||||
if value == NodeModuleKind::Cjs && is_script == Some(false) {
|
||||
// we now know this is actually esm
|
||||
self.known.insert(specifier.clone(), ModuleKind::Esm);
|
||||
Some(ModuleKind::Esm)
|
||||
known_cache.insert(specifier.clone(), NodeModuleKind::Esm);
|
||||
Some(NodeModuleKind::Esm)
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
} else if is_script == Some(false) {
|
||||
// we know this is esm
|
||||
self.known.insert(specifier.clone(), ModuleKind::Esm);
|
||||
Some(ModuleKind::Esm)
|
||||
known_cache.insert(specifier.clone(), NodeModuleKind::Esm);
|
||||
Some(NodeModuleKind::Esm)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -556,27 +630,38 @@ impl CjsTracker {
|
||||
fn check_based_on_pkg_json(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<ModuleKind, ClosestPkgJsonError> {
|
||||
) -> Result<NodeModuleKind, ClosestPkgJsonError> {
|
||||
if self.in_npm_pkg_checker.in_npm_package(specifier) {
|
||||
if let Some(pkg_json) =
|
||||
self.pkg_json_resolver.get_closest_package_json(specifier)?
|
||||
{
|
||||
let is_file_location_cjs = pkg_json.typ != "module";
|
||||
Ok(ModuleKind::from_is_cjs(is_file_location_cjs))
|
||||
Ok(if is_file_location_cjs {
|
||||
NodeModuleKind::Cjs
|
||||
} else {
|
||||
NodeModuleKind::Esm
|
||||
})
|
||||
} else {
|
||||
Ok(ModuleKind::Cjs)
|
||||
Ok(NodeModuleKind::Cjs)
|
||||
}
|
||||
} else if self.unstable_detect_cjs {
|
||||
} else if self.options.detect_cjs || self.options.is_node_main {
|
||||
if let Some(pkg_json) =
|
||||
self.pkg_json_resolver.get_closest_package_json(specifier)?
|
||||
{
|
||||
let is_cjs_type = pkg_json.typ == "commonjs";
|
||||
Ok(ModuleKind::from_is_cjs(is_cjs_type))
|
||||
let is_cjs_type = pkg_json.typ == "commonjs"
|
||||
|| self.options.is_node_main && pkg_json.typ == "none";
|
||||
Ok(if is_cjs_type {
|
||||
NodeModuleKind::Cjs
|
||||
} else {
|
||||
NodeModuleKind::Esm
|
||||
})
|
||||
} else if self.options.is_node_main {
|
||||
Ok(NodeModuleKind::Cjs)
|
||||
} else {
|
||||
Ok(ModuleKind::Esm)
|
||||
Ok(NodeModuleKind::Esm)
|
||||
}
|
||||
} else {
|
||||
Ok(ModuleKind::Esm)
|
||||
Ok(NodeModuleKind::Esm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -587,48 +672,33 @@ pub type CliSloppyImportsResolver =
|
||||
/// A resolver that takes care of resolution, taking into account loaded
|
||||
/// import map, JSX settings.
|
||||
#[derive(Debug)]
|
||||
pub struct CliGraphResolver {
|
||||
pub struct CliResolver {
|
||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
workspace_resolver: Arc<WorkspaceResolver>,
|
||||
maybe_default_jsx_import_source: Option<String>,
|
||||
maybe_default_jsx_import_source_types: Option<String>,
|
||||
maybe_jsx_import_source_module: Option<String>,
|
||||
maybe_vendor_specifier: Option<ModuleSpecifier>,
|
||||
found_package_json_dep_flag: AtomicFlag,
|
||||
bare_node_builtins_enabled: bool,
|
||||
warned_pkgs: DashSet<PackageReq>,
|
||||
}
|
||||
|
||||
pub struct CliGraphResolverOptions<'a> {
|
||||
pub struct CliResolverOptions<'a> {
|
||||
pub node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
pub npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
pub sloppy_imports_resolver: Option<Arc<CliSloppyImportsResolver>>,
|
||||
pub workspace_resolver: Arc<WorkspaceResolver>,
|
||||
pub bare_node_builtins_enabled: bool,
|
||||
pub maybe_jsx_import_source_config: Option<JsxImportSourceConfig>,
|
||||
pub maybe_vendor_dir: Option<&'a PathBuf>,
|
||||
}
|
||||
|
||||
impl CliGraphResolver {
|
||||
pub fn new(options: CliGraphResolverOptions) -> Self {
|
||||
impl CliResolver {
|
||||
pub fn new(options: CliResolverOptions) -> Self {
|
||||
Self {
|
||||
node_resolver: options.node_resolver,
|
||||
npm_resolver: options.npm_resolver,
|
||||
sloppy_imports_resolver: options.sloppy_imports_resolver,
|
||||
workspace_resolver: options.workspace_resolver,
|
||||
maybe_default_jsx_import_source: options
|
||||
.maybe_jsx_import_source_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.default_specifier.clone()),
|
||||
maybe_default_jsx_import_source_types: options
|
||||
.maybe_jsx_import_source_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.default_types_specifier.clone()),
|
||||
maybe_jsx_import_source_module: options
|
||||
.maybe_jsx_import_source_config
|
||||
.map(|c| c.module),
|
||||
maybe_vendor_specifier: options
|
||||
.maybe_vendor_dir
|
||||
.and_then(|v| ModuleSpecifier::from_directory_path(v).ok()),
|
||||
@ -638,10 +708,6 @@ impl CliGraphResolver {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_graph_resolver(&self) -> &dyn Resolver {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn create_graph_npm_resolver(&self) -> WorkerCliNpmGraphResolver {
|
||||
WorkerCliNpmGraphResolver {
|
||||
npm_resolver: self.npm_resolver.as_ref(),
|
||||
@ -649,28 +715,12 @@ impl CliGraphResolver {
|
||||
bare_node_builtins_enabled: self.bare_node_builtins_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolver for CliGraphResolver {
|
||||
fn default_jsx_import_source(&self) -> Option<String> {
|
||||
self.maybe_default_jsx_import_source.clone()
|
||||
}
|
||||
|
||||
fn default_jsx_import_source_types(&self) -> Option<String> {
|
||||
self.maybe_default_jsx_import_source_types.clone()
|
||||
}
|
||||
|
||||
fn jsx_import_source_module(&self) -> &str {
|
||||
self
|
||||
.maybe_jsx_import_source_module
|
||||
.as_deref()
|
||||
.unwrap_or(DEFAULT_JSX_IMPORT_SOURCE_MODULE)
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
pub fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer_range: &deno_graph::Range,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: ResolutionMode,
|
||||
) -> Result<ModuleSpecifier, ResolveError> {
|
||||
fn to_node_mode(mode: ResolutionMode) -> NodeResolutionMode {
|
||||
@ -686,7 +736,7 @@ impl Resolver for CliGraphResolver {
|
||||
if let Some(node_resolver) = self.node_resolver.as_ref() {
|
||||
if referrer.scheme() == "file" && node_resolver.in_npm_package(referrer) {
|
||||
return node_resolver
|
||||
.resolve(raw_specifier, referrer, to_node_mode(mode))
|
||||
.resolve(raw_specifier, referrer, referrer_kind, to_node_mode(mode))
|
||||
.map(|res| res.into_url())
|
||||
.map_err(|e| ResolveError::Other(e.into()));
|
||||
}
|
||||
@ -759,6 +809,7 @@ impl Resolver for CliGraphResolver {
|
||||
pkg_json.dir_path(),
|
||||
sub_path.as_deref(),
|
||||
Some(referrer),
|
||||
referrer_kind,
|
||||
to_node_mode(mode),
|
||||
)
|
||||
.map_err(|e| ResolveError::Other(e.into())),
|
||||
@ -800,6 +851,7 @@ impl Resolver for CliGraphResolver {
|
||||
pkg_folder,
|
||||
sub_path.as_deref(),
|
||||
Some(referrer),
|
||||
referrer_kind,
|
||||
to_node_mode(mode),
|
||||
)
|
||||
.map_err(|e| ResolveError::Other(e.into()))
|
||||
@ -847,6 +899,7 @@ impl Resolver for CliGraphResolver {
|
||||
pkg_folder,
|
||||
npm_req_ref.sub_path(),
|
||||
Some(referrer),
|
||||
referrer_kind,
|
||||
to_node_mode(mode),
|
||||
)
|
||||
.map_err(|e| ResolveError::Other(e.into()));
|
||||
@ -855,7 +908,12 @@ impl Resolver for CliGraphResolver {
|
||||
// do npm resolution for byonm
|
||||
if is_byonm {
|
||||
return node_resolver
|
||||
.resolve_req_reference(&npm_req_ref, referrer, to_node_mode(mode))
|
||||
.resolve_req_reference(
|
||||
&npm_req_ref,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
to_node_mode(mode),
|
||||
)
|
||||
.map_err(|err| err.into());
|
||||
}
|
||||
}
|
||||
@ -869,7 +927,12 @@ impl Resolver for CliGraphResolver {
|
||||
// If byonm, check if the bare specifier resolves to an npm package
|
||||
if is_byonm && referrer.scheme() == "file" {
|
||||
let maybe_resolution = node_resolver
|
||||
.resolve_if_for_npm_pkg(raw_specifier, referrer, to_node_mode(mode))
|
||||
.resolve_if_for_npm_pkg(
|
||||
raw_specifier,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
to_node_mode(mode),
|
||||
)
|
||||
.map_err(ResolveError::Other)?;
|
||||
if let Some(res) = maybe_resolution {
|
||||
match res {
|
||||
|
@ -528,7 +528,6 @@
|
||||
"bare-node-builtins",
|
||||
"byonm",
|
||||
"cron",
|
||||
"detect-cjs",
|
||||
"ffi",
|
||||
"fs",
|
||||
"fmt-component",
|
||||
|
@ -720,7 +720,6 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
||||
unstable_config: UnstableConfig {
|
||||
legacy_flag_enabled: false,
|
||||
bare_node_builtins: cli_options.unstable_bare_node_builtins(),
|
||||
detect_cjs: cli_options.unstable_detect_cjs(),
|
||||
sloppy_imports: cli_options.unstable_sloppy_imports(),
|
||||
features: cli_options.unstable_features(),
|
||||
},
|
||||
|
@ -45,6 +45,8 @@ use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use import_map::parse_from_json;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use serialization::DenoCompileModuleSource;
|
||||
use std::borrow::Cow;
|
||||
@ -76,9 +78,9 @@ use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::CreateInNpmPkgCheckerOptions;
|
||||
use crate::resolver::CjsTracker;
|
||||
use crate::resolver::CjsTrackerOptions;
|
||||
use crate::resolver::CliDenoResolverFs;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::IsCjsResolverOptions;
|
||||
use crate::resolver::NpmModuleLoader;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
@ -146,13 +148,27 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||
type_error(format!("Referrer uses invalid specifier: {}", err))
|
||||
})?
|
||||
};
|
||||
let referrer_kind = if self
|
||||
.shared
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(&referrer, MediaType::from_specifier(&referrer))?
|
||||
{
|
||||
NodeModuleKind::Cjs
|
||||
} else {
|
||||
NodeModuleKind::Esm
|
||||
};
|
||||
|
||||
if self.shared.node_resolver.in_npm_package(&referrer) {
|
||||
return Ok(
|
||||
self
|
||||
.shared
|
||||
.node_resolver
|
||||
.resolve(raw_specifier, &referrer, NodeResolutionMode::Execution)?
|
||||
.resolve(
|
||||
raw_specifier,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Execution,
|
||||
)?
|
||||
.into_url(),
|
||||
);
|
||||
}
|
||||
@ -178,6 +194,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||
pkg_json.dir_path(),
|
||||
sub_path.as_deref(),
|
||||
Some(&referrer),
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Execution,
|
||||
)?,
|
||||
),
|
||||
@ -192,6 +209,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||
req,
|
||||
sub_path.as_deref(),
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Execution,
|
||||
)
|
||||
}
|
||||
@ -211,6 +229,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||
pkg_folder,
|
||||
sub_path.as_deref(),
|
||||
Some(&referrer),
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Execution,
|
||||
)?,
|
||||
)
|
||||
@ -224,6 +243,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||
return self.shared.node_resolver.resolve_req_reference(
|
||||
&reference,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Execution,
|
||||
);
|
||||
}
|
||||
@ -250,6 +270,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||
let maybe_res = self.shared.node_resolver.resolve_if_for_npm_pkg(
|
||||
raw_specifier,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Execution,
|
||||
)?;
|
||||
if let Some(res) = maybe_res {
|
||||
@ -429,6 +450,14 @@ impl NodeRequireLoader for EmbeddedModuleLoader {
|
||||
) -> Result<String, AnyError> {
|
||||
Ok(self.shared.fs.read_text_file_lossy_sync(path, None)?)
|
||||
}
|
||||
|
||||
fn is_maybe_cjs(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<bool, ClosestPkgJsonError> {
|
||||
let media_type = MediaType::from_specifier(specifier);
|
||||
self.shared.cjs_tracker.is_maybe_cjs(specifier, media_type)
|
||||
}
|
||||
}
|
||||
|
||||
struct StandaloneModuleLoaderFactory {
|
||||
@ -628,14 +657,14 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
|
||||
let cjs_tracker = Arc::new(CjsTracker::new(
|
||||
in_npm_pkg_checker.clone(),
|
||||
pkg_json_resolver.clone(),
|
||||
CjsTrackerOptions {
|
||||
unstable_detect_cjs: metadata.unstable_config.detect_cjs,
|
||||
IsCjsResolverOptions {
|
||||
detect_cjs: !metadata.workspace_resolver.package_jsons.is_empty(),
|
||||
is_node_main: false,
|
||||
},
|
||||
));
|
||||
let cache_db = Caches::new(deno_dir_provider.clone());
|
||||
let node_analysis_cache = NodeAnalysisCache::new(cache_db.node_analysis_db());
|
||||
let cli_node_resolver = Arc::new(CliNodeResolver::new(
|
||||
cjs_tracker.clone(),
|
||||
fs.clone(),
|
||||
in_npm_pkg_checker.clone(),
|
||||
node_resolver.clone(),
|
||||
@ -646,7 +675,6 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
|
||||
cjs_tracker.clone(),
|
||||
fs.clone(),
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let node_code_translator = Arc::new(NodeCodeTranslator::new(
|
||||
cjs_esm_code_analyzer,
|
||||
|
@ -480,7 +480,7 @@ fn filter_coverages(
|
||||
.filter(|e| {
|
||||
let is_internal = e.url.starts_with("ext:")
|
||||
|| e.url.ends_with("__anonymous__")
|
||||
|| e.url.ends_with("$deno$test.js")
|
||||
|| e.url.ends_with("$deno$test.mjs")
|
||||
|| e.url.ends_with(".snap")
|
||||
|| is_supported_test_path(Path::new(e.url.as_str()))
|
||||
|| doc_test_re.is_match(e.url.as_str())
|
||||
|
@ -1396,6 +1396,7 @@ mod tests {
|
||||
.env_clear()
|
||||
// use the deno binary in the target directory
|
||||
.env("PATH", test_util::target_dir())
|
||||
.env("RUST_BACKTRACE", "1")
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait()
|
||||
|
@ -61,7 +61,7 @@ pub async fn kernel(
|
||||
let factory = CliFactory::from_flags(flags);
|
||||
let cli_options = factory.cli_options()?;
|
||||
let main_module =
|
||||
resolve_url_or_path("./$deno$jupyter.ts", cli_options.initial_cwd())
|
||||
resolve_url_or_path("./$deno$jupyter.mts", cli_options.initial_cwd())
|
||||
.unwrap();
|
||||
// TODO(bartlomieju): should we run with all permissions?
|
||||
let permissions =
|
||||
|
@ -63,7 +63,7 @@ pub use rules::LintRuleProvider;
|
||||
|
||||
const JSON_SCHEMA_VERSION: u8 = 1;
|
||||
|
||||
static STDIN_FILE_NAME: &str = "$deno$stdin.ts";
|
||||
static STDIN_FILE_NAME: &str = "$deno$stdin.mts";
|
||||
|
||||
pub async fn lint(
|
||||
flags: Arc<Flags>,
|
||||
|
@ -87,6 +87,7 @@ impl LintRule for NoSloppyImportsRule {
|
||||
captures: Default::default(),
|
||||
};
|
||||
|
||||
// fill this and capture the sloppy imports in the resolver
|
||||
deno_graph::parse_module_from_ast(deno_graph::ParseModuleFromAstOptions {
|
||||
graph_kind: deno_graph::GraphKind::All,
|
||||
specifier: context.specifier().clone(),
|
||||
|
@ -7,7 +7,7 @@ use crate::cdp;
|
||||
use crate::colors;
|
||||
use crate::lsp::ReplLanguageServer;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::tools::test::report_tests;
|
||||
use crate::tools::test::reporters::PrettyTestReporter;
|
||||
use crate::tools::test::reporters::TestReporter;
|
||||
@ -44,12 +44,12 @@ use deno_core::url::Url;
|
||||
use deno_core::LocalInspectorSession;
|
||||
use deno_core::PollEventLoopOptions;
|
||||
use deno_graph::source::ResolutionMode;
|
||||
use deno_graph::source::Resolver;
|
||||
use deno_graph::Position;
|
||||
use deno_graph::PositionRange;
|
||||
use deno_graph::SpecifierWithRange;
|
||||
use deno_runtime::worker::MainWorker;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Match;
|
||||
use regex::Regex;
|
||||
@ -180,7 +180,7 @@ struct ReplJsxState {
|
||||
|
||||
pub struct ReplSession {
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
pub worker: MainWorker,
|
||||
session: LocalInspectorSession,
|
||||
pub context_id: u64,
|
||||
@ -199,7 +199,7 @@ impl ReplSession {
|
||||
pub async fn initialize(
|
||||
cli_options: &CliOptions,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<CliResolver>,
|
||||
mut worker: MainWorker,
|
||||
main_module: ModuleSpecifier,
|
||||
test_event_receiver: TestEventReceiver,
|
||||
@ -245,7 +245,7 @@ impl ReplSession {
|
||||
assert_ne!(context_id, 0);
|
||||
|
||||
let referrer =
|
||||
deno_core::resolve_path("./$deno$repl.ts", cli_options.initial_cwd())
|
||||
deno_core::resolve_path("./$deno$repl.mts", cli_options.initial_cwd())
|
||||
.unwrap();
|
||||
|
||||
let cwd_url =
|
||||
@ -712,7 +712,12 @@ impl ReplSession {
|
||||
.flat_map(|i| {
|
||||
self
|
||||
.resolver
|
||||
.resolve(i, &referrer_range, ResolutionMode::Execution)
|
||||
.resolve(
|
||||
i,
|
||||
&referrer_range,
|
||||
NodeModuleKind::Esm,
|
||||
ResolutionMode::Execution,
|
||||
)
|
||||
.ok()
|
||||
.or_else(|| ModuleSpecifier::parse(i).ok())
|
||||
})
|
||||
|
@ -4,8 +4,6 @@ use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ModuleKind;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::StreamExt;
|
||||
@ -18,7 +16,6 @@ use tokio::select;
|
||||
|
||||
use crate::cdp;
|
||||
use crate::emit::Emitter;
|
||||
use crate::resolver::CjsTracker;
|
||||
use crate::util::file_watcher::WatcherCommunicator;
|
||||
use crate::util::file_watcher::WatcherRestartMode;
|
||||
|
||||
@ -63,7 +60,6 @@ pub struct HmrRunner {
|
||||
session: LocalInspectorSession,
|
||||
watcher_communicator: Arc<WatcherCommunicator>,
|
||||
script_ids: HashMap<String, String>,
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
emitter: Arc<Emitter>,
|
||||
}
|
||||
|
||||
@ -146,7 +142,6 @@ impl crate::worker::HmrRunner for HmrRunner {
|
||||
|
||||
let source_code = self.emitter.load_and_emit_for_hmr(
|
||||
&module_url,
|
||||
ModuleKind::from_is_cjs(self.cjs_tracker.is_maybe_cjs(&module_url, MediaType::from_specifier(&module_url))?),
|
||||
).await?;
|
||||
|
||||
let mut tries = 1;
|
||||
@ -179,14 +174,12 @@ impl crate::worker::HmrRunner for HmrRunner {
|
||||
|
||||
impl HmrRunner {
|
||||
pub fn new(
|
||||
cjs_tracker: Arc<CjsTracker>,
|
||||
emitter: Arc<Emitter>,
|
||||
session: LocalInspectorSession,
|
||||
watcher_communicator: Arc<WatcherCommunicator>,
|
||||
) -> Self {
|
||||
Self {
|
||||
session,
|
||||
cjs_tracker,
|
||||
emitter,
|
||||
watcher_communicator,
|
||||
script_ids: HashMap::new(),
|
||||
|
@ -121,8 +121,8 @@ delete Object.prototype.__proto__;
|
||||
/** @type {Map<string, ts.SourceFile>} */
|
||||
const sourceFileCache = new Map();
|
||||
|
||||
/** @type {Map<string, string>} */
|
||||
const sourceTextCache = new Map();
|
||||
/** @type {Map<string, ts.IScriptSnapshot & { isCjs?: boolean; }>} */
|
||||
const scriptSnapshotCache = new Map();
|
||||
|
||||
/** @type {Map<string, number>} */
|
||||
const sourceRefCounts = new Map();
|
||||
@ -133,9 +133,6 @@ delete Object.prototype.__proto__;
|
||||
/** @type {Map<string, boolean>} */
|
||||
const isNodeSourceFileCache = new Map();
|
||||
|
||||
/** @type {Map<string, boolean>} */
|
||||
const isCjsCache = new Map();
|
||||
|
||||
// Maps asset specifiers to the first scope that the asset was loaded into.
|
||||
/** @type {Map<string, string | null>} */
|
||||
const assetScopes = new Map();
|
||||
@ -210,12 +207,13 @@ delete Object.prototype.__proto__;
|
||||
const mapKey = path + key;
|
||||
let sourceFile = documentRegistrySourceFileCache.get(mapKey);
|
||||
if (!sourceFile || sourceFile.version !== version) {
|
||||
const isCjs = /** @type {any} */ (scriptSnapshot).isCjs;
|
||||
sourceFile = ts.createLanguageServiceSourceFile(
|
||||
fileName,
|
||||
scriptSnapshot,
|
||||
{
|
||||
...getCreateSourceFileOptions(sourceFileOptions),
|
||||
impliedNodeFormat: (isCjsCache.get(fileName) ?? false)
|
||||
impliedNodeFormat: isCjs
|
||||
? ts.ModuleKind.CommonJS
|
||||
: ts.ModuleKind.ESNext,
|
||||
// in the lsp we want to be able to show documentation
|
||||
@ -320,7 +318,7 @@ delete Object.prototype.__proto__;
|
||||
if (lastRequestMethod != "cleanupSemanticCache") {
|
||||
const mapKey = path + key;
|
||||
documentRegistrySourceFileCache.delete(mapKey);
|
||||
sourceTextCache.delete(path);
|
||||
scriptSnapshotCache.delete(path);
|
||||
ops.op_release(path);
|
||||
}
|
||||
} else {
|
||||
@ -624,8 +622,6 @@ delete Object.prototype.__proto__;
|
||||
`"data" is unexpectedly null for "${specifier}".`,
|
||||
);
|
||||
|
||||
isCjsCache.set(specifier, isCjs);
|
||||
|
||||
sourceFile = ts.createSourceFile(
|
||||
specifier,
|
||||
data,
|
||||
@ -699,7 +695,7 @@ delete Object.prototype.__proto__;
|
||||
/** @type {[string, ts.Extension] | undefined} */
|
||||
const resolved = ops.op_resolve(
|
||||
containingFilePath,
|
||||
isCjsCache.get(containingFilePath) ?? false,
|
||||
containingFileMode === ts.ModuleKind.CommonJS,
|
||||
[fileReference.fileName],
|
||||
)?.[0];
|
||||
if (resolved) {
|
||||
@ -723,7 +719,14 @@ delete Object.prototype.__proto__;
|
||||
}
|
||||
});
|
||||
},
|
||||
resolveModuleNames(specifiers, base) {
|
||||
resolveModuleNames(
|
||||
specifiers,
|
||||
base,
|
||||
_reusedNames,
|
||||
_redirectedReference,
|
||||
_options,
|
||||
containingSourceFile,
|
||||
) {
|
||||
if (logDebug) {
|
||||
debug(`host.resolveModuleNames()`);
|
||||
debug(` base: ${base}`);
|
||||
@ -732,7 +735,7 @@ delete Object.prototype.__proto__;
|
||||
/** @type {Array<[string, ts.Extension] | undefined>} */
|
||||
const resolved = ops.op_resolve(
|
||||
base,
|
||||
isCjsCache.get(base) ?? false,
|
||||
containingSourceFile?.impliedNodeFormat === ts.ModuleKind.CommonJS,
|
||||
specifiers,
|
||||
);
|
||||
if (resolved) {
|
||||
@ -814,19 +817,19 @@ delete Object.prototype.__proto__;
|
||||
return ts.ScriptSnapshot.fromString(sourceFile.text);
|
||||
}
|
||||
}
|
||||
let sourceText = sourceTextCache.get(specifier);
|
||||
if (sourceText == undefined) {
|
||||
let scriptSnapshot = scriptSnapshotCache.get(specifier);
|
||||
if (scriptSnapshot == undefined) {
|
||||
/** @type {{ data: string, version: string, isCjs: boolean }} */
|
||||
const fileInfo = ops.op_load(specifier);
|
||||
if (!fileInfo) {
|
||||
return undefined;
|
||||
}
|
||||
isCjsCache.set(specifier, fileInfo.isCjs);
|
||||
sourceTextCache.set(specifier, fileInfo.data);
|
||||
scriptSnapshot = ts.ScriptSnapshot.fromString(fileInfo.data);
|
||||
scriptSnapshot.isCjs = fileInfo.isCjs;
|
||||
scriptSnapshotCache.set(specifier, scriptSnapshot);
|
||||
scriptVersionCache.set(specifier, fileInfo.version);
|
||||
sourceText = fileInfo.data;
|
||||
}
|
||||
return ts.ScriptSnapshot.fromString(sourceText);
|
||||
return scriptSnapshot;
|
||||
},
|
||||
};
|
||||
|
||||
@ -1238,7 +1241,7 @@ delete Object.prototype.__proto__;
|
||||
closed = true;
|
||||
}
|
||||
scriptVersionCache.delete(script);
|
||||
sourceTextCache.delete(script);
|
||||
scriptSnapshotCache.delete(script);
|
||||
}
|
||||
|
||||
if (newConfigsByScope || opened || closed) {
|
||||
|
@ -343,31 +343,36 @@ impl TypeCheckingCjsTracker {
|
||||
media_type: MediaType,
|
||||
code: &Arc<str>,
|
||||
) -> bool {
|
||||
if let Some(module_kind) =
|
||||
self.cjs_tracker.get_known_kind(specifier, media_type)
|
||||
{
|
||||
module_kind.is_cjs()
|
||||
} else {
|
||||
let maybe_is_script = self
|
||||
.module_info_cache
|
||||
.as_module_analyzer()
|
||||
.analyze_sync(specifier, media_type, code)
|
||||
.ok()
|
||||
.map(|info| info.is_script);
|
||||
maybe_is_script
|
||||
.and_then(|is_script| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_cjs_with_known_is_script(specifier, media_type, is_script)
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(specifier, media_type)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
}
|
||||
let maybe_is_script = self
|
||||
.module_info_cache
|
||||
.as_module_analyzer()
|
||||
.analyze_sync(specifier, media_type, code)
|
||||
.ok()
|
||||
.map(|info| info.is_script);
|
||||
maybe_is_script
|
||||
.and_then(|is_script| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_cjs_with_known_is_script(specifier, media_type, is_script)
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_maybe_cjs(specifier, media_type)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_cjs_with_known_is_script(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
media_type: MediaType,
|
||||
is_script: bool,
|
||||
) -> Result<bool, node_resolver::errors::ClosestPkgJsonError> {
|
||||
self
|
||||
.cjs_tracker
|
||||
.is_cjs_with_known_is_script(specifier, media_type, is_script)
|
||||
}
|
||||
}
|
||||
|
||||
@ -627,8 +632,12 @@ fn op_load_inner(
|
||||
match module {
|
||||
Module::Js(module) => {
|
||||
media_type = module.media_type;
|
||||
if matches!(media_type, MediaType::Cjs | MediaType::Cts) {
|
||||
is_cjs = true;
|
||||
if let Some(npm_state) = &state.maybe_npm {
|
||||
is_cjs = npm_state.cjs_tracker.is_cjs_with_known_is_script(
|
||||
specifier,
|
||||
module.media_type,
|
||||
module.is_script,
|
||||
)?;
|
||||
}
|
||||
let source = module
|
||||
.fast_check_module()
|
||||
@ -737,6 +746,7 @@ fn op_resolve_inner(
|
||||
"Error converting a string module specifier for \"op_resolve\".",
|
||||
)?
|
||||
};
|
||||
let referrer_module = state.graph.get(&referrer);
|
||||
for specifier in args.specifiers {
|
||||
if specifier.starts_with("node:") {
|
||||
resolved.push((
|
||||
@ -752,16 +762,19 @@ fn op_resolve_inner(
|
||||
continue;
|
||||
}
|
||||
|
||||
let graph = &state.graph;
|
||||
let resolved_dep = graph
|
||||
.get(&referrer)
|
||||
let resolved_dep = referrer_module
|
||||
.and_then(|m| m.js())
|
||||
.and_then(|m| m.dependencies_prefer_fast_check().get(&specifier))
|
||||
.and_then(|d| d.maybe_type.ok().or_else(|| d.maybe_code.ok()));
|
||||
|
||||
let maybe_result = match resolved_dep {
|
||||
Some(ResolutionResolved { specifier, .. }) => {
|
||||
resolve_graph_specifier_types(specifier, &referrer, state)?
|
||||
resolve_graph_specifier_types(
|
||||
specifier,
|
||||
&referrer,
|
||||
referrer_kind,
|
||||
state,
|
||||
)?
|
||||
}
|
||||
_ => {
|
||||
match resolve_non_graph_specifier_types(
|
||||
@ -834,6 +847,7 @@ fn op_resolve_inner(
|
||||
fn resolve_graph_specifier_types(
|
||||
specifier: &ModuleSpecifier,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_kind: NodeModuleKind,
|
||||
state: &State,
|
||||
) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> {
|
||||
let graph = &state.graph;
|
||||
@ -886,6 +900,7 @@ fn resolve_graph_specifier_types(
|
||||
&package_folder,
|
||||
module.nv_reference.sub_path(),
|
||||
Some(referrer),
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Types,
|
||||
);
|
||||
let maybe_url = match res_result {
|
||||
@ -965,6 +980,7 @@ fn resolve_non_graph_specifier_types(
|
||||
&package_folder,
|
||||
npm_req_ref.sub_path(),
|
||||
Some(referrer),
|
||||
referrer_kind,
|
||||
NodeResolutionMode::Types,
|
||||
);
|
||||
let maybe_url = match res_result {
|
||||
|
@ -44,6 +44,7 @@ use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_terminal::colors;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use tokio::select;
|
||||
|
||||
@ -680,6 +681,7 @@ impl CliMainWorkerFactory {
|
||||
package_folder,
|
||||
sub_path,
|
||||
/* referrer */ None,
|
||||
NodeModuleKind::Esm,
|
||||
NodeResolutionMode::Execution,
|
||||
)?;
|
||||
if specifier
|
||||
|
@ -14,6 +14,7 @@ use deno_core::url::Url;
|
||||
#[allow(unused_imports)]
|
||||
use deno_core::v8;
|
||||
use deno_core::v8::ExternalReference;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::NpmResolverRc;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
@ -157,6 +158,10 @@ pub trait NodeRequireLoader {
|
||||
) -> Result<Cow<'a, Path>, AnyError>;
|
||||
|
||||
fn load_text_file_lossy(&self, path: &Path) -> Result<String, AnyError>;
|
||||
|
||||
/// Get if the module kind is maybe CJS and loading should determine
|
||||
/// if its CJS or ESM.
|
||||
fn is_maybe_cjs(&self, specifier: &Url) -> Result<bool, ClosestPkgJsonError>;
|
||||
}
|
||||
|
||||
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
@ -385,6 +390,7 @@ deno_core::extension!(deno_node,
|
||||
ops::require::op_require_proxy_path,
|
||||
ops::require::op_require_is_deno_dir_package,
|
||||
ops::require::op_require_resolve_deno_dir,
|
||||
ops::require::op_require_is_maybe_cjs,
|
||||
ops::require::op_require_is_request_relative,
|
||||
ops::require::op_require_resolve_lookup_paths,
|
||||
ops::require::op_require_try_self_parent_path<P>,
|
||||
@ -398,7 +404,6 @@ deno_core::extension!(deno_node,
|
||||
ops::require::op_require_read_file<P>,
|
||||
ops::require::op_require_as_file_path,
|
||||
ops::require::op_require_resolve_exports<P>,
|
||||
ops::require::op_require_read_closest_package_json<P>,
|
||||
ops::require::op_require_read_package_scope<P>,
|
||||
ops::require::op_require_package_imports_resolve<P>,
|
||||
ops::require::op_require_break_on_next_statement,
|
||||
|
@ -1,16 +1,18 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op2;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::v8;
|
||||
use deno_core::JsRuntimeInspector;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_fs::FileSystemRc;
|
||||
use deno_package_json::NodeModuleKind;
|
||||
use deno_package_json::PackageJsonRc;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_path_util::url_from_file_path;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use node_resolver::REQUIRE_CONDITIONS;
|
||||
use std::borrow::Cow;
|
||||
@ -217,17 +219,17 @@ pub fn op_require_resolve_deno_dir(
|
||||
state: &mut OpState,
|
||||
#[string] request: String,
|
||||
#[string] parent_filename: String,
|
||||
) -> Option<String> {
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
let resolver = state.borrow::<NpmResolverRc>();
|
||||
resolver
|
||||
.resolve_package_folder_from_package(
|
||||
&request,
|
||||
&ModuleSpecifier::from_file_path(&parent_filename).unwrap_or_else(|_| {
|
||||
panic!("Url::from_file_path: [{:?}]", parent_filename)
|
||||
}),
|
||||
)
|
||||
.ok()
|
||||
.map(|p| p.to_string_lossy().into_owned())
|
||||
Ok(
|
||||
resolver
|
||||
.resolve_package_folder_from_package(
|
||||
&request,
|
||||
&url_from_file_path(&PathBuf::from(parent_filename))?,
|
||||
)
|
||||
.ok()
|
||||
.map(|p| p.to_string_lossy().into_owned()),
|
||||
)
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
@ -564,19 +566,17 @@ where
|
||||
}))
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_require_read_closest_package_json<P>(
|
||||
#[op2(fast)]
|
||||
pub fn op_require_is_maybe_cjs(
|
||||
state: &mut OpState,
|
||||
#[string] filename: String,
|
||||
) -> Result<Option<PackageJsonRc>, node_resolver::errors::ClosestPkgJsonError>
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
) -> Result<bool, ClosestPkgJsonError> {
|
||||
let filename = PathBuf::from(filename);
|
||||
// permissions: allow reading the closest package.json files
|
||||
let pkg_json_resolver = state.borrow::<PackageJsonResolverRc>();
|
||||
pkg_json_resolver.get_closest_package_json_from_path(&filename)
|
||||
let Ok(url) = url_from_file_path(&filename) else {
|
||||
return Ok(false);
|
||||
};
|
||||
let loader = state.borrow::<NodeRequireLoaderRc>();
|
||||
loader.is_maybe_cjs(&url)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
op_require_can_parse_as_esm,
|
||||
op_require_init_paths,
|
||||
op_require_is_deno_dir_package,
|
||||
op_require_is_maybe_cjs,
|
||||
op_require_is_request_relative,
|
||||
op_require_node_module_paths,
|
||||
op_require_package_imports_resolve,
|
||||
@ -19,7 +20,6 @@ import {
|
||||
op_require_path_is_absolute,
|
||||
op_require_path_resolve,
|
||||
op_require_proxy_path,
|
||||
op_require_read_closest_package_json,
|
||||
op_require_read_file,
|
||||
op_require_read_package_scope,
|
||||
op_require_real_path,
|
||||
@ -1060,36 +1060,13 @@ Module.prototype._compile = function (content, filename, format) {
|
||||
return result;
|
||||
};
|
||||
|
||||
Module._extensions[".js"] = function (module, filename) {
|
||||
const content = op_require_read_file(filename);
|
||||
|
||||
let format;
|
||||
if (StringPrototypeEndsWith(filename, ".js")) {
|
||||
const pkg = op_require_read_closest_package_json(filename);
|
||||
if (pkg?.type === "module") {
|
||||
format = "module";
|
||||
} else if (pkg?.type === "commonjs") {
|
||||
format = "commonjs";
|
||||
}
|
||||
}
|
||||
|
||||
module._compile(content, filename, format);
|
||||
};
|
||||
|
||||
Module._extensions[".ts"] =
|
||||
Module._extensions[".js"] =
|
||||
Module._extensions[".ts"] =
|
||||
Module._extensions[".jsx"] =
|
||||
Module._extensions[".tsx"] =
|
||||
function (module, filename) {
|
||||
const content = op_require_read_file(filename);
|
||||
|
||||
let format;
|
||||
const pkg = op_require_read_closest_package_json(filename);
|
||||
if (pkg?.type === "module") {
|
||||
format = "module";
|
||||
} else if (pkg?.type === "commonjs") {
|
||||
format = "commonjs";
|
||||
}
|
||||
|
||||
const format = op_require_is_maybe_cjs(filename) ? undefined : "module";
|
||||
module._compile(content, filename, format);
|
||||
};
|
||||
|
||||
|
@ -919,7 +919,7 @@ Object.defineProperty(argv, "1", {
|
||||
if (Deno.mainModule?.startsWith("file:")) {
|
||||
return pathFromURL(new URL(Deno.mainModule));
|
||||
} else {
|
||||
return join(Deno.cwd(), "$deno$node.js");
|
||||
return join(Deno.cwd(), "$deno$node.mjs");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -15,8 +15,8 @@ use crate::errors::CanonicalizingPkgJsonDirError;
|
||||
use crate::errors::ClosestPkgJsonError;
|
||||
use crate::errors::PackageJsonLoadError;
|
||||
|
||||
// todo(dsherret): this isn't exactly correct and we should change it to instead
|
||||
// be created per worker and passed down as a ctor arg to the pkg json resolver
|
||||
// it would be nice if this was passed down as a ctor arg to the package.json resolver,
|
||||
// but it's a little bit complicated to do that, so we just maintain a thread local cache
|
||||
thread_local! {
|
||||
static CACHE: RefCell<HashMap<PathBuf, PackageJsonRc>> = RefCell::new(HashMap::new());
|
||||
}
|
||||
|
@ -50,6 +50,15 @@ pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"];
|
||||
pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"];
|
||||
static TYPES_ONLY_CONDITIONS: &[&str] = &["types"];
|
||||
|
||||
fn conditions_from_module_kind(
|
||||
kind: NodeModuleKind,
|
||||
) -> &'static [&'static str] {
|
||||
match kind {
|
||||
NodeModuleKind::Esm => DEFAULT_CONDITIONS,
|
||||
NodeModuleKind::Cjs => REQUIRE_CONDITIONS,
|
||||
}
|
||||
}
|
||||
|
||||
pub type NodeModuleKind = deno_package_json::NodeModuleKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -166,8 +175,7 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
|
||||
specifier,
|
||||
referrer,
|
||||
referrer_kind,
|
||||
// even though the referrer may be CJS, if we're here that means we're doing ESM resolution
|
||||
DEFAULT_CONDITIONS,
|
||||
conditions_from_module_kind(referrer_kind),
|
||||
mode,
|
||||
)?;
|
||||
|
||||
@ -299,9 +307,9 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
|
||||
package_dir: &Path,
|
||||
package_subpath: Option<&str>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<Url, PackageSubpathResolveError> {
|
||||
let node_module_kind = NodeModuleKind::Esm;
|
||||
let package_subpath = package_subpath
|
||||
.map(|s| format!("./{s}"))
|
||||
.unwrap_or_else(|| ".".to_string());
|
||||
@ -309,8 +317,8 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
|
||||
package_dir,
|
||||
&package_subpath,
|
||||
maybe_referrer,
|
||||
node_module_kind,
|
||||
DEFAULT_CONDITIONS,
|
||||
referrer_kind,
|
||||
conditions_from_module_kind(referrer_kind),
|
||||
mode,
|
||||
)?;
|
||||
// TODO(bartlomieju): skipped checking errors for commonJS resolution and
|
||||
@ -441,10 +449,7 @@ impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
|
||||
/* sub path */ ".",
|
||||
maybe_referrer,
|
||||
referrer_kind,
|
||||
match referrer_kind {
|
||||
NodeModuleKind::Esm => DEFAULT_CONDITIONS,
|
||||
NodeModuleKind::Cjs => REQUIRE_CONDITIONS,
|
||||
},
|
||||
conditions_from_module_kind(referrer_kind),
|
||||
NodeResolutionMode::Types,
|
||||
);
|
||||
if let Ok(resolution) = resolution_result {
|
||||
|
@ -310,14 +310,13 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec<FixSuggestion> {
|
||||
{
|
||||
return vec![
|
||||
FixSuggestion::info_multiline(&[
|
||||
cstr!("Deno supports CommonJS modules in <u>.cjs</> files, or when there's a <u>package.json</>"),
|
||||
cstr!("with <i>\"type\": \"commonjs\"</> option and <i>--unstable-detect-cjs</> flag is used.")
|
||||
cstr!("Deno supports CommonJS modules in <u>.cjs</> files, or when the closest"),
|
||||
cstr!("<u>package.json</> has a <i>\"type\": \"commonjs\"</> option.")
|
||||
]),
|
||||
FixSuggestion::hint_multiline(&[
|
||||
"Rewrite this module to ESM,",
|
||||
cstr!("or change the file extension to <u>.cjs</u>,"),
|
||||
cstr!("or add <u>package.json</> next to the file with <i>\"type\": \"commonjs\"</> option"),
|
||||
cstr!("and pass <i>--unstable-detect-cjs</> flag."),
|
||||
cstr!("or add <u>package.json</> next to the file with <i>\"type\": \"commonjs\"</> option."),
|
||||
]),
|
||||
FixSuggestion::docs("https://docs.deno.com/go/commonjs"),
|
||||
];
|
||||
|
@ -393,6 +393,13 @@ pub struct WebWorker {
|
||||
maybe_worker_metadata: Option<WorkerMetadata>,
|
||||
}
|
||||
|
||||
impl Drop for WebWorker {
|
||||
fn drop(&mut self) {
|
||||
// clean up the package.json thread local cache
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl WebWorker {
|
||||
pub fn bootstrap_from_options(
|
||||
services: WebWorkerServiceOptions,
|
||||
|
@ -16139,6 +16139,55 @@ fn lsp_cjs_import_dual() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_type_commonjs() {
|
||||
let context = TestContextBuilder::new()
|
||||
.use_http_server()
|
||||
.use_temp_cwd()
|
||||
.add_npm_env_vars()
|
||||
.build();
|
||||
let temp_dir = context.temp_dir();
|
||||
temp_dir.write("deno.json", r#"{}"#);
|
||||
temp_dir.write(
|
||||
"package.json",
|
||||
r#"{
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"@denotest/dual-cjs-esm": "1"
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
context.run_npm("install");
|
||||
|
||||
let mut client = context.new_lsp_command().build();
|
||||
client.initialize_default();
|
||||
let main_url = temp_dir.path().join("main.ts").url_file();
|
||||
let diagnostics = client.did_open(
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": main_url,
|
||||
"languageId": "typescript",
|
||||
"version": 1,
|
||||
// getKind() should resolve as "cjs" and cause a type checker error
|
||||
"text": "import mod = require('@denotest/dual-cjs-esm');\nconst kind: 'other' = mod.getKind(); console.log(kind);",
|
||||
}
|
||||
}),
|
||||
);
|
||||
assert_eq!(
|
||||
json!(diagnostics.all()),
|
||||
json!([{
|
||||
"range": {
|
||||
"start": { "line": 1, "character": 6, },
|
||||
"end": { "line": 1, "character": 10, },
|
||||
},
|
||||
"severity": 1,
|
||||
"code": 2322,
|
||||
"source": "deno-ts",
|
||||
"message": "Type '\"cjs\"' is not assignable to type '\"other\"'.",
|
||||
}])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_ts_code_fix_any_param() {
|
||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||
|
3
tests/node_compat/package.json
Normal file
3
tests/node_compat/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
@ -1 +0,0 @@
|
||||
{}
|
1
tests/node_compat/test/fixtures/package.json
vendored
1
tests/node_compat/test/fixtures/package.json
vendored
@ -1 +0,0 @@
|
||||
{}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -0,0 +1,12 @@
|
||||
const tempDir = Deno.makeTempDirSync();
|
||||
try {
|
||||
// should work requiring these because this was launched via a node binary entrypoint
|
||||
Deno.writeTextFileSync(`${tempDir}/index.js`, "module.exports = require('./other');");
|
||||
Deno.writeTextFileSync(`${tempDir}/other.js`, "module.exports = (a, b) => a + b;");
|
||||
const add = require(`${tempDir}/index.js`);
|
||||
if (add(1, 2) !== 3) {
|
||||
throw new Error("FAILED");
|
||||
}
|
||||
} finally {
|
||||
Deno.removeSync(tempDir, { recursive: true });
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@denotest/install-launch-cjs-temp-dir",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"install": "node install.js"
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
require("./output");
|
@ -0,0 +1 @@
|
||||
require("./output");
|
@ -0,0 +1 @@
|
||||
console.log("SUCCESS");
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@denotest/install-no-ext",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"install": "node install/check && node install"
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"unstable": [
|
||||
"detect-cjs"
|
||||
]
|
||||
}
|
4
tests/specs/eval/pkg_json_type_cjs/__test__.jsonc
Normal file
4
tests/specs/eval/pkg_json_type_cjs/__test__.jsonc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"args": "eval console.log(1)",
|
||||
"output": "1\n"
|
||||
}
|
3
tests/specs/eval/pkg_json_type_cjs/package.json
Normal file
3
tests/specs/eval/pkg_json_type_cjs/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"tempDir": true,
|
||||
"args": "install --allow-scripts",
|
||||
"output": "output.out"
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
Download http://localhost:4260/@denotest%2finstall-launch-cjs-temp-dir
|
||||
Download http://localhost:4260/@denotest/install-launch-cjs-temp-dir/1.0.0.tgz
|
||||
Initialize @denotest/install-launch-cjs-temp-dir@1.0.0
|
||||
Initialize @denotest/install-launch-cjs-temp-dir@1.0.0: running 'install' script
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@denotest/install-launch-cjs-temp-dir": "*"
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"tempDir": true,
|
||||
"args": "install --allow-scripts",
|
||||
"output": "output.out"
|
||||
}
|
4
tests/specs/install/scripts_install_no_ext/output.out
Normal file
4
tests/specs/install/scripts_install_no_ext/output.out
Normal file
@ -0,0 +1,4 @@
|
||||
Download http://localhost:4260/@denotest%2finstall-no-ext
|
||||
Download http://localhost:4260/@denotest/install-no-ext/1.0.0.tgz
|
||||
Initialize @denotest/install-no-ext@1.0.0
|
||||
Initialize @denotest/install-no-ext@1.0.0: running 'install' script
|
5
tests/specs/install/scripts_install_no_ext/package.json
Normal file
5
tests/specs/install/scripts_install_no_ext/package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@denotest/install-no-ext": "*"
|
||||
}
|
||||
}
|
@ -119,6 +119,9 @@ struct MultiStepMetaData {
|
||||
/// steps.
|
||||
#[serde(default)]
|
||||
pub temp_dir: bool,
|
||||
/// Whether the temporary directory should be symlinked to another path.
|
||||
#[serde(default)]
|
||||
pub symlinked_temp_dir: bool,
|
||||
/// The base environment to use for the test.
|
||||
#[serde(default)]
|
||||
pub base: Option<String>,
|
||||
@ -142,6 +145,8 @@ struct SingleTestMetaData {
|
||||
#[serde(default)]
|
||||
pub temp_dir: bool,
|
||||
#[serde(default)]
|
||||
pub symlinked_temp_dir: bool,
|
||||
#[serde(default)]
|
||||
pub repeat: Option<usize>,
|
||||
#[serde(flatten)]
|
||||
pub step: StepMetaData,
|
||||
@ -155,6 +160,7 @@ impl SingleTestMetaData {
|
||||
base: self.base,
|
||||
cwd: None,
|
||||
temp_dir: self.temp_dir,
|
||||
symlinked_temp_dir: self.symlinked_temp_dir,
|
||||
repeat: self.repeat,
|
||||
envs: Default::default(),
|
||||
steps: vec![self.step],
|
||||
@ -330,6 +336,20 @@ fn test_context_from_metadata(
|
||||
builder = builder.cwd(cwd.to_string_lossy());
|
||||
}
|
||||
|
||||
if metadata.symlinked_temp_dir {
|
||||
// not actually deprecated, we just want to discourage its use
|
||||
// because it's mostly used for testing purposes locally
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
builder = builder.use_symlinked_temp_dir();
|
||||
}
|
||||
if cfg!(not(debug_assertions)) {
|
||||
// panic to prevent using this on the CI as CI already uses
|
||||
// a symlinked temp directory for every test
|
||||
panic!("Cannot use symlinkedTempDir in release mode");
|
||||
}
|
||||
}
|
||||
|
||||
match &metadata.base {
|
||||
// todo(dsherret): add bases in the future as needed
|
||||
Some(base) => panic!("Unknown test base: {}", base),
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"args": "run -A --quiet dual_cjs_esm/main.ts",
|
||||
"output": "dual_cjs_esm/main.out"
|
||||
}
|
14
tests/specs/npm/dual_cjs_esm/cjs_referrer/__test__.jsonc
Normal file
14
tests/specs/npm/dual_cjs_esm/cjs_referrer/__test__.jsonc
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"tempDir": true,
|
||||
"tests": {
|
||||
"check": {
|
||||
"args": "check --node-modules-dir=auto main.cts",
|
||||
"output": "check.out",
|
||||
"exitCode": 1
|
||||
},
|
||||
"run": {
|
||||
"args": "run --node-modules-dir=auto --allow-read main.cts",
|
||||
"output": "main.out"
|
||||
}
|
||||
}
|
||||
}
|
8
tests/specs/npm/dual_cjs_esm/cjs_referrer/check.out
Normal file
8
tests/specs/npm/dual_cjs_esm/cjs_referrer/check.out
Normal file
@ -0,0 +1,8 @@
|
||||
Download http://localhost:4260/@denotest%2fdual-cjs-esm
|
||||
Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
|
||||
Initialize @denotest/dual-cjs-esm@1.0.0
|
||||
Check file:///[WILDLINE]/main.cts
|
||||
error: TS2322 [ERROR]: Type '"cjs"' is not assignable to type '"other"'.
|
||||
const kind: "other" = mod.getKind();
|
||||
~~~~
|
||||
at file:///[WILDLINE]/main.cts:3:7
|
4
tests/specs/npm/dual_cjs_esm/cjs_referrer/main.cts
Normal file
4
tests/specs/npm/dual_cjs_esm/cjs_referrer/main.cts
Normal file
@ -0,0 +1,4 @@
|
||||
import mod = require("@denotest/dual-cjs-esm");
|
||||
|
||||
const kind: "other" = mod.getKind();
|
||||
console.log(kind);
|
4
tests/specs/npm/dual_cjs_esm/cjs_referrer/main.out
Normal file
4
tests/specs/npm/dual_cjs_esm/cjs_referrer/main.out
Normal file
@ -0,0 +1,4 @@
|
||||
Download http://localhost:4260/@denotest%2fdual-cjs-esm
|
||||
Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
|
||||
Initialize @denotest/dual-cjs-esm@1.0.0
|
||||
cjs
|
5
tests/specs/npm/dual_cjs_esm/cjs_referrer/package.json
Normal file
5
tests/specs/npm/dual_cjs_esm/cjs_referrer/package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@denotest/dual-cjs-esm": "*"
|
||||
}
|
||||
}
|
4
tests/specs/npm/dual_cjs_esm/esm_referrer/__test__.jsonc
Normal file
4
tests/specs/npm/dual_cjs_esm/esm_referrer/__test__.jsonc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"args": "run -A --quiet main.ts",
|
||||
"output": "main.out"
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"tempDir": true,
|
||||
"tests": {
|
||||
"check": {
|
||||
"args": "check --node-modules-dir=auto main.ts",
|
||||
"output": "check.out",
|
||||
"exitCode": 1
|
||||
},
|
||||
"run": {
|
||||
"args": "run --node-modules-dir=auto --allow-read main.ts",
|
||||
"output": "main.out"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
Download http://localhost:4260/@denotest%2fdual-cjs-esm
|
||||
Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
|
||||
Initialize @denotest/dual-cjs-esm@1.0.0
|
||||
Check file:///[WILDLINE]/main.ts
|
||||
error: TS2322 [ERROR]: Type '"cjs"' is not assignable to type '"other"'.
|
||||
const kind: "other" = mod.getKind();
|
||||
~~~~
|
||||
at file:///[WILDLINE]/main.ts:3:7
|
@ -0,0 +1,4 @@
|
||||
Download http://localhost:4260/@denotest%2fdual-cjs-esm
|
||||
Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
|
||||
Initialize @denotest/dual-cjs-esm@1.0.0
|
||||
cjs
|
@ -0,0 +1,4 @@
|
||||
import mod = require("@denotest/dual-cjs-esm");
|
||||
|
||||
const kind: "other" = mod.getKind();
|
||||
console.log(kind);
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"@denotest/dual-cjs-esm": "*"
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"args": "run --allow-read permissions_outside_package/main.ts",
|
||||
"output": "permissions_outside_package/main.out"
|
||||
"tempDir": true,
|
||||
"args": "run --allow-read --node-modules-dir=none main.ts",
|
||||
"output": "main.out"
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "foobar",
|
||||
"version": "0.0.1",
|
||||
"type": "commonjs"
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { loadConfigFile } from "npm:@denotest/permissions-outside-package";
|
||||
|
||||
const fileName = `${Deno.cwd()}/permissions_outside_package/foo/config.js`;
|
||||
const fileName = `${Deno.cwd()}/foo/config.js`;
|
||||
const config = loadConfigFile(fileName);
|
||||
console.log(config);
|
2
tests/specs/npm/permissions_outside_package/package.json
Normal file
2
tests/specs/npm/permissions_outside_package/package.json
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "foobar",
|
||||
"version": "0.0.1"
|
||||
}
|
@ -1,21 +1,27 @@
|
||||
{
|
||||
"steps": [
|
||||
{ "args": "run -R index.cjs", "output": "index.out" },
|
||||
{ "args": "run -R main.ts", "output": "main.out" },
|
||||
{
|
||||
"tests": {
|
||||
"cjs_entrypoint": {
|
||||
"args": "run -R index.cjs",
|
||||
"output": "index.out"
|
||||
},
|
||||
"esm_entrypoint": {
|
||||
"args": "run -R main.ts",
|
||||
"output": "main.out"
|
||||
},
|
||||
"module_error": {
|
||||
"args": "run module_error.js",
|
||||
"output": "module_error.out",
|
||||
"exitCode": 1
|
||||
},
|
||||
{
|
||||
"exports_error": {
|
||||
"args": "run exports_error.js",
|
||||
"output": "exports_error.out",
|
||||
"exitCode": 1
|
||||
},
|
||||
{
|
||||
"require_error": {
|
||||
"args": "run require_error.js",
|
||||
"output": "require_error.out",
|
||||
"exitCode": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
function foobar() {
|
||||
console.log("foobar");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
foobar,
|
||||
};
|
@ -3,10 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
^
|
||||
at [WILDCARD]exports_error.js:1:23
|
||||
|
||||
info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
|
||||
with "type": "commonjs" option and --unstable-detect-cjs flag is used.
|
||||
info: Deno supports CommonJS modules in .cjs files, or when the closest
|
||||
package.json has a "type": "commonjs" option.
|
||||
hint: Rewrite this module to ESM,
|
||||
or change the file extension to .cjs,
|
||||
or add package.json next to the file with "type": "commonjs" option
|
||||
and pass --unstable-detect-cjs flag.
|
||||
or add package.json next to the file with "type": "commonjs" option.
|
||||
docs: https://docs.deno.com/go/commonjs
|
||||
|
@ -1,9 +1,7 @@
|
||||
const process = require("process");
|
||||
const a = require("./a");
|
||||
|
||||
console.log(process.cwd());
|
||||
|
||||
module.exports = {
|
||||
cwd: process.cwd,
|
||||
foobar: a.foobar,
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
[WILDCARD]import_common_js
|
||||
[WILDLINE]import_common_js
|
||||
|
@ -1,5 +1,3 @@
|
||||
hello from foo node module
|
||||
[WILDCARD]import_common_js
|
||||
cjsModule.cwd() [WILDCARD]import_common_js
|
||||
foobar
|
||||
cjsModule.foobar() undefined
|
||||
|
@ -3,10 +3,9 @@ module.exports = {
|
||||
^
|
||||
at [WILDCARD]module_error.js:1:1
|
||||
|
||||
info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
|
||||
with "type": "commonjs" option and --unstable-detect-cjs flag is used.
|
||||
info: Deno supports CommonJS modules in .cjs files, or when the closest
|
||||
package.json has a "type": "commonjs" option.
|
||||
hint: Rewrite this module to ESM,
|
||||
or change the file extension to .cjs,
|
||||
or add package.json next to the file with "type": "commonjs" option
|
||||
and pass --unstable-detect-cjs flag.
|
||||
or add package.json next to the file with "type": "commonjs" option.
|
||||
docs: https://docs.deno.com/go/commonjs
|
||||
|
1
tests/specs/run/import_common_js/node_modules/foo/index.mjs
generated
vendored
1
tests/specs/run/import_common_js/node_modules/foo/index.mjs
generated
vendored
@ -10,5 +10,4 @@ export default async function () {
|
||||
const cjsModule = await import(url.pathToFileURL(cjsFileToImport));
|
||||
|
||||
console.log("cjsModule.cwd()", cjsModule.cwd());
|
||||
console.log("cjsModule.foobar()", cjsModule.foobar());
|
||||
}
|
||||
|
@ -3,10 +3,9 @@ const process = require("process");
|
||||
^
|
||||
at [WILDCARD]require_error.js:1:17
|
||||
|
||||
info: Deno supports CommonJS modules in .cjs files, or when there's a package.json
|
||||
with "type": "commonjs" option and --unstable-detect-cjs flag is used.
|
||||
info: Deno supports CommonJS modules in .cjs files, or when the closest
|
||||
package.json has a "type": "commonjs" option.
|
||||
hint: Rewrite this module to ESM,
|
||||
or change the file extension to .cjs,
|
||||
or add package.json next to the file with "type": "commonjs" option
|
||||
and pass --unstable-detect-cjs flag.
|
||||
or add package.json next to the file with "type": "commonjs" option.
|
||||
docs: https://docs.deno.com/go/commonjs
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user