mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
fix(check): CJS types importing dual ESM/CJS package should prefer CJS types (#24492)
Closes #16370
This commit is contained in:
parent
4d2d764816
commit
a49d0bd10b
20 changed files with 246 additions and 88 deletions
|
@ -409,13 +409,13 @@ impl CliFactory {
|
||||||
create_cli_npm_resolver(if self.options.use_byonm() && !matches!(self.options.sub_command(), DenoSubcommand::Install(_)) {
|
create_cli_npm_resolver(if self.options.use_byonm() && !matches!(self.options.sub_command(), DenoSubcommand::Install(_)) {
|
||||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||||
fs: fs.clone(),
|
fs: fs.clone(),
|
||||||
root_node_modules_dir: match self.options.node_modules_dir_path() {
|
root_node_modules_dir: Some(match self.options.node_modules_dir_path() {
|
||||||
Some(node_modules_path) => node_modules_path.to_path_buf(),
|
Some(node_modules_path) => node_modules_path.to_path_buf(),
|
||||||
// path needs to be canonicalized for node resolution
|
// path needs to be canonicalized for node resolution
|
||||||
// (node_modules_dir_path above is already canonicalized)
|
// (node_modules_dir_path above is already canonicalized)
|
||||||
None => canonicalize_path_maybe_not_exists(self.options.initial_cwd())?
|
None => canonicalize_path_maybe_not_exists(self.options.initial_cwd())?
|
||||||
.join("node_modules"),
|
.join("node_modules"),
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
||||||
|
@ -732,7 +732,7 @@ impl CliFactory {
|
||||||
.cli_node_resolver
|
.cli_node_resolver
|
||||||
.get_or_try_init_async(async {
|
.get_or_try_init_async(async {
|
||||||
Ok(Arc::new(CliNodeResolver::new(
|
Ok(Arc::new(CliNodeResolver::new(
|
||||||
Some(self.cjs_resolutions().clone()),
|
self.cjs_resolutions().clone(),
|
||||||
self.fs().clone(),
|
self.fs().clone(),
|
||||||
self.node_resolver().await?.clone(),
|
self.node_resolver().await?.clone(),
|
||||||
self.npm_resolver().await?.clone(),
|
self.npm_resolver().await?.clone(),
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::args::create_default_npmrc;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::args::CliLockfile;
|
use crate::args::CliLockfile;
|
||||||
use crate::args::PackageJsonInstallDepsProvider;
|
use crate::args::PackageJsonInstallDepsProvider;
|
||||||
|
use crate::args::DENO_FUTURE;
|
||||||
use crate::graph_util::CliJsrUrlProvider;
|
use crate::graph_util::CliJsrUrlProvider;
|
||||||
use crate::http_util::HttpClientProvider;
|
use crate::http_util::HttpClientProvider;
|
||||||
use crate::lsp::config::Config;
|
use crate::lsp::config::Config;
|
||||||
|
@ -16,6 +17,7 @@ use crate::npm::CliNpmResolverCreateOptions;
|
||||||
use crate::npm::CliNpmResolverManagedCreateOptions;
|
use crate::npm::CliNpmResolverManagedCreateOptions;
|
||||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||||
use crate::npm::ManagedCliNpmResolver;
|
use crate::npm::ManagedCliNpmResolver;
|
||||||
|
use crate::resolver::CjsResolutionStore;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
use crate::resolver::CliGraphResolverOptions;
|
use crate::resolver::CliGraphResolverOptions;
|
||||||
use crate::resolver::CliNodeResolver;
|
use crate::resolver::CliNodeResolver;
|
||||||
|
@ -38,6 +40,7 @@ use deno_runtime::deno_node::errors::ClosestPkgJsonError;
|
||||||
use deno_runtime::deno_node::NodeResolution;
|
use deno_runtime::deno_node::NodeResolution;
|
||||||
use deno_runtime::deno_node::NodeResolutionMode;
|
use deno_runtime::deno_node::NodeResolutionMode;
|
||||||
use deno_runtime::deno_node::NodeResolver;
|
use deno_runtime::deno_node::NodeResolver;
|
||||||
|
use deno_runtime::deno_node::NpmResolver;
|
||||||
use deno_runtime::deno_node::PackageJson;
|
use deno_runtime::deno_node::PackageJson;
|
||||||
use deno_runtime::fs_util::specifier_to_file_path;
|
use deno_runtime::fs_util::specifier_to_file_path;
|
||||||
use deno_semver::jsr::JsrPackageReqReference;
|
use deno_semver::jsr::JsrPackageReqReference;
|
||||||
|
@ -343,11 +346,29 @@ impl LspResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
|
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
|
||||||
let resolver = self.get_scope_resolver(Some(specifier));
|
fn has_node_modules_dir(specifier: &ModuleSpecifier) -> bool {
|
||||||
if let Some(npm_resolver) = &resolver.npm_resolver {
|
// consider any /node_modules/ directory as being in the node_modules
|
||||||
return npm_resolver.in_npm_package(specifier);
|
// folder for the LSP because it's pretty complicated to deal with multiple scopes
|
||||||
|
specifier.scheme() == "file"
|
||||||
|
&& specifier
|
||||||
|
.path()
|
||||||
|
.to_ascii_lowercase()
|
||||||
|
.contains("/node_modules/")
|
||||||
}
|
}
|
||||||
false
|
|
||||||
|
let global_npm_resolver = self
|
||||||
|
.get_scope_resolver(Some(specifier))
|
||||||
|
.npm_resolver
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|npm_resolver| npm_resolver.as_managed())
|
||||||
|
.filter(|r| r.root_node_modules_path().is_none());
|
||||||
|
if let Some(npm_resolver) = &global_npm_resolver {
|
||||||
|
if npm_resolver.in_npm_package(specifier) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
has_node_modules_dir(specifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_media_type(
|
pub fn node_media_type(
|
||||||
|
@ -422,20 +443,17 @@ async fn create_npm_resolver(
|
||||||
cache: &LspCache,
|
cache: &LspCache,
|
||||||
http_client_provider: &Arc<HttpClientProvider>,
|
http_client_provider: &Arc<HttpClientProvider>,
|
||||||
) -> Option<Arc<dyn CliNpmResolver>> {
|
) -> Option<Arc<dyn CliNpmResolver>> {
|
||||||
let mut byonm_dir = None;
|
let enable_byonm = config_data.map(|d| d.byonm).unwrap_or(*DENO_FUTURE);
|
||||||
if let Some(config_data) = config_data {
|
let options = if enable_byonm {
|
||||||
if config_data.byonm {
|
|
||||||
byonm_dir = Some(config_data.node_modules_dir.clone().or_else(|| {
|
|
||||||
specifier_to_file_path(&config_data.scope)
|
|
||||||
.ok()
|
|
||||||
.map(|p| p.join("node_modules/"))
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let options = if let Some(byonm_dir) = byonm_dir {
|
|
||||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||||
fs: Arc::new(deno_fs::RealFs),
|
fs: Arc::new(deno_fs::RealFs),
|
||||||
root_node_modules_dir: byonm_dir,
|
root_node_modules_dir: config_data.and_then(|config_data| {
|
||||||
|
config_data.node_modules_dir.clone().or_else(|| {
|
||||||
|
specifier_to_file_path(&config_data.scope)
|
||||||
|
.ok()
|
||||||
|
.map(|p| p.join("node_modules/"))
|
||||||
|
})
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
||||||
|
@ -478,6 +496,13 @@ async fn create_npm_resolver(
|
||||||
fn create_node_resolver(
|
fn create_node_resolver(
|
||||||
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
||||||
) -> Option<Arc<CliNodeResolver>> {
|
) -> Option<Arc<CliNodeResolver>> {
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
// it's not ideal to share this across all scopes and to
|
||||||
|
// never clear it, but it's fine for the time being
|
||||||
|
static CJS_RESOLUTIONS: Lazy<Arc<CjsResolutionStore>> =
|
||||||
|
Lazy::new(Default::default);
|
||||||
|
|
||||||
let npm_resolver = npm_resolver?;
|
let npm_resolver = npm_resolver?;
|
||||||
let fs = Arc::new(deno_fs::RealFs);
|
let fs = Arc::new(deno_fs::RealFs);
|
||||||
let node_resolver_inner = Arc::new(NodeResolver::new(
|
let node_resolver_inner = Arc::new(NodeResolver::new(
|
||||||
|
@ -485,7 +510,7 @@ fn create_node_resolver(
|
||||||
npm_resolver.clone().into_npm_resolver(),
|
npm_resolver.clone().into_npm_resolver(),
|
||||||
));
|
));
|
||||||
Some(Arc::new(CliNodeResolver::new(
|
Some(Arc::new(CliNodeResolver::new(
|
||||||
None,
|
CJS_RESOLUTIONS.clone(),
|
||||||
fs,
|
fs,
|
||||||
node_resolver_inner,
|
node_resolver_inner,
|
||||||
npm_resolver.clone(),
|
npm_resolver.clone(),
|
||||||
|
|
|
@ -4347,9 +4347,17 @@ fn op_release(
|
||||||
fn op_resolve(
|
fn op_resolve(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[string] base: String,
|
#[string] base: String,
|
||||||
|
is_base_cjs: bool,
|
||||||
#[serde] specifiers: Vec<String>,
|
#[serde] specifiers: Vec<String>,
|
||||||
) -> Result<Vec<Option<(String, String)>>, AnyError> {
|
) -> Result<Vec<Option<(String, String)>>, AnyError> {
|
||||||
op_resolve_inner(state, ResolveArgs { base, specifiers })
|
op_resolve_inner(
|
||||||
|
state,
|
||||||
|
ResolveArgs {
|
||||||
|
base,
|
||||||
|
is_base_cjs,
|
||||||
|
specifiers,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TscRequestArray {
|
struct TscRequestArray {
|
||||||
|
@ -6287,6 +6295,7 @@ mod tests {
|
||||||
&mut state,
|
&mut state,
|
||||||
ResolveArgs {
|
ResolveArgs {
|
||||||
base: "file:///a.ts".to_string(),
|
base: "file:///a.ts".to_string(),
|
||||||
|
is_base_cjs: false,
|
||||||
specifiers: vec!["./b.ts".to_string()],
|
specifiers: vec!["./b.ts".to_string()],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,7 +29,8 @@ use super::InnerCliNpmResolverRef;
|
||||||
|
|
||||||
pub struct CliNpmResolverByonmCreateOptions {
|
pub struct CliNpmResolverByonmCreateOptions {
|
||||||
pub fs: Arc<dyn FileSystem>,
|
pub fs: Arc<dyn FileSystem>,
|
||||||
pub root_node_modules_dir: PathBuf,
|
// todo(dsherret): investigate removing this
|
||||||
|
pub root_node_modules_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_byonm_npm_resolver(
|
pub fn create_byonm_npm_resolver(
|
||||||
|
@ -44,7 +45,7 @@ pub fn create_byonm_npm_resolver(
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ByonmCliNpmResolver {
|
pub struct ByonmCliNpmResolver {
|
||||||
fs: Arc<dyn FileSystem>,
|
fs: Arc<dyn FileSystem>,
|
||||||
root_node_modules_dir: PathBuf,
|
root_node_modules_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ByonmCliNpmResolver {
|
impl ByonmCliNpmResolver {
|
||||||
|
@ -131,16 +132,16 @@ impl ByonmCliNpmResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, fall fallback to the project's package.json
|
// otherwise, fall fallback to the project's package.json
|
||||||
let root_pkg_json_path = self
|
if let Some(root_node_modules_dir) = &self.root_node_modules_dir {
|
||||||
.root_node_modules_dir
|
let root_pkg_json_path =
|
||||||
.parent()
|
root_node_modules_dir.parent().unwrap().join("package.json");
|
||||||
.unwrap()
|
if let Some(pkg_json) =
|
||||||
.join("package.json");
|
load_pkg_json(self.fs.as_ref(), &root_pkg_json_path)?
|
||||||
if let Some(pkg_json) =
|
{
|
||||||
load_pkg_json(self.fs.as_ref(), &root_pkg_json_path)?
|
if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||||
{
|
{
|
||||||
if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref()) {
|
return Ok((pkg_json, alias));
|
||||||
return Ok((pkg_json, alias));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,9 +160,10 @@ impl NpmResolver for ByonmCliNpmResolver {
|
||||||
fn get_npm_process_state(&self) -> String {
|
fn get_npm_process_state(&self) -> String {
|
||||||
serde_json::to_string(&NpmProcessState {
|
serde_json::to_string(&NpmProcessState {
|
||||||
kind: NpmProcessStateKind::Byonm,
|
kind: NpmProcessStateKind::Byonm,
|
||||||
local_node_modules_path: Some(
|
local_node_modules_path: self
|
||||||
self.root_node_modules_dir.to_string_lossy().to_string(),
|
.root_node_modules_dir
|
||||||
),
|
.as_ref()
|
||||||
|
.map(|p| p.to_string_lossy().to_string()),
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -256,7 +258,7 @@ impl CliNpmResolver for ByonmCliNpmResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root_node_modules_path(&self) -> Option<&PathBuf> {
|
fn root_node_modules_path(&self) -> Option<&PathBuf> {
|
||||||
Some(&self.root_node_modules_dir)
|
self.root_node_modules_dir.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_pkg_folder_from_deno_module_req(
|
fn resolve_pkg_folder_from_deno_module_req(
|
||||||
|
|
|
@ -27,6 +27,7 @@ use deno_runtime::deno_node::errors::ClosestPkgJsonError;
|
||||||
use deno_runtime::deno_node::errors::UrlToNodeResolutionError;
|
use deno_runtime::deno_node::errors::UrlToNodeResolutionError;
|
||||||
use deno_runtime::deno_node::is_builtin_node_module;
|
use deno_runtime::deno_node::is_builtin_node_module;
|
||||||
use deno_runtime::deno_node::parse_npm_pkg_name;
|
use deno_runtime::deno_node::parse_npm_pkg_name;
|
||||||
|
use deno_runtime::deno_node::NodeModuleKind;
|
||||||
use deno_runtime::deno_node::NodeResolution;
|
use deno_runtime::deno_node::NodeResolution;
|
||||||
use deno_runtime::deno_node::NodeResolutionMode;
|
use deno_runtime::deno_node::NodeResolutionMode;
|
||||||
use deno_runtime::deno_node::NodeResolver;
|
use deno_runtime::deno_node::NodeResolver;
|
||||||
|
@ -66,8 +67,7 @@ pub struct ModuleCodeStringSource {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CliNodeResolver {
|
pub struct CliNodeResolver {
|
||||||
// not used in the LSP
|
cjs_resolutions: Arc<CjsResolutionStore>,
|
||||||
cjs_resolutions: Option<Arc<CjsResolutionStore>>,
|
|
||||||
fs: Arc<dyn deno_fs::FileSystem>,
|
fs: Arc<dyn deno_fs::FileSystem>,
|
||||||
node_resolver: Arc<NodeResolver>,
|
node_resolver: Arc<NodeResolver>,
|
||||||
// todo(dsherret): remove this pub(crate)
|
// todo(dsherret): remove this pub(crate)
|
||||||
|
@ -76,7 +76,7 @@ pub struct CliNodeResolver {
|
||||||
|
|
||||||
impl CliNodeResolver {
|
impl CliNodeResolver {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cjs_resolutions: Option<Arc<CjsResolutionStore>>,
|
cjs_resolutions: Arc<CjsResolutionStore>,
|
||||||
fs: Arc<dyn deno_fs::FileSystem>,
|
fs: Arc<dyn deno_fs::FileSystem>,
|
||||||
node_resolver: Arc<NodeResolver>,
|
node_resolver: Arc<NodeResolver>,
|
||||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||||
|
@ -120,10 +120,16 @@ impl CliNodeResolver {
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
mode: NodeResolutionMode,
|
mode: NodeResolutionMode,
|
||||||
) -> Result<Option<NodeResolution>, AnyError> {
|
) -> Result<Option<NodeResolution>, AnyError> {
|
||||||
|
let referrer_kind = if self.cjs_resolutions.contains(referrer) {
|
||||||
|
NodeModuleKind::Cjs
|
||||||
|
} else {
|
||||||
|
NodeModuleKind::Esm
|
||||||
|
};
|
||||||
|
|
||||||
self.handle_node_resolve_result(
|
self.handle_node_resolve_result(
|
||||||
self
|
self
|
||||||
.node_resolver
|
.node_resolver
|
||||||
.resolve(specifier, referrer, mode)
|
.resolve(specifier, referrer, referrer_kind, mode)
|
||||||
.map_err(AnyError::from),
|
.map_err(AnyError::from),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -241,16 +247,12 @@ impl CliNodeResolver {
|
||||||
let specifier =
|
let specifier =
|
||||||
crate::node::resolve_specifier_into_node_modules(&specifier);
|
crate::node::resolve_specifier_into_node_modules(&specifier);
|
||||||
if self.in_npm_package(&specifier) {
|
if self.in_npm_package(&specifier) {
|
||||||
if let Some(cjs_resolutions) = &self.cjs_resolutions {
|
let resolution =
|
||||||
let resolution =
|
self.node_resolver.url_to_node_resolution(specifier)?;
|
||||||
self.node_resolver.url_to_node_resolution(specifier)?;
|
if let NodeResolution::CommonJs(specifier) = &resolution {
|
||||||
if let NodeResolution::CommonJs(specifier) = &resolution {
|
self.cjs_resolutions.insert(specifier.clone());
|
||||||
cjs_resolutions.insert(specifier.clone());
|
|
||||||
}
|
|
||||||
return Ok(resolution.into_url());
|
|
||||||
} else {
|
|
||||||
return Ok(specifier);
|
|
||||||
}
|
}
|
||||||
|
return Ok(resolution.into_url());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,9 +274,7 @@ impl CliNodeResolver {
|
||||||
Some(response) => {
|
Some(response) => {
|
||||||
if let NodeResolution::CommonJs(specifier) = &response {
|
if let NodeResolution::CommonJs(specifier) = &response {
|
||||||
// remember that this was a common js resolution
|
// remember that this was a common js resolution
|
||||||
if let Some(cjs_resolutions) = &self.cjs_resolutions {
|
self.cjs_resolutions.insert(specifier.clone());
|
||||||
cjs_resolutions.insert(specifier.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(Some(response))
|
Ok(Some(response))
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub enum NodeModules {
|
||||||
node_modules_dir: Option<String>,
|
node_modules_dir: Option<String>,
|
||||||
},
|
},
|
||||||
Byonm {
|
Byonm {
|
||||||
root_node_modules_dir: String,
|
root_node_modules_dir: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,15 +572,16 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
||||||
Some(root_dir),
|
Some(root_dir),
|
||||||
files,
|
files,
|
||||||
Some(NodeModules::Byonm {
|
Some(NodeModules::Byonm {
|
||||||
root_node_modules_dir: root_dir_url
|
root_node_modules_dir: resolver.root_node_modules_path().map(
|
||||||
.specifier_key(
|
|node_modules_dir| {
|
||||||
&ModuleSpecifier::from_directory_path(
|
root_dir_url
|
||||||
// will always be set for byonm
|
.specifier_key(
|
||||||
resolver.root_node_modules_path().unwrap(),
|
&ModuleSpecifier::from_directory_path(node_modules_dir)
|
||||||
)
|
.unwrap(),
|
||||||
.unwrap(),
|
)
|
||||||
)
|
.into_owned()
|
||||||
.into_owned(),
|
},
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -490,7 +490,8 @@ pub async fn run(
|
||||||
let vfs_root_dir_path = root_path.clone();
|
let vfs_root_dir_path = root_path.clone();
|
||||||
let vfs = load_npm_vfs(vfs_root_dir_path.clone())
|
let vfs = load_npm_vfs(vfs_root_dir_path.clone())
|
||||||
.context("Failed to load vfs.")?;
|
.context("Failed to load vfs.")?;
|
||||||
let root_node_modules_dir = vfs.root().join(root_node_modules_dir);
|
let root_node_modules_dir =
|
||||||
|
root_node_modules_dir.map(|p| vfs.root().join(p));
|
||||||
let fs = Arc::new(DenoCompileFileSystem::new(vfs))
|
let fs = Arc::new(DenoCompileFileSystem::new(vfs))
|
||||||
as Arc<dyn deno_fs::FileSystem>;
|
as Arc<dyn deno_fs::FileSystem>;
|
||||||
let npm_resolver = create_cli_npm_resolver(
|
let npm_resolver = create_cli_npm_resolver(
|
||||||
|
@ -584,7 +585,7 @@ pub async fn run(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let cli_node_resolver = Arc::new(CliNodeResolver::new(
|
let cli_node_resolver = Arc::new(CliNodeResolver::new(
|
||||||
Some(cjs_resolutions.clone()),
|
cjs_resolutions.clone(),
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
node_resolver.clone(),
|
node_resolver.clone(),
|
||||||
npm_resolver.clone(),
|
npm_resolver.clone(),
|
||||||
|
|
|
@ -731,6 +731,7 @@ delete Object.prototype.__proto__;
|
||||||
/** @type {[string, ts.Extension] | undefined} */
|
/** @type {[string, ts.Extension] | undefined} */
|
||||||
const resolved = ops.op_resolve(
|
const resolved = ops.op_resolve(
|
||||||
containingFilePath,
|
containingFilePath,
|
||||||
|
isCjsCache.has(containingFilePath),
|
||||||
[fileReference.fileName],
|
[fileReference.fileName],
|
||||||
)?.[0];
|
)?.[0];
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
|
@ -764,6 +765,7 @@ delete Object.prototype.__proto__;
|
||||||
/** @type {Array<[string, ts.Extension] | undefined>} */
|
/** @type {Array<[string, ts.Extension] | undefined>} */
|
||||||
const resolved = ops.op_resolve(
|
const resolved = ops.op_resolve(
|
||||||
base,
|
base,
|
||||||
|
isCjsCache.has(base),
|
||||||
specifiers,
|
specifiers,
|
||||||
);
|
);
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ use deno_graph::GraphKind;
|
||||||
use deno_graph::Module;
|
use deno_graph::Module;
|
||||||
use deno_graph::ModuleGraph;
|
use deno_graph::ModuleGraph;
|
||||||
use deno_graph::ResolutionResolved;
|
use deno_graph::ResolutionResolved;
|
||||||
|
use deno_runtime::deno_node::NodeModuleKind;
|
||||||
use deno_runtime::deno_node::NodeResolution;
|
use deno_runtime::deno_node::NodeResolution;
|
||||||
use deno_runtime::deno_node::NodeResolutionMode;
|
use deno_runtime::deno_node::NodeResolutionMode;
|
||||||
use deno_runtime::deno_node::NodeResolver;
|
use deno_runtime::deno_node::NodeResolver;
|
||||||
|
@ -585,6 +586,8 @@ pub struct ResolveArgs {
|
||||||
/// The base specifier that the supplied specifier strings should be resolved
|
/// The base specifier that the supplied specifier strings should be resolved
|
||||||
/// relative to.
|
/// relative to.
|
||||||
pub base: String,
|
pub base: String,
|
||||||
|
/// If the base is cjs.
|
||||||
|
pub is_base_cjs: bool,
|
||||||
/// A list of specifiers that should be resolved.
|
/// A list of specifiers that should be resolved.
|
||||||
pub specifiers: Vec<String>,
|
pub specifiers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
@ -594,9 +597,17 @@ pub struct ResolveArgs {
|
||||||
fn op_resolve(
|
fn op_resolve(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[string] base: String,
|
#[string] base: String,
|
||||||
|
is_base_cjs: bool,
|
||||||
#[serde] specifiers: Vec<String>,
|
#[serde] specifiers: Vec<String>,
|
||||||
) -> Result<Vec<(String, String)>, AnyError> {
|
) -> Result<Vec<(String, String)>, AnyError> {
|
||||||
op_resolve_inner(state, ResolveArgs { base, specifiers })
|
op_resolve_inner(
|
||||||
|
state,
|
||||||
|
ResolveArgs {
|
||||||
|
base,
|
||||||
|
is_base_cjs,
|
||||||
|
specifiers,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -607,6 +618,11 @@ fn op_resolve_inner(
|
||||||
let state = state.borrow_mut::<State>();
|
let state = state.borrow_mut::<State>();
|
||||||
let mut resolved: Vec<(String, String)> =
|
let mut resolved: Vec<(String, String)> =
|
||||||
Vec::with_capacity(args.specifiers.len());
|
Vec::with_capacity(args.specifiers.len());
|
||||||
|
let referrer_kind = if args.is_base_cjs {
|
||||||
|
NodeModuleKind::Cjs
|
||||||
|
} else {
|
||||||
|
NodeModuleKind::Esm
|
||||||
|
};
|
||||||
let referrer = if let Some(remapped_specifier) =
|
let referrer = if let Some(remapped_specifier) =
|
||||||
state.remapped_specifiers.get(&args.base)
|
state.remapped_specifiers.get(&args.base)
|
||||||
{
|
{
|
||||||
|
@ -646,7 +662,12 @@ fn op_resolve_inner(
|
||||||
Some(ResolutionResolved { specifier, .. }) => {
|
Some(ResolutionResolved { specifier, .. }) => {
|
||||||
resolve_graph_specifier_types(specifier, &referrer, state)?
|
resolve_graph_specifier_types(specifier, &referrer, state)?
|
||||||
}
|
}
|
||||||
_ => resolve_non_graph_specifier_types(&specifier, &referrer, state)?,
|
_ => resolve_non_graph_specifier_types(
|
||||||
|
&specifier,
|
||||||
|
&referrer,
|
||||||
|
referrer_kind,
|
||||||
|
state,
|
||||||
|
)?,
|
||||||
};
|
};
|
||||||
let result = match maybe_result {
|
let result = match maybe_result {
|
||||||
Some((specifier, media_type)) => {
|
Some((specifier, media_type)) => {
|
||||||
|
@ -766,6 +787,7 @@ fn resolve_graph_specifier_types(
|
||||||
fn resolve_non_graph_specifier_types(
|
fn resolve_non_graph_specifier_types(
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
|
referrer_kind: NodeModuleKind,
|
||||||
state: &State,
|
state: &State,
|
||||||
) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> {
|
) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> {
|
||||||
let npm = match state.maybe_npm.as_ref() {
|
let npm = match state.maybe_npm.as_ref() {
|
||||||
|
@ -777,11 +799,17 @@ fn resolve_non_graph_specifier_types(
|
||||||
// we're in an npm package, so use node resolution
|
// we're in an npm package, so use node resolution
|
||||||
Ok(Some(NodeResolution::into_specifier_and_media_type(
|
Ok(Some(NodeResolution::into_specifier_and_media_type(
|
||||||
node_resolver
|
node_resolver
|
||||||
.resolve(specifier, referrer, NodeResolutionMode::Types)
|
.resolve(
|
||||||
|
specifier,
|
||||||
|
referrer,
|
||||||
|
referrer_kind,
|
||||||
|
NodeResolutionMode::Types,
|
||||||
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.flatten(),
|
.flatten(),
|
||||||
)))
|
)))
|
||||||
} else if let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier) {
|
} else if let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier) {
|
||||||
|
debug_assert_eq!(referrer_kind, NodeModuleKind::Esm);
|
||||||
// todo(dsherret): add support for injecting this in the graph so
|
// todo(dsherret): add support for injecting this in the graph so
|
||||||
// we don't need this special code here.
|
// we don't need this special code here.
|
||||||
// This could occur when resolving npm:@types/node when it is
|
// This could occur when resolving npm:@types/node when it is
|
||||||
|
@ -1184,6 +1212,7 @@ mod tests {
|
||||||
&mut state,
|
&mut state,
|
||||||
ResolveArgs {
|
ResolveArgs {
|
||||||
base: "https://deno.land/x/a.ts".to_string(),
|
base: "https://deno.land/x/a.ts".to_string(),
|
||||||
|
is_base_cjs: false,
|
||||||
specifiers: vec!["./b.ts".to_string()],
|
specifiers: vec!["./b.ts".to_string()],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -1206,6 +1235,7 @@ mod tests {
|
||||||
&mut state,
|
&mut state,
|
||||||
ResolveArgs {
|
ResolveArgs {
|
||||||
base: "https://deno.land/x/a.ts".to_string(),
|
base: "https://deno.land/x/a.ts".to_string(),
|
||||||
|
is_base_cjs: false,
|
||||||
specifiers: vec!["./bad.ts".to_string()],
|
specifiers: vec!["./bad.ts".to_string()],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -172,6 +172,7 @@ impl NodeResolver {
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
|
referrer_kind: NodeModuleKind,
|
||||||
mode: NodeResolutionMode,
|
mode: NodeResolutionMode,
|
||||||
) -> Result<Option<NodeResolution>, NodeResolveError> {
|
) -> Result<Option<NodeResolution>, NodeResolveError> {
|
||||||
// Note: if we are here, then the referrer is an esm module
|
// Note: if we are here, then the referrer is an esm module
|
||||||
|
@ -212,8 +213,16 @@ impl NodeResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let maybe_url =
|
let maybe_url = self.module_resolve(
|
||||||
self.module_resolve(specifier, referrer, DEFAULT_CONDITIONS, mode)?;
|
specifier,
|
||||||
|
referrer,
|
||||||
|
referrer_kind,
|
||||||
|
match referrer_kind {
|
||||||
|
NodeModuleKind::Esm => DEFAULT_CONDITIONS,
|
||||||
|
NodeModuleKind::Cjs => REQUIRE_CONDITIONS,
|
||||||
|
},
|
||||||
|
mode,
|
||||||
|
)?;
|
||||||
let url = match maybe_url {
|
let url = match maybe_url {
|
||||||
Some(url) => url,
|
Some(url) => url,
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
|
@ -229,6 +238,7 @@ impl NodeResolver {
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
|
referrer_kind: NodeModuleKind,
|
||||||
conditions: &[&str],
|
conditions: &[&str],
|
||||||
mode: NodeResolutionMode,
|
mode: NodeResolutionMode,
|
||||||
) -> Result<Option<ModuleSpecifier>, NodeResolveError> {
|
) -> Result<Option<ModuleSpecifier>, NodeResolveError> {
|
||||||
|
@ -250,7 +260,7 @@ impl NodeResolver {
|
||||||
Some(self.package_imports_resolve(
|
Some(self.package_imports_resolve(
|
||||||
specifier,
|
specifier,
|
||||||
Some(referrer),
|
Some(referrer),
|
||||||
NodeModuleKind::Esm,
|
referrer_kind,
|
||||||
pkg_config.as_deref(),
|
pkg_config.as_deref(),
|
||||||
conditions,
|
conditions,
|
||||||
mode,
|
mode,
|
||||||
|
@ -261,7 +271,7 @@ impl NodeResolver {
|
||||||
self.package_resolve(
|
self.package_resolve(
|
||||||
specifier,
|
specifier,
|
||||||
referrer,
|
referrer,
|
||||||
NodeModuleKind::Esm,
|
referrer_kind,
|
||||||
conditions,
|
conditions,
|
||||||
mode,
|
mode,
|
||||||
)?
|
)?
|
||||||
|
@ -273,13 +283,7 @@ impl NodeResolver {
|
||||||
|
|
||||||
let maybe_url = if mode.is_types() {
|
let maybe_url = if mode.is_types() {
|
||||||
let file_path = to_file_path(&url);
|
let file_path = to_file_path(&url);
|
||||||
// todo(16370): the referrer module kind is not correct here. I think we need
|
self.path_to_declaration_url(file_path, Some(referrer), referrer_kind)?
|
||||||
// typescript to tell us if the referrer is esm or cjs
|
|
||||||
self.path_to_declaration_url(
|
|
||||||
file_path,
|
|
||||||
Some(referrer),
|
|
||||||
NodeModuleKind::Esm,
|
|
||||||
)?
|
|
||||||
} else {
|
} else {
|
||||||
Some(url)
|
Some(url)
|
||||||
};
|
};
|
||||||
|
@ -1319,13 +1323,7 @@ impl NodeResolver {
|
||||||
source: source.into_io_error(),
|
source: source.into_io_error(),
|
||||||
},
|
},
|
||||||
)?);
|
)?);
|
||||||
let mut current_dir = current_dir.as_path();
|
for current_dir in current_dir.ancestors() {
|
||||||
let package_json_path = current_dir.join("package.json");
|
|
||||||
if let Some(pkg_json) = self.load_package_json(&package_json_path)? {
|
|
||||||
return Ok(Some(pkg_json));
|
|
||||||
}
|
|
||||||
while let Some(parent) = current_dir.parent() {
|
|
||||||
current_dir = parent;
|
|
||||||
let package_json_path = current_dir.join("package.json");
|
let package_json_path = current_dir.join("package.json");
|
||||||
if let Some(pkg_json) = self.load_package_json(&package_json_path)? {
|
if let Some(pkg_json) = self.load_package_json(&package_json_path)? {
|
||||||
return Ok(Some(pkg_json));
|
return Ok(Some(pkg_json));
|
||||||
|
|
|
@ -14500,6 +14500,55 @@ fn lsp_cjs_internal_types_default_export() {
|
||||||
assert_eq!(json!(diagnostics.all()), json!([]));
|
assert_eq!(json!(diagnostics.all()), json!([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lsp_cjs_import_dual() {
|
||||||
|
let context = TestContextBuilder::new()
|
||||||
|
.use_http_server()
|
||||||
|
.use_temp_cwd()
|
||||||
|
.add_npm_env_vars()
|
||||||
|
.env("DENO_FUTURE", "1")
|
||||||
|
.build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
|
temp_dir.write("deno.json", r#"{}"#);
|
||||||
|
temp_dir.write(
|
||||||
|
"package.json",
|
||||||
|
r#"{
|
||||||
|
"dependencies": {
|
||||||
|
"@denotest/cjs-import-dual": "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").uri_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 { getKind } from 'npm:@denotest/cjs-import-dual@1';\nconst kind: 'esm' = 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 '\"esm\"'.",
|
||||||
|
}])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_ts_code_fix_any_param() {
|
fn lsp_ts_code_fix_any_param() {
|
||||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
|
2
tests/registry/npm/@denotest/cjs-import-dual/1.0.0/index.d.ts
vendored
Normal file
2
tests/registry/npm/@denotest/cjs-import-dual/1.0.0/index.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// it should pick up the cjs types
|
||||||
|
export { getKind } from "@denotest/dual-cjs-esm";
|
|
@ -0,0 +1 @@
|
||||||
|
module.exports.getKind = require("@denotest/dual-cjs-esm").getKind;
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "@denotest/cjs-import-dual",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@denotest/dual-cjs-esm": "1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
export function getKind(): string;
|
export function getKind(): "cjs";
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export function getKind(): string;
|
export function getKind(): "esm";
|
||||||
|
|
13
tests/specs/npm/cjs_import_dual/__test__.jsonc
Normal file
13
tests/specs/npm/cjs_import_dual/__test__.jsonc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"tests": {
|
||||||
|
"run": {
|
||||||
|
"args": "run main.ts",
|
||||||
|
"output": "run.out"
|
||||||
|
},
|
||||||
|
"check": {
|
||||||
|
"args": "check --all main.ts",
|
||||||
|
"exitCode": 1,
|
||||||
|
"output": "check.out"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
tests/specs/npm/cjs_import_dual/check.out
Normal file
9
tests/specs/npm/cjs_import_dual/check.out
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Download http://localhost:4260/@denotest/cjs-import-dual
|
||||||
|
Download http://localhost:4260/@denotest/dual-cjs-esm
|
||||||
|
Download http://localhost:4260/@denotest/cjs-import-dual/1.0.0.tgz
|
||||||
|
Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
|
||||||
|
Check file:///[WILDLINE]/cjs_import_dual/main.ts
|
||||||
|
error: TS2322 [ERROR]: Type '"cjs"' is not assignable to type '"esm"'.
|
||||||
|
const kind: "esm" = getKind(); // should cause a type error
|
||||||
|
~~~~
|
||||||
|
at file:///[WILDLINE]/cjs_import_dual/main.ts:3:7
|
4
tests/specs/npm/cjs_import_dual/main.ts
Normal file
4
tests/specs/npm/cjs_import_dual/main.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { getKind } from "npm:@denotest/cjs-import-dual@1";
|
||||||
|
|
||||||
|
const kind: "esm" = getKind(); // should cause a type error
|
||||||
|
console.log(kind);
|
5
tests/specs/npm/cjs_import_dual/run.out
Normal file
5
tests/specs/npm/cjs_import_dual/run.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Download http://localhost:4260/@denotest/cjs-import-dual
|
||||||
|
Download http://localhost:4260/@denotest/dual-cjs-esm
|
||||||
|
Download http://localhost:4260/@denotest/cjs-import-dual/1.0.0.tgz
|
||||||
|
Download http://localhost:4260/@denotest/dual-cjs-esm/1.0.0.tgz
|
||||||
|
cjs
|
Loading…
Reference in a new issue