Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(unstable): ability to resolve specifiers with no extension, specifiers for a directory, and TS files from JS extensions #21464

Merged
merged 18 commits into from
Dec 7, 2023
Merged
Prev Previous commit
Next Next commit
Loose -> Sloppy
  • Loading branch information
dsherret committed Dec 5, 2023
commit d38736ca962bbb4224abcfb354ffdc49a4ee3273
8 changes: 4 additions & 4 deletions cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ pub struct Flags {
pub unstable: bool,
pub unstable_bare_node_builtins: bool,
pub unstable_byonm: bool,
pub unstable_loose_imports: bool,
pub unstable_sloppy_imports: bool,
pub unstable_workspaces: bool,
pub unstable_features: Vec<String>,
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
Expand Down Expand Up @@ -855,7 +855,7 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::error::Result<Flags> {
flags.unstable_bare_node_builtins =
matches.get_flag("unstable-bare-node-builtins");
flags.unstable_byonm = matches.get_flag("unstable-byonm");
flags.unstable_loose_imports = matches.get_flag("unstable-loose-imports");
flags.unstable_sloppy_imports = matches.get_flag("unstable-sloppy-imports");
flags.unstable_workspaces = matches.get_flag("unstable-workspaces");

if matches.get_flag("quiet") {
Expand Down Expand Up @@ -974,8 +974,8 @@ fn clap_root() -> Command {
.global(true),
)
.arg(
Arg::new("unstable-loose-imports")
.long("unstable-loose-imports")
Arg::new("unstable-sloppy-imports")
.long("unstable-sloppy-imports")
.help(
"Enable unstable resolving of specifiers by extension probing, .js to .ts, and directory probing.",
)
Expand Down
6 changes: 3 additions & 3 deletions cli/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1340,12 +1340,12 @@ impl CliOptions {
.unwrap_or(false)
}

pub fn unstable_loose_imports(&self) -> bool {
self.flags.unstable_loose_imports
pub fn unstable_sloppy_imports(&self) -> bool {
self.flags.unstable_sloppy_imports
|| self
.maybe_config_file()
.as_ref()
.map(|c| c.has_unstable("loose-imports"))
.map(|c| c.has_unstable("sloppy-imports"))
.unwrap_or(false)
}

Expand Down
6 changes: 3 additions & 3 deletions cli/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use crate::npm::CliNpmResolverManagedPackageJsonInstallerOption;
use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::resolver::CliGraphResolver;
use crate::resolver::CliGraphResolverOptions;
use crate::resolver::UnstableLooseImportsResolver;
use crate::resolver::UnstableSloppyImportsResolver;
use crate::standalone::DenoCompileBinaryWriter;
use crate::tools::check::TypeChecker;
use crate::util::file_watcher::WatcherCommunicator;
Expand Down Expand Up @@ -384,8 +384,8 @@ impl CliFactory {
Ok(Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
fs: self.fs().clone(),
cjs_resolutions: Some(self.cjs_resolutions().clone()),
loose_imports_resolver: if self.options.unstable_loose_imports() {
Some(UnstableLooseImportsResolver::new(self.fs().clone()))
sloppy_imports_resolver: if self.options.unstable_sloppy_imports() {
Some(UnstableSloppyImportsResolver::new(self.fs().clone()))
} else {
None
},
Expand Down
48 changes: 24 additions & 24 deletions cli/lsp/documents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use crate::lsp::logging::lsp_warn;
use crate::npm::CliNpmResolver;
use crate::resolver::CliGraphResolver;
use crate::resolver::CliGraphResolverOptions;
use crate::resolver::UnstableLooseImportsFsEntry;
use crate::resolver::UnstableLooseImportsResolver;
use crate::resolver::UnstableSloppyImportsFsEntry;
use crate::resolver::UnstableSloppyImportsResolver;
use crate::util::glob;
use crate::util::path::specifier_to_file_path;
use crate::util::text_encoding;
Expand Down Expand Up @@ -891,8 +891,8 @@ pub struct Documents {
has_injected_types_node_package: bool,
/// Resolves a specifier to its final redirected to specifier.
redirect_resolver: Arc<RedirectResolver>,
/// If --unstable-loose-imports is enabled.
unstable_loose_imports: bool,
/// If --unstable-sloppy-imports is enabled.
unstable_sloppy_imports: bool,
}

impl Documents {
Expand All @@ -915,12 +915,12 @@ impl Documents {
maybe_import_map: None,
maybe_vendor_dir: None,
bare_node_builtins_enabled: false,
loose_imports_resolver: None,
sloppy_imports_resolver: None,
})),
npm_specifier_reqs: Default::default(),
has_injected_types_node_package: false,
redirect_resolver: Arc::new(RedirectResolver::new(cache)),
unstable_loose_imports: false,
unstable_sloppy_imports: false,
}
}

Expand Down Expand Up @@ -1050,30 +1050,30 @@ impl Documents {
&self,
specifier: &ModuleSpecifier,
) -> Option<ModuleSpecifier> {
if specifier.scheme() == "file" && self.unstable_loose_imports {
Some(self.resolve_unstable_loose_import(specifier).into_owned())
if specifier.scheme() == "file" && self.unstable_sloppy_imports {
dsherret marked this conversation as resolved.
Show resolved Hide resolved
Some(self.resolve_unstable_sloppy_import(specifier).into_owned())
} else {
self.redirect_resolver.resolve(specifier)
}
}

fn resolve_unstable_loose_import<'a>(
fn resolve_unstable_sloppy_import<'a>(
&self,
specifier: &'a ModuleSpecifier,
) -> Cow<'a, ModuleSpecifier> {
UnstableLooseImportsResolver::resolve_with_stat_sync(specifier, |path| {
UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
if self.open_docs.contains_key(&specifier)
|| self.cache.contains(&specifier)
{
return Some(UnstableLooseImportsFsEntry::File);
return Some(UnstableSloppyImportsFsEntry::File);
}
}
path.metadata().ok().and_then(|m| {
if m.is_file() {
Some(UnstableLooseImportsFsEntry::File)
Some(UnstableSloppyImportsFsEntry::File)
} else if m.is_dir() {
Some(UnstableLooseImportsFsEntry::Dir)
Some(UnstableSloppyImportsFsEntry::Dir)
} else {
None
}
Expand Down Expand Up @@ -1376,7 +1376,7 @@ impl Documents {
// Don't set this for the LSP because instead we'll use the OpenDocumentsLoader
// because it's much easier and we get diagnostics/quick fixes about a redirected
// specifier for free.
loose_imports_resolver: None,
sloppy_imports_resolver: None,
}));
self.redirect_resolver =
Arc::new(RedirectResolver::new(self.cache.clone()));
Expand All @@ -1400,9 +1400,9 @@ impl Documents {
IndexMap::new()
},
);
self.unstable_loose_imports = options
self.unstable_sloppy_imports = options
.maybe_config_file
.map(|c| c.has_unstable("loose-imports"))
.map(|c| c.has_unstable("sloppy-imports"))
.unwrap_or(false);

// only refresh the dependencies if the underlying configuration has changed
Expand Down Expand Up @@ -1701,7 +1701,7 @@ fn node_resolve_npm_req_ref(
pub struct OpenDocumentsGraphLoader<'a> {
pub inner_loader: &'a mut dyn deno_graph::source::Loader,
pub open_docs: &'a HashMap<ModuleSpecifier, Document>,
pub unstable_loose_imports: bool,
pub unstable_sloppy_imports: bool,
}

impl<'a> OpenDocumentsGraphLoader<'a> {
Expand All @@ -1724,21 +1724,21 @@ impl<'a> OpenDocumentsGraphLoader<'a> {
None
}

fn resolve_unstable_loose_import<'b>(
fn resolve_unstable_sloppy_import<'b>(
&self,
specifier: &'b ModuleSpecifier,
) -> Cow<'b, ModuleSpecifier> {
UnstableLooseImportsResolver::resolve_with_stat_sync(specifier, |path| {
UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
if self.open_docs.contains_key(&specifier) {
return Some(UnstableLooseImportsFsEntry::File);
return Some(UnstableSloppyImportsFsEntry::File);
}
}
path.metadata().ok().and_then(|m| {
if m.is_file() {
Some(UnstableLooseImportsFsEntry::File)
Some(UnstableSloppyImportsFsEntry::File)
} else if m.is_dir() {
Some(UnstableLooseImportsFsEntry::Dir)
Some(UnstableSloppyImportsFsEntry::Dir)
} else {
None
}
Expand All @@ -1758,8 +1758,8 @@ impl<'a> deno_graph::source::Loader for OpenDocumentsGraphLoader<'a> {
is_dynamic: bool,
cache_setting: deno_graph::source::CacheSetting,
) -> deno_graph::source::LoadFuture {
let specifier = if self.unstable_loose_imports {
self.resolve_unstable_loose_import(specifier)
let specifier = if self.unstable_sloppy_imports {
self.resolve_unstable_sloppy_import(specifier)
} else {
Cow::Borrowed(specifier)
};
Expand Down
2 changes: 1 addition & 1 deletion cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl LanguageServer {
let mut loader = crate::lsp::documents::OpenDocumentsGraphLoader {
inner_loader: &mut inner_loader,
open_docs: &open_docs,
unstable_loose_imports: cli_options.unstable_loose_imports(),
unstable_sloppy_imports: cli_options.unstable_sloppy_imports(),
};
let graph = module_graph_builder
.create_graph_with_loader(GraphKind::All, roots.clone(), &mut loader)
Expand Down
71 changes: 37 additions & 34 deletions cli/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl MappedSpecifierResolver {
#[derive(Debug)]
pub struct CliGraphResolver {
fs: Arc<dyn FileSystem>,
loose_imports_resolver: Option<UnstableLooseImportsResolver>,
sloppy_imports_resolver: Option<UnstableSloppyImportsResolver>,
mapped_specifier_resolver: MappedSpecifierResolver,
maybe_default_jsx_import_source: Option<String>,
maybe_jsx_import_source_module: Option<String>,
Expand All @@ -132,7 +132,7 @@ pub struct CliGraphResolver {
pub struct CliGraphResolverOptions<'a> {
pub fs: Arc<dyn FileSystem>,
pub cjs_resolutions: Option<Arc<CjsResolutionStore>>,
pub loose_imports_resolver: Option<UnstableLooseImportsResolver>,
pub sloppy_imports_resolver: Option<UnstableSloppyImportsResolver>,
pub node_resolver: Option<Arc<NodeResolver>>,
pub npm_resolver: Option<Arc<dyn CliNpmResolver>>,
pub package_json_deps_provider: Arc<PackageJsonDepsProvider>,
Expand All @@ -152,7 +152,7 @@ impl CliGraphResolver {
Self {
fs: options.fs,
cjs_resolutions: options.cjs_resolutions,
loose_imports_resolver: options.loose_imports_resolver,
sloppy_imports_resolver: options.sloppy_imports_resolver,
mapped_specifier_resolver: MappedSpecifierResolver::new(
options.maybe_import_map,
if is_byonm {
Expand Down Expand Up @@ -270,16 +270,19 @@ impl Resolver for CliGraphResolver {
}
};

// do loose imports resolution if enabled
let result = if let Some(loose_imports_resolver) =
&self.loose_imports_resolver
{
result.map(|specifier| {
loose_imports_resolve(loose_imports_resolver, specifier, referrer_range)
})
} else {
result
};
// do sloppy imports resolution if enabled
let result =
if let Some(sloppy_imports_resolver) = &self.sloppy_imports_resolver {
result.map(|specifier| {
sloppy_imports_resolve(
sloppy_imports_resolver,
specifier,
referrer_range,
)
})
} else {
result
};

// When the user is vendoring, don't allow them to import directly from the vendor/ directory
// as it might cause them confusion or duplicate dependencies. Additionally, this folder has
Expand Down Expand Up @@ -395,8 +398,8 @@ impl Resolver for CliGraphResolver {
}
}

fn loose_imports_resolve(
resolver: &UnstableLooseImportsResolver,
fn sloppy_imports_resolve(
resolver: &UnstableSloppyImportsResolver,
specifier: ModuleSpecifier,
referrer_range: &deno_graph::Range,
) -> ModuleSpecifier {
Expand Down Expand Up @@ -517,20 +520,20 @@ impl NpmResolver for CliGraphResolver {
}

#[derive(Debug)]
struct UnstableLooseImportsStatCache {
struct UnstableSloppyImportsStatCache {
fs: Arc<dyn FileSystem>,
cache: Mutex<HashMap<PathBuf, Option<UnstableLooseImportsFsEntry>>>,
cache: Mutex<HashMap<PathBuf, Option<UnstableSloppyImportsFsEntry>>>,
}

impl UnstableLooseImportsStatCache {
impl UnstableSloppyImportsStatCache {
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
Self {
fs,
cache: Default::default(),
}
}

pub fn stat_sync(&self, path: &Path) -> Option<UnstableLooseImportsFsEntry> {
pub fn stat_sync(&self, path: &Path) -> Option<UnstableSloppyImportsFsEntry> {
// there will only ever be one thread in here at a
// time, so it's ok to hold the lock for so long
let mut cache = self.cache.lock();
Expand All @@ -540,9 +543,9 @@ impl UnstableLooseImportsStatCache {

let entry = self.fs.stat_sync(path).ok().and_then(|stat| {
if stat.is_file {
Some(UnstableLooseImportsFsEntry::File)
Some(UnstableSloppyImportsFsEntry::File)
} else if stat.is_directory {
Some(UnstableLooseImportsFsEntry::Dir)
Some(UnstableSloppyImportsFsEntry::Dir)
} else {
None
}
Expand All @@ -553,26 +556,26 @@ impl UnstableLooseImportsStatCache {
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnstableLooseImportsFsEntry {
pub enum UnstableSloppyImportsFsEntry {
File,
Dir,
}

#[derive(Debug)]
pub struct UnstableLooseImportsResolver {
stat_cache: UnstableLooseImportsStatCache,
pub struct UnstableSloppyImportsResolver {
stat_cache: UnstableSloppyImportsStatCache,
}

impl UnstableLooseImportsResolver {
impl UnstableSloppyImportsResolver {
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
Self {
stat_cache: UnstableLooseImportsStatCache::new(fs),
stat_cache: UnstableSloppyImportsStatCache::new(fs),
}
}

pub fn resolve_with_stat_sync(
specifier: &ModuleSpecifier,
stat_sync: impl Fn(&Path) -> Option<UnstableLooseImportsFsEntry>,
stat_sync: impl Fn(&Path) -> Option<UnstableSloppyImportsFsEntry>,
) -> Cow<ModuleSpecifier> {
if specifier.scheme() != "file" {
return Cow::Borrowed(specifier);
Expand All @@ -582,10 +585,10 @@ impl UnstableLooseImportsResolver {
return Cow::Borrowed(specifier);
};
let probe_paths = match (stat_sync)(&path) {
Some(UnstableLooseImportsFsEntry::File) => {
Some(UnstableSloppyImportsFsEntry::File) => {
return Cow::Borrowed(specifier);
}
Some(UnstableLooseImportsFsEntry::Dir) => {
Some(UnstableSloppyImportsFsEntry::Dir) => {
// try to resolve at the index file
vec![
path.join("index.ts"),
Expand Down Expand Up @@ -645,7 +648,7 @@ impl UnstableLooseImportsResolver {
};

for probe_path in probe_paths {
if (stat_sync)(&probe_path) == Some(UnstableLooseImportsFsEntry::File) {
if (stat_sync)(&probe_path) == Some(UnstableSloppyImportsFsEntry::File) {
if let Ok(specifier) = ModuleSpecifier::from_file_path(probe_path) {
return Cow::Owned(specifier);
}
Expand Down Expand Up @@ -735,14 +738,14 @@ mod test {
}

#[test]
fn test_unstable_loose_imports() {
fn test_unstable_sloppy_imports() {
fn resolve(specifier: &ModuleSpecifier) -> Cow<ModuleSpecifier> {
UnstableLooseImportsResolver::resolve_with_stat_sync(specifier, |path| {
UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
RealFs.stat_sync(path).ok().and_then(|stat| {
if stat.is_file {
Some(UnstableLooseImportsFsEntry::File)
Some(UnstableSloppyImportsFsEntry::File)
} else if stat.is_directory {
Some(UnstableLooseImportsFsEntry::Dir)
Some(UnstableSloppyImportsFsEntry::Dir)
} else {
None
}
Expand Down
Loading