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

feat(unstable): repurpose --unstable-detect-cjs to attempt loading more modules as cjs (#27094)

This resurrects the `--unstable-detect-cjs` flag (which became stable),
and repurposes it to attempt loading .js/.jsx/.ts/.tsx files as CJS in
the following additional scenarios:

1. There is no package.json
1. There is a package.json without a "type" field

Also cleans up the implementation of this in the LSP a lot by hanging
`resolution_mode()` off `Document` (didn't think about doing that until
now).
This commit is contained in:
David Sherret 2024-11-27 09:50:38 -05:00 committed by GitHub
parent 1e51b650be
commit 2bbfef137c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 217 additions and 226 deletions

View file

@ -598,6 +598,7 @@ pub struct UnstableConfig {
// TODO(bartlomieju): remove in Deno 2.5 // TODO(bartlomieju): remove in Deno 2.5
pub legacy_flag_enabled: bool, // --unstable pub legacy_flag_enabled: bool, // --unstable
pub bare_node_builtins: bool, pub bare_node_builtins: bool,
pub detect_cjs: bool,
pub sloppy_imports: bool, pub sloppy_imports: bool,
pub features: Vec<String>, // --unstabe-kv --unstable-cron pub features: Vec<String>, // --unstabe-kv --unstable-cron
} }
@ -4373,7 +4374,7 @@ impl CommandExt for Command {
).arg( ).arg(
Arg::new("unstable-detect-cjs") Arg::new("unstable-detect-cjs")
.long("unstable-detect-cjs") .long("unstable-detect-cjs")
.help("Reads the package.json type field in a project to treat .js files as .cjs") .help("Treats ambiguous .js, .jsx, .ts, .tsx files as CommonJS modules in more cases")
.value_parser(FalseyValueParser::new()) .value_parser(FalseyValueParser::new())
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.hide(true) .hide(true)
@ -5986,6 +5987,7 @@ fn unstable_args_parse(
flags.unstable_config.bare_node_builtins = flags.unstable_config.bare_node_builtins =
matches.get_flag("unstable-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 = flags.unstable_config.sloppy_imports =
matches.get_flag("unstable-sloppy-imports"); matches.get_flag("unstable-sloppy-imports");

View file

@ -1606,6 +1606,11 @@ impl CliOptions {
|| self.workspace().has_unstable("bare-node-builtins") || 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 { pub fn detect_cjs(&self) -> bool {
// only enabled when there's a package.json in order to not have a // 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 // perf penalty for non-npm Deno projects of searching for the closest
@ -1675,6 +1680,7 @@ impl CliOptions {
"sloppy-imports", "sloppy-imports",
"byonm", "byonm",
"bare-node-builtins", "bare-node-builtins",
"detect-cjs",
"fmt-component", "fmt-component",
"fmt-sql", "fmt-sql",
]) ])

View file

@ -48,7 +48,6 @@ use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver; use crate::resolver::CliResolver;
use crate::resolver::CliResolverOptions; use crate::resolver::CliResolverOptions;
use crate::resolver::CliSloppyImportsResolver; use crate::resolver::CliSloppyImportsResolver;
use crate::resolver::IsCjsResolverOptions;
use crate::resolver::NpmModuleLoader; use crate::resolver::NpmModuleLoader;
use crate::resolver::SloppyImportsCachedFs; use crate::resolver::SloppyImportsCachedFs;
use crate::standalone::DenoCompileBinaryWriter; use crate::standalone::DenoCompileBinaryWriter;
@ -72,6 +71,7 @@ use deno_core::error::AnyError;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::FeatureChecker; use deno_core::FeatureChecker;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions; use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmReqResolver; use deno_resolver::NodeAndNpmReqResolver;
@ -845,9 +845,12 @@ impl CliFactory {
Ok(Arc::new(CjsTracker::new( Ok(Arc::new(CjsTracker::new(
self.in_npm_pkg_checker()?.clone(), self.in_npm_pkg_checker()?.clone(),
self.pkg_json_resolver().clone(), self.pkg_json_resolver().clone(),
IsCjsResolverOptions { if options.is_node_main() || options.unstable_detect_cjs() {
detect_cjs: options.detect_cjs(), IsCjsResolutionMode::ImplicitTypeCommonJs
is_node_main: options.is_node_main(), } else if options.detect_cjs() {
IsCjsResolutionMode::ExplicitTypeCommonJs
} else {
IsCjsResolutionMode::Disabled
}, },
))) )))
}) })

View file

@ -1281,9 +1281,7 @@ impl CodeActionCollection {
import_start_from_specifier(document, i) import_start_from_specifier(document, i)
})?; })?;
let referrer = document.specifier(); let referrer = document.specifier();
let referrer_kind = language_server let resolution_mode = document.resolution_mode();
.is_cjs_resolver
.get_doc_resolution_mode(document);
let file_referrer = document.file_referrer(); let file_referrer = document.file_referrer();
let config_data = language_server let config_data = language_server
.config .config
@ -1309,7 +1307,7 @@ impl CodeActionCollection {
if !language_server.resolver.is_bare_package_json_dep( if !language_server.resolver.is_bare_package_json_dep(
&dep_key, &dep_key,
referrer, referrer,
referrer_kind, resolution_mode,
) { ) {
return None; return None;
} }
@ -1329,7 +1327,7 @@ impl CodeActionCollection {
} }
if language_server if language_server
.resolver .resolver
.npm_to_file_url(&npm_ref, referrer, referrer_kind, file_referrer) .npm_to_file_url(&npm_ref, referrer, resolution_mode, file_referrer)
.is_some() .is_some()
{ {
// The package import has types. // The package import has types.

View file

@ -9,7 +9,6 @@ use super::jsr::CliJsrSearchApi;
use super::lsp_custom; use super::lsp_custom;
use super::npm::CliNpmSearchApi; use super::npm::CliNpmSearchApi;
use super::registries::ModuleRegistry; use super::registries::ModuleRegistry;
use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver; use super::resolver::LspResolver;
use super::search::PackageSearchApi; use super::search::PackageSearchApi;
use super::tsc; use super::tsc;
@ -161,7 +160,6 @@ pub async fn get_import_completions(
jsr_search_api: &CliJsrSearchApi, jsr_search_api: &CliJsrSearchApi,
npm_search_api: &CliNpmSearchApi, npm_search_api: &CliNpmSearchApi,
documents: &Documents, documents: &Documents,
is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver, resolver: &LspResolver,
maybe_import_map: Option<&ImportMap>, maybe_import_map: Option<&ImportMap>,
) -> Option<lsp::CompletionResponse> { ) -> Option<lsp::CompletionResponse> {
@ -171,7 +169,7 @@ pub async fn get_import_completions(
let resolution_mode = graph_range let resolution_mode = graph_range
.resolution_mode .resolution_mode
.map(to_node_resolution_mode) .map(to_node_resolution_mode)
.unwrap_or_else(|| is_cjs_resolver.get_doc_resolution_mode(&document)); .unwrap_or_else(|| document.resolution_mode());
let range = to_narrow_lsp_range(document.text_info(), graph_range.range); let range = to_narrow_lsp_range(document.text_info(), graph_range.range);
let resolved = resolver let resolved = resolver
.as_cli_resolver(file_referrer) .as_cli_resolver(file_referrer)

View file

@ -1707,7 +1707,6 @@ mod tests {
documents: Arc::new(documents), documents: Arc::new(documents),
assets: Default::default(), assets: Default::default(),
config: Arc::new(config), config: Arc::new(config),
is_cjs_resolver: Default::default(),
resolver, resolver,
}, },
) )

View file

@ -3,7 +3,6 @@
use super::cache::calculate_fs_version; use super::cache::calculate_fs_version;
use super::cache::LspCache; use super::cache::LspCache;
use super::config::Config; use super::config::Config;
use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver; use super::resolver::LspResolver;
use super::resolver::ScopeDepInfo; use super::resolver::ScopeDepInfo;
use super::resolver::SingleReferrerGraphResolver; use super::resolver::SingleReferrerGraphResolver;
@ -313,6 +312,7 @@ pub struct Document {
media_type: MediaType, media_type: MediaType,
/// Present if and only if this is an open document. /// Present if and only if this is an open document.
open_data: Option<DocumentOpenData>, open_data: Option<DocumentOpenData>,
resolution_mode: ResolutionMode,
resolver: Arc<LspResolver>, resolver: Arc<LspResolver>,
specifier: ModuleSpecifier, specifier: ModuleSpecifier,
text: Arc<str>, text: Arc<str>,
@ -328,7 +328,6 @@ impl Document {
maybe_lsp_version: Option<i32>, maybe_lsp_version: Option<i32>,
maybe_language_id: Option<LanguageId>, maybe_language_id: Option<LanguageId>,
maybe_headers: Option<HashMap<String, String>>, maybe_headers: Option<HashMap<String, String>>,
is_cjs_resolver: &LspIsCjsResolver,
resolver: Arc<LspResolver>, resolver: Arc<LspResolver>,
config: Arc<Config>, config: Arc<Config>,
cache: &Arc<LspCache>, cache: &Arc<LspCache>,
@ -340,7 +339,7 @@ impl Document {
.or(file_referrer); .or(file_referrer);
let media_type = let media_type =
resolve_media_type(&specifier, maybe_headers.as_ref(), maybe_language_id); resolve_media_type(&specifier, maybe_headers.as_ref(), maybe_language_id);
let (maybe_parsed_source, maybe_module) = let (maybe_parsed_source, maybe_module, resolution_mode) =
if media_type_is_diagnosable(media_type) { if media_type_is_diagnosable(media_type) {
parse_and_analyze_module( parse_and_analyze_module(
specifier.clone(), specifier.clone(),
@ -348,11 +347,10 @@ impl Document {
maybe_headers.as_ref(), maybe_headers.as_ref(),
media_type, media_type,
file_referrer.as_ref(), file_referrer.as_ref(),
is_cjs_resolver,
&resolver, &resolver,
) )
} else { } else {
(None, None) (None, None, ResolutionMode::Import)
}; };
let maybe_module = maybe_module.and_then(Result::ok); let maybe_module = maybe_module.and_then(Result::ok);
let dependencies = maybe_module let dependencies = maybe_module
@ -387,6 +385,7 @@ impl Document {
maybe_parsed_source, maybe_parsed_source,
maybe_semantic_tokens: Default::default(), maybe_semantic_tokens: Default::default(),
}), }),
resolution_mode,
resolver, resolver,
specifier, specifier,
text, text,
@ -396,7 +395,6 @@ impl Document {
fn with_new_config( fn with_new_config(
&self, &self,
is_cjs_resolver: &LspIsCjsResolver,
resolver: Arc<LspResolver>, resolver: Arc<LspResolver>,
config: Arc<Config>, config: Arc<Config>,
) -> Arc<Self> { ) -> Arc<Self> {
@ -408,20 +406,20 @@ impl Document {
let dependencies; let dependencies;
let maybe_types_dependency; let maybe_types_dependency;
let maybe_parsed_source; let maybe_parsed_source;
let found_resolution_mode;
let is_script; let is_script;
let maybe_test_module_fut; let maybe_test_module_fut;
if media_type != self.media_type { if media_type != self.media_type {
let parsed_source_result = let parsed_source_result =
parse_source(self.specifier.clone(), self.text.clone(), media_type); parse_source(self.specifier.clone(), self.text.clone(), media_type);
let maybe_module = analyze_module( let (maybe_module_result, resolution_mode) = analyze_module(
self.specifier.clone(), self.specifier.clone(),
&parsed_source_result, &parsed_source_result,
self.maybe_headers.as_ref(), self.maybe_headers.as_ref(),
self.file_referrer.as_ref(), self.file_referrer.as_ref(),
is_cjs_resolver,
&resolver, &resolver,
) );
.ok(); let maybe_module = maybe_module_result.ok();
dependencies = maybe_module dependencies = maybe_module
.as_ref() .as_ref()
.map(|m| Arc::new(m.dependencies.clone())) .map(|m| Arc::new(m.dependencies.clone()))
@ -433,17 +431,21 @@ impl Document {
maybe_parsed_source = Some(parsed_source_result); maybe_parsed_source = Some(parsed_source_result);
maybe_test_module_fut = maybe_test_module_fut =
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &config); get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &config);
found_resolution_mode = resolution_mode;
} else { } else {
let cli_resolver = resolver.as_cli_resolver(self.file_referrer.as_ref()); let cli_resolver = resolver.as_cli_resolver(self.file_referrer.as_ref());
let is_cjs_resolver =
resolver.as_is_cjs_resolver(self.file_referrer.as_ref());
let npm_resolver = let npm_resolver =
resolver.create_graph_npm_resolver(self.file_referrer.as_ref()); resolver.create_graph_npm_resolver(self.file_referrer.as_ref());
let config_data = resolver.as_config_data(self.file_referrer.as_ref()); let config_data = resolver.as_config_data(self.file_referrer.as_ref());
let jsx_import_source_config = let jsx_import_source_config =
config_data.and_then(|d| d.maybe_jsx_import_source_config()); config_data.and_then(|d| d.maybe_jsx_import_source_config());
found_resolution_mode = is_cjs_resolver
.get_lsp_resolution_mode(&self.specifier, self.is_script);
let resolver = SingleReferrerGraphResolver { let resolver = SingleReferrerGraphResolver {
valid_referrer: &self.specifier, valid_referrer: &self.specifier,
module_resolution_mode: is_cjs_resolver module_resolution_mode: found_resolution_mode,
.get_lsp_resolution_mode(&self.specifier, self.is_script),
cli_resolver, cli_resolver,
jsx_import_source_config: jsx_import_source_config.as_ref(), jsx_import_source_config: jsx_import_source_config.as_ref(),
}; };
@ -493,6 +495,7 @@ impl Document {
maybe_language_id: self.maybe_language_id, maybe_language_id: self.maybe_language_id,
maybe_test_module_fut, maybe_test_module_fut,
media_type, media_type,
resolution_mode: found_resolution_mode,
open_data: self.open_data.as_ref().map(|d| DocumentOpenData { open_data: self.open_data.as_ref().map(|d| DocumentOpenData {
lsp_version: d.lsp_version, lsp_version: d.lsp_version,
maybe_parsed_source, maybe_parsed_source,
@ -508,7 +511,6 @@ impl Document {
fn with_change( fn with_change(
&self, &self,
is_cjs_resolver: &LspIsCjsResolver,
version: i32, version: i32,
changes: Vec<lsp::TextDocumentContentChangeEvent>, changes: Vec<lsp::TextDocumentContentChangeEvent>,
) -> Result<Arc<Self>, AnyError> { ) -> Result<Arc<Self>, AnyError> {
@ -530,7 +532,7 @@ impl Document {
} }
let text: Arc<str> = content.into(); let text: Arc<str> = content.into();
let media_type = self.media_type; let media_type = self.media_type;
let (maybe_parsed_source, maybe_module) = if self let (maybe_parsed_source, maybe_module, resolution_mode) = if self
.maybe_language_id .maybe_language_id
.as_ref() .as_ref()
.map(|li| li.is_diagnosable()) .map(|li| li.is_diagnosable())
@ -542,11 +544,10 @@ impl Document {
self.maybe_headers.as_ref(), self.maybe_headers.as_ref(),
media_type, media_type,
self.file_referrer.as_ref(), self.file_referrer.as_ref(),
is_cjs_resolver,
self.resolver.as_ref(), self.resolver.as_ref(),
) )
} else { } else {
(None, None) (None, None, ResolutionMode::Import)
}; };
let maybe_module = maybe_module.and_then(Result::ok); let maybe_module = maybe_module.and_then(Result::ok);
let dependencies = maybe_module let dependencies = maybe_module
@ -580,6 +581,7 @@ impl Document {
maybe_navigation_tree: Mutex::new(None), maybe_navigation_tree: Mutex::new(None),
maybe_test_module_fut, maybe_test_module_fut,
media_type, media_type,
resolution_mode,
open_data: self.open_data.is_some().then_some(DocumentOpenData { open_data: self.open_data.is_some().then_some(DocumentOpenData {
lsp_version: version, lsp_version: version,
maybe_parsed_source, maybe_parsed_source,
@ -613,6 +615,7 @@ impl Document {
maybe_test_module_fut: self.maybe_test_module_fut.clone(), maybe_test_module_fut: self.maybe_test_module_fut.clone(),
media_type: self.media_type, media_type: self.media_type,
open_data: None, open_data: None,
resolution_mode: self.resolution_mode,
resolver: self.resolver.clone(), resolver: self.resolver.clone(),
}) })
} }
@ -641,6 +644,7 @@ impl Document {
maybe_test_module_fut: self.maybe_test_module_fut.clone(), maybe_test_module_fut: self.maybe_test_module_fut.clone(),
media_type: self.media_type, media_type: self.media_type,
open_data: self.open_data.clone(), open_data: self.open_data.clone(),
resolution_mode: self.resolution_mode,
resolver: self.resolver.clone(), resolver: self.resolver.clone(),
}) })
} }
@ -664,6 +668,10 @@ impl Document {
&self.text &self.text
} }
pub fn resolution_mode(&self) -> ResolutionMode {
self.resolution_mode
}
pub fn text_info(&self) -> &SourceTextInfo { pub fn text_info(&self) -> &SourceTextInfo {
// try to get the text info from the parsed source and if // try to get the text info from the parsed source and if
// not then create one in the cell // not then create one in the cell
@ -677,14 +685,6 @@ impl Document {
.get_or_init(|| SourceTextInfo::new(self.text.clone())) .get_or_init(|| SourceTextInfo::new(self.text.clone()))
}) })
} }
/// 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> { pub fn line_index(&self) -> Arc<LineIndex> {
self.line_index.clone() self.line_index.clone()
} }
@ -832,7 +832,6 @@ impl FileSystemDocuments {
pub fn get( pub fn get(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
is_cjs_resolver: &LspIsCjsResolver,
resolver: &Arc<LspResolver>, resolver: &Arc<LspResolver>,
config: &Arc<Config>, config: &Arc<Config>,
cache: &Arc<LspCache>, cache: &Arc<LspCache>,
@ -856,14 +855,7 @@ impl FileSystemDocuments {
}; };
if dirty { if dirty {
// attempt to update the file on the file system // attempt to update the file on the file system
self.refresh_document( self.refresh_document(specifier, resolver, config, cache, file_referrer)
specifier,
is_cjs_resolver,
resolver,
config,
cache,
file_referrer,
)
} else { } else {
old_doc old_doc
} }
@ -874,7 +866,6 @@ impl FileSystemDocuments {
fn refresh_document( fn refresh_document(
&self, &self,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
is_cjs_resolver: &LspIsCjsResolver,
resolver: &Arc<LspResolver>, resolver: &Arc<LspResolver>,
config: &Arc<Config>, config: &Arc<Config>,
cache: &Arc<LspCache>, cache: &Arc<LspCache>,
@ -896,7 +887,6 @@ impl FileSystemDocuments {
None, None,
None, None,
None, None,
is_cjs_resolver,
resolver.clone(), resolver.clone(),
config.clone(), config.clone(),
cache, cache,
@ -913,7 +903,6 @@ impl FileSystemDocuments {
None, None,
None, None,
None, None,
is_cjs_resolver,
resolver.clone(), resolver.clone(),
config.clone(), config.clone(),
cache, cache,
@ -946,7 +935,6 @@ impl FileSystemDocuments {
None, None,
None, None,
Some(cached_file.metadata.headers), Some(cached_file.metadata.headers),
is_cjs_resolver,
resolver.clone(), resolver.clone(),
config.clone(), config.clone(),
cache, cache,
@ -987,8 +975,6 @@ pub struct Documents {
/// The DENO_DIR that the documents looks for non-file based modules. /// The DENO_DIR that the documents looks for non-file based modules.
cache: Arc<LspCache>, cache: Arc<LspCache>,
config: Arc<Config>, 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 /// A resolver that takes into account currently loaded import map and JSX
/// settings. /// settings.
resolver: Arc<LspResolver>, resolver: Arc<LspResolver>,
@ -1024,7 +1010,6 @@ impl Documents {
// the cache for remote modules here in order to get the // the cache for remote modules here in order to get the
// x-typescript-types? // x-typescript-types?
None, None,
&self.is_cjs_resolver,
self.resolver.clone(), self.resolver.clone(),
self.config.clone(), self.config.clone(),
&self.cache, &self.cache,
@ -1059,7 +1044,7 @@ impl Documents {
)) ))
})?; })?;
self.dirty = true; self.dirty = true;
let doc = doc.with_change(&self.is_cjs_resolver, version, changes)?; let doc = doc.with_change(version, changes)?;
self.open_docs.insert(doc.specifier().clone(), doc.clone()); self.open_docs.insert(doc.specifier().clone(), doc.clone());
Ok(doc) Ok(doc)
} }
@ -1191,7 +1176,6 @@ impl Documents {
if let Some(old_doc) = old_doc { if let Some(old_doc) = old_doc {
self.file_system_docs.get( self.file_system_docs.get(
specifier, specifier,
&self.is_cjs_resolver,
&self.resolver, &self.resolver,
&self.config, &self.config,
&self.cache, &self.cache,
@ -1216,7 +1200,6 @@ impl Documents {
} else { } else {
self.file_system_docs.get( self.file_system_docs.get(
&specifier, &specifier,
&self.is_cjs_resolver,
&self.resolver, &self.resolver,
&self.config, &self.config,
&self.cache, &self.cache,
@ -1346,7 +1329,6 @@ impl Documents {
) { ) {
self.config = Arc::new(config.clone()); self.config = Arc::new(config.clone());
self.cache = Arc::new(cache.clone()); self.cache = Arc::new(cache.clone());
self.is_cjs_resolver = Arc::new(LspIsCjsResolver::new(cache));
self.resolver = resolver.clone(); self.resolver = resolver.clone();
node_resolver::PackageJsonThreadLocalCache::clear(); node_resolver::PackageJsonThreadLocalCache::clear();
@ -1370,21 +1352,14 @@ impl Documents {
if !config.specifier_enabled(doc.specifier()) { if !config.specifier_enabled(doc.specifier()) {
continue; continue;
} }
*doc = doc.with_new_config( *doc = doc.with_new_config(self.resolver.clone(), self.config.clone());
&self.is_cjs_resolver,
self.resolver.clone(),
self.config.clone(),
);
} }
for mut doc in self.file_system_docs.docs.iter_mut() { for mut doc in self.file_system_docs.docs.iter_mut() {
if !config.specifier_enabled(doc.specifier()) { if !config.specifier_enabled(doc.specifier()) {
continue; continue;
} }
*doc.value_mut() = doc.with_new_config( *doc.value_mut() =
&self.is_cjs_resolver, doc.with_new_config(self.resolver.clone(), self.config.clone());
self.resolver.clone(),
self.config.clone(),
);
} }
self.open_docs = open_docs; self.open_docs = open_docs;
let mut preload_count = 0; let mut preload_count = 0;
@ -1401,7 +1376,6 @@ impl Documents {
{ {
fs_docs.refresh_document( fs_docs.refresh_document(
specifier, specifier,
&self.is_cjs_resolver,
&self.resolver, &self.resolver,
&self.config, &self.config,
&self.cache, &self.cache,
@ -1567,8 +1541,12 @@ impl Documents {
return Some((specifier, media_type)); return Some((specifier, media_type));
}; };
if let Some(types) = doc.maybe_types_dependency().maybe_specifier() { if let Some(types) = doc.maybe_types_dependency().maybe_specifier() {
let specifier_kind = self.is_cjs_resolver.get_doc_resolution_mode(&doc); self.resolve_dependency(
self.resolve_dependency(types, &specifier, specifier_kind, file_referrer) types,
&specifier,
doc.resolution_mode(),
file_referrer,
)
} else { } else {
Some((doc.specifier().clone(), doc.media_type())) Some((doc.specifier().clone(), doc.media_type()))
} }
@ -1636,19 +1614,25 @@ fn parse_and_analyze_module(
maybe_headers: Option<&HashMap<String, String>>, maybe_headers: Option<&HashMap<String, String>>,
media_type: MediaType, media_type: MediaType,
file_referrer: Option<&ModuleSpecifier>, file_referrer: Option<&ModuleSpecifier>,
is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver, resolver: &LspResolver,
) -> (Option<ParsedSourceResult>, Option<ModuleResult>) { ) -> (
Option<ParsedSourceResult>,
Option<ModuleResult>,
ResolutionMode,
) {
let parsed_source_result = parse_source(specifier.clone(), text, media_type); let parsed_source_result = parse_source(specifier.clone(), text, media_type);
let module_result = analyze_module( let (module_result, resolution_mode) = analyze_module(
specifier, specifier,
&parsed_source_result, &parsed_source_result,
maybe_headers, maybe_headers,
file_referrer, file_referrer,
is_cjs_resolver,
resolver, resolver,
); );
(Some(parsed_source_result), Some(module_result)) (
Some(parsed_source_result),
Some(module_result),
resolution_mode,
)
} }
fn parse_source( fn parse_source(
@ -1671,44 +1655,51 @@ fn analyze_module(
parsed_source_result: &ParsedSourceResult, parsed_source_result: &ParsedSourceResult,
maybe_headers: Option<&HashMap<String, String>>, maybe_headers: Option<&HashMap<String, String>>,
file_referrer: Option<&ModuleSpecifier>, file_referrer: Option<&ModuleSpecifier>,
is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver, resolver: &LspResolver,
) -> ModuleResult { ) -> (ModuleResult, ResolutionMode) {
match parsed_source_result { match parsed_source_result {
Ok(parsed_source) => { Ok(parsed_source) => {
let npm_resolver = resolver.create_graph_npm_resolver(file_referrer); let npm_resolver = resolver.create_graph_npm_resolver(file_referrer);
let cli_resolver = resolver.as_cli_resolver(file_referrer); let cli_resolver = resolver.as_cli_resolver(file_referrer);
let is_cjs_resolver = resolver.as_is_cjs_resolver(file_referrer);
let config_data = resolver.as_config_data(file_referrer); let config_data = resolver.as_config_data(file_referrer);
let valid_referrer = specifier.clone(); let valid_referrer = specifier.clone();
let jsx_import_source_config = let jsx_import_source_config =
config_data.and_then(|d| d.maybe_jsx_import_source_config()); config_data.and_then(|d| d.maybe_jsx_import_source_config());
let module_resolution_mode = is_cjs_resolver.get_lsp_resolution_mode(
&specifier,
Some(parsed_source.compute_is_script()),
);
let resolver = SingleReferrerGraphResolver { let resolver = SingleReferrerGraphResolver {
valid_referrer: &valid_referrer, valid_referrer: &valid_referrer,
module_resolution_mode: is_cjs_resolver.get_lsp_resolution_mode( module_resolution_mode,
&specifier,
Some(parsed_source.compute_is_script()),
),
cli_resolver, cli_resolver,
jsx_import_source_config: jsx_import_source_config.as_ref(), jsx_import_source_config: jsx_import_source_config.as_ref(),
}; };
Ok(deno_graph::parse_module_from_ast( (
deno_graph::ParseModuleFromAstOptions { Ok(deno_graph::parse_module_from_ast(
graph_kind: deno_graph::GraphKind::TypesOnly, deno_graph::ParseModuleFromAstOptions {
specifier, graph_kind: deno_graph::GraphKind::TypesOnly,
maybe_headers, specifier,
parsed_source, maybe_headers,
// use a null file system because there's no need to bother resolving parsed_source,
// dynamic imports like import(`./dir/${something}`) in the LSP // use a null file system because there's no need to bother resolving
file_system: &deno_graph::source::NullFileSystem, // dynamic imports like import(`./dir/${something}`) in the LSP
jsr_url_provider: &CliJsrUrlProvider, file_system: &deno_graph::source::NullFileSystem,
maybe_resolver: Some(&resolver), jsr_url_provider: &CliJsrUrlProvider,
maybe_npm_resolver: Some(&npm_resolver), maybe_resolver: Some(&resolver),
}, maybe_npm_resolver: Some(&npm_resolver),
)) },
)),
module_resolution_mode,
)
} }
Err(err) => Err(deno_graph::ModuleGraphError::ModuleError( Err(err) => (
deno_graph::ModuleError::ParseErr(specifier, err.clone()), Err(deno_graph::ModuleGraphError::ModuleError(
)), deno_graph::ModuleError::ParseErr(specifier, err.clone()),
)),
ResolutionMode::Import,
),
} }
} }

View file

@ -79,7 +79,6 @@ use super::parent_process_checker;
use super::performance::Performance; use super::performance::Performance;
use super::refactor; use super::refactor;
use super::registries::ModuleRegistry; use super::registries::ModuleRegistry;
use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver; use super::resolver::LspResolver;
use super::testing; use super::testing;
use super::text; use super::text;
@ -147,7 +146,6 @@ pub struct StateSnapshot {
pub project_version: usize, pub project_version: usize,
pub assets: AssetsSnapshot, pub assets: AssetsSnapshot,
pub config: Arc<Config>, pub config: Arc<Config>,
pub is_cjs_resolver: Arc<LspIsCjsResolver>,
pub documents: Arc<Documents>, pub documents: Arc<Documents>,
pub resolver: Arc<LspResolver>, pub resolver: Arc<LspResolver>,
} }
@ -207,7 +205,6 @@ pub struct Inner {
pub documents: Documents, pub documents: Documents,
http_client_provider: Arc<HttpClientProvider>, http_client_provider: Arc<HttpClientProvider>,
initial_cwd: PathBuf, initial_cwd: PathBuf,
pub is_cjs_resolver: Arc<LspIsCjsResolver>,
jsr_search_api: CliJsrSearchApi, jsr_search_api: CliJsrSearchApi,
/// Handles module registries, which allow discovery of modules /// Handles module registries, which allow discovery of modules
module_registry: ModuleRegistry, module_registry: ModuleRegistry,
@ -485,7 +482,6 @@ impl Inner {
let initial_cwd = std::env::current_dir().unwrap_or_else(|_| { let initial_cwd = std::env::current_dir().unwrap_or_else(|_| {
panic!("Could not resolve current working directory") panic!("Could not resolve current working directory")
}); });
let is_cjs_resolver = Arc::new(LspIsCjsResolver::new(&cache));
Self { Self {
assets, assets,
@ -497,7 +493,6 @@ impl Inner {
documents, documents,
http_client_provider, http_client_provider,
initial_cwd: initial_cwd.clone(), initial_cwd: initial_cwd.clone(),
is_cjs_resolver,
jsr_search_api, jsr_search_api,
project_version: 0, project_version: 0,
task_queue: Default::default(), task_queue: Default::default(),
@ -608,7 +603,6 @@ impl Inner {
project_version: self.project_version, project_version: self.project_version,
assets: self.assets.snapshot(), assets: self.assets.snapshot(),
config: Arc::new(self.config.clone()), config: Arc::new(self.config.clone()),
is_cjs_resolver: self.is_cjs_resolver.clone(),
documents: Arc::new(self.documents.clone()), documents: Arc::new(self.documents.clone()),
resolver: self.resolver.snapshot(), resolver: self.resolver.snapshot(),
}) })
@ -630,7 +624,6 @@ impl Inner {
} }
}); });
self.cache = LspCache::new(global_cache_url); 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 deno_dir = self.cache.deno_dir();
let workspace_settings = self.config.workspace_settings(); let workspace_settings = self.config.workspace_settings();
let maybe_root_path = self let maybe_root_path = self
@ -1638,7 +1631,7 @@ impl Inner {
.get_ts_diagnostics(&specifier, asset_or_doc.document_lsp_version()); .get_ts_diagnostics(&specifier, asset_or_doc.document_lsp_version());
let specifier_kind = asset_or_doc let specifier_kind = asset_or_doc
.document() .document()
.map(|d| self.is_cjs_resolver.get_doc_resolution_mode(d)) .map(|d| d.resolution_mode())
.unwrap_or(ResolutionMode::Import); .unwrap_or(ResolutionMode::Import);
let mut includes_no_cache = false; let mut includes_no_cache = false;
for diagnostic in &fixable_diagnostics { for diagnostic in &fixable_diagnostics {
@ -1862,7 +1855,7 @@ impl Inner {
maybe_asset_or_doc maybe_asset_or_doc
.as_ref() .as_ref()
.and_then(|d| d.document()) .and_then(|d| d.document())
.map(|d| self.is_cjs_resolver.get_doc_resolution_mode(d)) .map(|d| d.resolution_mode())
.unwrap_or(ResolutionMode::Import), .unwrap_or(ResolutionMode::Import),
&combined_code_actions.changes, &combined_code_actions.changes,
self, self,
@ -1919,7 +1912,7 @@ impl Inner {
&action_data.specifier, &action_data.specifier,
asset_or_doc asset_or_doc
.document() .document()
.map(|d| self.is_cjs_resolver.get_doc_resolution_mode(d)) .map(|d| d.resolution_mode())
.unwrap_or(ResolutionMode::Import), .unwrap_or(ResolutionMode::Import),
&refactor_edit_info.edits, &refactor_edit_info.edits,
self, self,
@ -2270,7 +2263,6 @@ impl Inner {
&self.jsr_search_api, &self.jsr_search_api,
&self.npm_search_api, &self.npm_search_api,
&self.documents, &self.documents,
&self.is_cjs_resolver,
self.resolver.as_ref(), self.resolver.as_ref(),
self self
.config .config

View file

@ -13,8 +13,8 @@ use deno_graph::GraphImport;
use deno_graph::ModuleSpecifier; use deno_graph::ModuleSpecifier;
use deno_graph::Range; use deno_graph::Range;
use deno_npm::NpmSystemInfo; use deno_npm::NpmSystemInfo;
use deno_path_util::url_from_directory_path;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::npm::NpmReqResolverOptions;
use deno_resolver::DenoResolverOptions; use deno_resolver::DenoResolverOptions;
use deno_resolver::NodeAndNpmReqResolver; use deno_resolver::NodeAndNpmReqResolver;
@ -39,7 +39,6 @@ use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use super::cache::LspCache; use super::cache::LspCache;
use super::documents::Document;
use super::jsr::JsrCacheResolver; use super::jsr::JsrCacheResolver;
use crate::args::create_default_npmrc; use crate::args::create_default_npmrc;
use crate::args::CacheSetting; use crate::args::CacheSetting;
@ -71,7 +70,6 @@ use crate::resolver::CliResolverOptions;
use crate::resolver::IsCjsResolver; use crate::resolver::IsCjsResolver;
use crate::resolver::WorkerCliNpmGraphResolver; use crate::resolver::WorkerCliNpmGraphResolver;
use crate::tsc::into_specifier_and_media_type; 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::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
@ -79,6 +77,7 @@ use crate::util::progress_bar::ProgressBarStyle;
struct LspScopeResolver { struct LspScopeResolver {
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
is_cjs_resolver: Arc<IsCjsResolver>,
jsr_resolver: Option<Arc<JsrCacheResolver>>, jsr_resolver: Option<Arc<JsrCacheResolver>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>, npm_resolver: Option<Arc<dyn CliNpmResolver>>,
node_resolver: Option<Arc<NodeResolver>>, node_resolver: Option<Arc<NodeResolver>>,
@ -97,6 +96,7 @@ impl Default for LspScopeResolver {
Self { Self {
resolver: factory.cli_resolver().clone(), resolver: factory.cli_resolver().clone(),
in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(), in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(),
is_cjs_resolver: factory.is_cjs_resolver().clone(),
jsr_resolver: None, jsr_resolver: None,
npm_resolver: None, npm_resolver: None,
node_resolver: None, node_resolver: None,
@ -206,6 +206,7 @@ impl LspScopeResolver {
Self { Self {
resolver: cli_resolver, resolver: cli_resolver,
in_npm_pkg_checker, in_npm_pkg_checker,
is_cjs_resolver: factory.is_cjs_resolver().clone(),
jsr_resolver, jsr_resolver,
npm_pkg_req_resolver, npm_pkg_req_resolver,
npm_resolver, npm_resolver,
@ -229,6 +230,7 @@ impl LspScopeResolver {
Arc::new(Self { Arc::new(Self {
resolver: factory.cli_resolver().clone(), resolver: factory.cli_resolver().clone(),
in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(), in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(),
is_cjs_resolver: factory.is_cjs_resolver().clone(),
jsr_resolver: self.jsr_resolver.clone(), jsr_resolver: self.jsr_resolver.clone(),
npm_pkg_req_resolver: factory.npm_pkg_req_resolver().cloned(), npm_pkg_req_resolver: factory.npm_pkg_req_resolver().cloned(),
npm_resolver: factory.npm_resolver().cloned(), npm_resolver: factory.npm_resolver().cloned(),
@ -346,6 +348,14 @@ impl LspResolver {
resolver.resolver.create_graph_npm_resolver() resolver.resolver.create_graph_npm_resolver()
} }
pub fn as_is_cjs_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &IsCjsResolver {
let resolver = self.get_scope_resolver(file_referrer);
resolver.is_cjs_resolver.as_ref()
}
pub fn as_config_data( pub fn as_config_data(
&self, &self,
file_referrer: Option<&ModuleSpecifier>, file_referrer: Option<&ModuleSpecifier>,
@ -582,6 +592,7 @@ pub struct ScopeDepInfo {
struct ResolverFactoryServices { struct ResolverFactoryServices {
cli_resolver: Deferred<Arc<CliResolver>>, cli_resolver: Deferred<Arc<CliResolver>>,
in_npm_pkg_checker: Deferred<Arc<dyn InNpmPackageChecker>>, in_npm_pkg_checker: Deferred<Arc<dyn InNpmPackageChecker>>,
is_cjs_resolver: Deferred<Arc<IsCjsResolver>>,
node_resolver: Deferred<Option<Arc<NodeResolver>>>, node_resolver: Deferred<Option<Arc<NodeResolver>>>,
npm_pkg_req_resolver: Deferred<Option<Arc<CliNpmReqResolver>>>, npm_pkg_req_resolver: Deferred<Option<Arc<CliNpmReqResolver>>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>, npm_resolver: Option<Arc<dyn CliNpmResolver>>,
@ -745,6 +756,23 @@ impl<'a> ResolverFactory<'a> {
}) })
} }
pub fn is_cjs_resolver(&self) -> &Arc<IsCjsResolver> {
self.services.is_cjs_resolver.get_or_init(|| {
Arc::new(IsCjsResolver::new(
self.in_npm_pkg_checker().clone(),
self.pkg_json_resolver().clone(),
if self
.config_data
.is_some_and(|d| d.unstable.contains("detect-cjs"))
{
IsCjsResolutionMode::ImplicitTypeCommonJs
} else {
IsCjsResolutionMode::ExplicitTypeCommonJs
},
))
})
}
pub fn node_resolver(&self) -> Option<&Arc<NodeResolver>> { pub fn node_resolver(&self) -> Option<&Arc<NodeResolver>> {
self self
.services .services
@ -804,84 +832,6 @@ 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_doc_resolution_mode(&self, document: &Document) -> ResolutionMode {
self.get_lsp_resolution_mode(document.specifier(), document.is_script())
}
pub fn get_lsp_resolution_mode(
&self,
specifier: &ModuleSpecifier,
is_script: Option<bool>,
) -> ResolutionMode {
self.inner.get_lsp_resolution_mode(specifier, is_script)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct SingleReferrerGraphResolver<'a> { pub struct SingleReferrerGraphResolver<'a> {
pub valid_referrer: &'a ModuleSpecifier, pub valid_referrer: &'a ModuleSpecifier,

View file

@ -4449,12 +4449,7 @@ fn op_load<'s>(
version: state.script_version(&specifier), version: state.script_version(&specifier),
is_cjs: doc is_cjs: doc
.document() .document()
.map(|d| { .map(|d| d.resolution_mode())
state
.state_snapshot
.is_cjs_resolver
.get_doc_resolution_mode(d)
})
.unwrap_or(ResolutionMode::Import) .unwrap_or(ResolutionMode::Import)
== ResolutionMode::Require, == ResolutionMode::Require,
}) })
@ -4689,10 +4684,7 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
let (types, _) = documents.resolve_dependency( let (types, _) = documents.resolve_dependency(
types, types,
specifier, specifier,
state doc.resolution_mode(),
.state_snapshot
.is_cjs_resolver
.get_doc_resolution_mode(doc),
doc.file_referrer(), doc.file_referrer(),
)?; )?;
let types_doc = documents.get_or_load(&types, doc.file_referrer())?; let types_doc = documents.get_or_load(&types, doc.file_referrer())?;
@ -5576,7 +5568,6 @@ mod tests {
documents: Arc::new(documents), documents: Arc::new(documents),
assets: Default::default(), assets: Default::default(),
config: Arc::new(config), config: Arc::new(config),
is_cjs_resolver: Default::default(),
resolver, resolver,
}); });
let performance = Arc::new(Performance::default()); let performance = Arc::new(Performance::default());

View file

@ -42,7 +42,6 @@ use crate::util::text_encoding::from_utf8_lossy_owned;
pub type CjsTracker = deno_resolver::cjs::CjsTracker<DenoFsNodeResolverEnv>; pub type CjsTracker = deno_resolver::cjs::CjsTracker<DenoFsNodeResolverEnv>;
pub type IsCjsResolver = pub type IsCjsResolver =
deno_resolver::cjs::IsCjsResolver<DenoFsNodeResolverEnv>; deno_resolver::cjs::IsCjsResolver<DenoFsNodeResolverEnv>;
pub type IsCjsResolverOptions = deno_resolver::cjs::IsCjsResolverOptions;
pub type CliSloppyImportsResolver = pub type CliSloppyImportsResolver =
SloppyImportsResolver<SloppyImportsCachedFs>; SloppyImportsResolver<SloppyImportsCachedFs>;
pub type CliDenoResolver = deno_resolver::DenoResolver< pub type CliDenoResolver = deno_resolver::DenoResolver<

View file

@ -554,6 +554,7 @@
"bare-node-builtins", "bare-node-builtins",
"byonm", "byonm",
"cron", "cron",
"detect-cjs",
"ffi", "ffi",
"fs", "fs",
"fmt-component", "fmt-component",

View file

@ -777,6 +777,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
unstable_config: UnstableConfig { unstable_config: UnstableConfig {
legacy_flag_enabled: false, legacy_flag_enabled: false,
bare_node_builtins: self.cli_options.unstable_bare_node_builtins(), bare_node_builtins: self.cli_options.unstable_bare_node_builtins(),
detect_cjs: self.cli_options.unstable_detect_cjs(),
sloppy_imports: self.cli_options.unstable_sloppy_imports(), sloppy_imports: self.cli_options.unstable_sloppy_imports(),
features: self.cli_options.unstable_features(), features: self.cli_options.unstable_features(),
}, },

View file

@ -32,6 +32,7 @@ use deno_core::ResolutionKind;
use deno_core::SourceCodeCacheInfo; use deno_core::SourceCodeCacheInfo;
use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::npm_rc::ResolvedNpmRc;
use deno_package_json::PackageJsonDepValue; use deno_package_json::PackageJsonDepValue;
use deno_resolver::cjs::IsCjsResolutionMode;
use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::npm::NpmReqResolverOptions;
use deno_runtime::deno_fs; use deno_runtime::deno_fs;
use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::create_host_defined_options;
@ -87,7 +88,6 @@ use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::resolver::CjsTracker; use crate::resolver::CjsTracker;
use crate::resolver::CliDenoResolverFs; use crate::resolver::CliDenoResolverFs;
use crate::resolver::CliNpmReqResolver; use crate::resolver::CliNpmReqResolver;
use crate::resolver::IsCjsResolverOptions;
use crate::resolver::NpmModuleLoader; use crate::resolver::NpmModuleLoader;
use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
@ -731,9 +731,12 @@ pub async fn run(data: StandaloneData) -> Result<i32, AnyError> {
let cjs_tracker = Arc::new(CjsTracker::new( let cjs_tracker = Arc::new(CjsTracker::new(
in_npm_pkg_checker.clone(), in_npm_pkg_checker.clone(),
pkg_json_resolver.clone(), pkg_json_resolver.clone(),
IsCjsResolverOptions { if metadata.unstable_config.detect_cjs {
detect_cjs: !metadata.workspace_resolver.package_jsons.is_empty(), IsCjsResolutionMode::ImplicitTypeCommonJs
is_node_main: false, } else if metadata.workspace_resolver.package_jsons.is_empty() {
IsCjsResolutionMode::Disabled
} else {
IsCjsResolutionMode::ExplicitTypeCommonJs
}, },
)); ));
let cache_db = Caches::new(deno_dir_provider.clone()); let cache_db = Caches::new(deno_dir_provider.clone());

View file

@ -26,13 +26,13 @@ impl<TEnv: NodeResolverEnv> CjsTracker<TEnv> {
pub fn new( pub fn new(
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
pkg_json_resolver: Arc<PackageJsonResolver<TEnv>>, pkg_json_resolver: Arc<PackageJsonResolver<TEnv>>,
options: IsCjsResolverOptions, mode: IsCjsResolutionMode,
) -> Self { ) -> Self {
Self { Self {
is_cjs_resolver: IsCjsResolver::new( is_cjs_resolver: IsCjsResolver::new(
in_npm_pkg_checker, in_npm_pkg_checker,
pkg_json_resolver, pkg_json_resolver,
options, mode,
), ),
known: Default::default(), known: Default::default(),
} }
@ -114,10 +114,14 @@ impl<TEnv: NodeResolverEnv> CjsTracker<TEnv> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IsCjsResolverOptions { pub enum IsCjsResolutionMode {
pub detect_cjs: bool, /// Requires an explicit `"type": "commonjs"` in the package.json.
pub is_node_main: bool, ExplicitTypeCommonJs,
/// Implicitly uses `"type": "commonjs"` if no `"type"` is specified.
ImplicitTypeCommonJs,
/// Does not respect `"type": "commonjs"` and always treats ambiguous files as ESM.
Disabled,
} }
/// Resolves whether a module is CJS or ESM. /// Resolves whether a module is CJS or ESM.
@ -125,19 +129,19 @@ pub struct IsCjsResolverOptions {
pub struct IsCjsResolver<TEnv: NodeResolverEnv> { pub struct IsCjsResolver<TEnv: NodeResolverEnv> {
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
pkg_json_resolver: Arc<PackageJsonResolver<TEnv>>, pkg_json_resolver: Arc<PackageJsonResolver<TEnv>>,
options: IsCjsResolverOptions, mode: IsCjsResolutionMode,
} }
impl<TEnv: NodeResolverEnv> IsCjsResolver<TEnv> { impl<TEnv: NodeResolverEnv> IsCjsResolver<TEnv> {
pub fn new( pub fn new(
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>, in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
pkg_json_resolver: Arc<PackageJsonResolver<TEnv>>, pkg_json_resolver: Arc<PackageJsonResolver<TEnv>>,
options: IsCjsResolverOptions, mode: IsCjsResolutionMode,
) -> Self { ) -> Self {
Self { Self {
in_npm_pkg_checker, in_npm_pkg_checker,
pkg_json_resolver, pkg_json_resolver,
options, mode,
} }
} }
@ -249,18 +253,19 @@ impl<TEnv: NodeResolverEnv> IsCjsResolver<TEnv> {
} else { } else {
Ok(ResolutionMode::Require) Ok(ResolutionMode::Require)
} }
} else if self.options.detect_cjs || self.options.is_node_main { } else if self.mode != IsCjsResolutionMode::Disabled {
if let Some(pkg_json) = if let Some(pkg_json) =
self.pkg_json_resolver.get_closest_package_json(specifier)? self.pkg_json_resolver.get_closest_package_json(specifier)?
{ {
let is_cjs_type = pkg_json.typ == "commonjs" let is_cjs_type = pkg_json.typ == "commonjs"
|| self.options.is_node_main && pkg_json.typ == "none"; || self.mode == IsCjsResolutionMode::ImplicitTypeCommonJs
&& pkg_json.typ == "none";
Ok(if is_cjs_type { Ok(if is_cjs_type {
ResolutionMode::Require ResolutionMode::Require
} else { } else {
ResolutionMode::Import ResolutionMode::Import
}) })
} else if self.options.is_node_main { } else if self.mode == IsCjsResolutionMode::ImplicitTypeCommonJs {
Ok(ResolutionMode::Require) Ok(ResolutionMode::Require)
} else { } else {
Ok(ResolutionMode::Import) Ok(ResolutionMode::Import)

View file

@ -316,7 +316,8 @@ fn get_suggestions_for_terminal_errors(e: &JsError) -> Vec<FixSuggestion> {
FixSuggestion::hint_multiline(&[ FixSuggestion::hint_multiline(&[
"Rewrite this module to ESM,", "Rewrite this module to ESM,",
cstr!("or change the file extension to <u>.cjs</u>,"), 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!("or add <u>package.json</> next to the file with <i>\"type\": \"commonjs\"</> option,"),
cstr!("or pass <i>--unstable-detect-cjs</> flag to detect CommonJS when loading."),
]), ]),
FixSuggestion::docs("https://docs.deno.com/go/commonjs"), FixSuggestion::docs("https://docs.deno.com/go/commonjs"),
]; ];

View file

@ -0,0 +1,4 @@
{
"args": "run --check --quiet --allow-read=. main.ts",
"output": "main.out"
}

View file

@ -0,0 +1,3 @@
export function add(a: number, b: number) {
return a + b;
}

View file

@ -0,0 +1,3 @@
{
"unstable": ["detect-cjs"]
}

View file

@ -0,0 +1 @@
3

View file

@ -0,0 +1,3 @@
import mod = require("./add.ts");
console.log(mod.add(1, 2));

View file

@ -0,0 +1,4 @@
{
"args": "run --unstable-detect-cjs --check --quiet --allow-read=. main.ts",
"output": "main.out"
}

View file

@ -0,0 +1,3 @@
export function add(a: number, b: number) {
return a + b;
}

View file

@ -0,0 +1 @@
3

View file

@ -0,0 +1,3 @@
import mod = require("./add.ts");
console.log(mod.add(1, 2));

View file

@ -0,0 +1,2 @@
{
}

View file

@ -0,0 +1,5 @@
{
"args": "run --unstable-detect-cjs --quiet --allow-read=. main.ts",
"output": "main.out",
"exitCode": 1
}

View file

@ -0,0 +1,3 @@
export function add(a: number, b: number) {
return a + b;
}

View file

@ -0,0 +1,4 @@
error: Uncaught SyntaxError: Unexpected token '='
import mod = require("./add.ts");
^
at <anonymous> (file:///[WILDLINE]/main.ts:1:8)

View file

@ -0,0 +1,3 @@
import mod = require("./add.ts");
console.log(mod.add(1, 2));

View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -7,5 +7,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
package.json has a "type": "commonjs" option. package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM, hint: Rewrite this module to ESM,
or change the file extension to .cjs, or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option. or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs docs: https://docs.deno.com/go/commonjs

View file

@ -7,5 +7,6 @@ module.exports = {
package.json has a "type": "commonjs" option. package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM, hint: Rewrite this module to ESM,
or change the file extension to .cjs, or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option. or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs docs: https://docs.deno.com/go/commonjs

View file

@ -7,5 +7,6 @@ const process = require("process");
package.json has a "type": "commonjs" option. package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM, hint: Rewrite this module to ESM,
or change the file extension to .cjs, or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option. or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs docs: https://docs.deno.com/go/commonjs

View file

@ -8,5 +8,6 @@ console.log(require);
package.json has a "type": "commonjs" option. package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM, hint: Rewrite this module to ESM,
or change the file extension to .cjs, or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option. or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs docs: https://docs.deno.com/go/commonjs

View file

@ -8,5 +8,6 @@ console.log(require("./add").add(1, 2));
package.json has a "type": "commonjs" option. package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM, hint: Rewrite this module to ESM,
or change the file extension to .cjs, or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option. or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs docs: https://docs.deno.com/go/commonjs

View file

@ -7,5 +7,6 @@ const { add } = require("./add");
package.json has a "type": "commonjs" option. package.json has a "type": "commonjs" option.
hint: Rewrite this module to ESM, hint: Rewrite this module to ESM,
or change the file extension to .cjs, or change the file extension to .cjs,
or add package.json next to the file with "type": "commonjs" option. or add package.json next to the file with "type": "commonjs" option,
or pass --unstable-detect-cjs flag to detect CommonJS when loading.
docs: https://docs.deno.com/go/commonjs docs: https://docs.deno.com/go/commonjs