mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat: add suggestions to module not found error messages for file urls (#21498)
This commit is contained in:
parent
3f96e5a29a
commit
78566753c8
12 changed files with 277 additions and 67 deletions
|
@ -39,7 +39,7 @@ use crate::npm::CliNpmResolverManagedPackageJsonInstallerOption;
|
||||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
use crate::resolver::CliGraphResolverOptions;
|
use crate::resolver::CliGraphResolverOptions;
|
||||||
use crate::resolver::UnstableSloppyImportsResolver;
|
use crate::resolver::SloppyImportsResolver;
|
||||||
use crate::standalone::DenoCompileBinaryWriter;
|
use crate::standalone::DenoCompileBinaryWriter;
|
||||||
use crate::tools::check::TypeChecker;
|
use crate::tools::check::TypeChecker;
|
||||||
use crate::util::file_watcher::WatcherCommunicator;
|
use crate::util::file_watcher::WatcherCommunicator;
|
||||||
|
@ -383,7 +383,7 @@ impl CliFactory {
|
||||||
fs: self.fs().clone(),
|
fs: self.fs().clone(),
|
||||||
cjs_resolutions: Some(self.cjs_resolutions().clone()),
|
cjs_resolutions: Some(self.cjs_resolutions().clone()),
|
||||||
sloppy_imports_resolver: if self.options.unstable_sloppy_imports() {
|
sloppy_imports_resolver: if self.options.unstable_sloppy_imports() {
|
||||||
Some(UnstableSloppyImportsResolver::new(self.fs().clone()))
|
Some(SloppyImportsResolver::new(self.fs().clone()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,12 +12,15 @@ use crate::errors::get_error_class_name;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
use crate::npm::CliNpmResolver;
|
use crate::npm::CliNpmResolver;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
|
use crate::resolver::SloppyImportsResolution;
|
||||||
|
use crate::resolver::SloppyImportsResolver;
|
||||||
use crate::tools::check;
|
use crate::tools::check;
|
||||||
use crate::tools::check::TypeChecker;
|
use crate::tools::check::TypeChecker;
|
||||||
use crate::util::file_watcher::WatcherCommunicator;
|
use crate::util::file_watcher::WatcherCommunicator;
|
||||||
use crate::util::sync::TaskQueue;
|
use crate::util::sync::TaskQueue;
|
||||||
use crate::util::sync::TaskQueuePermit;
|
use crate::util::sync::TaskQueuePermit;
|
||||||
|
|
||||||
|
use deno_ast::MediaType;
|
||||||
use deno_core::anyhow::bail;
|
use deno_core::anyhow::bail;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::custom_error;
|
use deno_core::error::custom_error;
|
||||||
|
@ -58,11 +61,13 @@ pub struct GraphValidOptions {
|
||||||
/// error statically reachable from `roots` and not a dynamic import.
|
/// error statically reachable from `roots` and not a dynamic import.
|
||||||
pub fn graph_valid_with_cli_options(
|
pub fn graph_valid_with_cli_options(
|
||||||
graph: &ModuleGraph,
|
graph: &ModuleGraph,
|
||||||
|
fs: &Arc<dyn FileSystem>,
|
||||||
roots: &[ModuleSpecifier],
|
roots: &[ModuleSpecifier],
|
||||||
options: &CliOptions,
|
options: &CliOptions,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
graph_valid(
|
graph_valid(
|
||||||
graph,
|
graph,
|
||||||
|
fs,
|
||||||
roots,
|
roots,
|
||||||
GraphValidOptions {
|
GraphValidOptions {
|
||||||
is_vendoring: false,
|
is_vendoring: false,
|
||||||
|
@ -81,6 +86,7 @@ pub fn graph_valid_with_cli_options(
|
||||||
/// for the CLI.
|
/// for the CLI.
|
||||||
pub fn graph_valid(
|
pub fn graph_valid(
|
||||||
graph: &ModuleGraph,
|
graph: &ModuleGraph,
|
||||||
|
fs: &Arc<dyn FileSystem>,
|
||||||
roots: &[ModuleSpecifier],
|
roots: &[ModuleSpecifier],
|
||||||
options: GraphValidOptions,
|
options: GraphValidOptions,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
|
@ -109,10 +115,12 @@ pub fn graph_valid(
|
||||||
ModuleGraphError::TypesResolutionError(resolution_error) => {
|
ModuleGraphError::TypesResolutionError(resolution_error) => {
|
||||||
format!(
|
format!(
|
||||||
"Failed resolving types. {}",
|
"Failed resolving types. {}",
|
||||||
enhanced_resolution_error_message(resolution_error,)
|
enhanced_resolution_error_message(resolution_error)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ModuleGraphError::ModuleError(_) => format!("{error}"),
|
ModuleGraphError::ModuleError(e) => {
|
||||||
|
enhanced_module_error_message(fs, e)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(range) = error.maybe_range() {
|
if let Some(range) = error.maybe_range() {
|
||||||
|
@ -356,7 +364,12 @@ impl ModuleGraphBuilder {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let graph = Arc::new(graph);
|
let graph = Arc::new(graph);
|
||||||
graph_valid_with_cli_options(&graph, &graph.roots, &self.options)?;
|
graph_valid_with_cli_options(
|
||||||
|
&graph,
|
||||||
|
&self.fs,
|
||||||
|
&graph.roots,
|
||||||
|
&self.options,
|
||||||
|
)?;
|
||||||
if let Some(lockfile) = &self.lockfile {
|
if let Some(lockfile) = &self.lockfile {
|
||||||
graph_lock_or_exit(&graph, &mut lockfile.lock());
|
graph_lock_or_exit(&graph, &mut lockfile.lock());
|
||||||
}
|
}
|
||||||
|
@ -524,6 +537,68 @@ pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enhanced_module_error_message(
|
||||||
|
fs: &Arc<dyn FileSystem>,
|
||||||
|
error: &ModuleError,
|
||||||
|
) -> String {
|
||||||
|
let additional_message = match error {
|
||||||
|
ModuleError::Missing(specifier, _) => {
|
||||||
|
maybe_sloppy_imports_suggestion_message(fs, specifier)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(message) = additional_message {
|
||||||
|
format!(
|
||||||
|
"{} {} or run with --unstable-sloppy-imports",
|
||||||
|
error, message
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("{}", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maybe_sloppy_imports_suggestion_message(
|
||||||
|
fs: &Arc<dyn FileSystem>,
|
||||||
|
original_specifier: &ModuleSpecifier,
|
||||||
|
) -> Option<String> {
|
||||||
|
let sloppy_imports_resolver = SloppyImportsResolver::new(fs.clone());
|
||||||
|
let resolution = sloppy_imports_resolver.resolve(original_specifier);
|
||||||
|
sloppy_import_resolution_to_suggestion_message(&resolution)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sloppy_import_resolution_to_suggestion_message(
|
||||||
|
resolution: &SloppyImportsResolution,
|
||||||
|
) -> Option<String> {
|
||||||
|
match resolution {
|
||||||
|
SloppyImportsResolution::None(_) => None,
|
||||||
|
SloppyImportsResolution::JsToTs(specifier) => {
|
||||||
|
let media_type = MediaType::from_specifier(specifier);
|
||||||
|
Some(format!(
|
||||||
|
"Maybe change the extension to '{}'",
|
||||||
|
media_type.as_ts_extension()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SloppyImportsResolution::NoExtension(specifier) => {
|
||||||
|
let media_type = MediaType::from_specifier(specifier);
|
||||||
|
Some(format!(
|
||||||
|
"Maybe add a '{}' extension",
|
||||||
|
media_type.as_ts_extension()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SloppyImportsResolution::Directory(specifier) => {
|
||||||
|
let file_name = specifier
|
||||||
|
.path()
|
||||||
|
.rsplit_once('/')
|
||||||
|
.map(|(_, file_name)| file_name)
|
||||||
|
.unwrap_or(specifier.path());
|
||||||
|
Some(format!(
|
||||||
|
"Maybe specify path to '{}' file in directory instead",
|
||||||
|
file_name
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_resolution_error_bare_node_specifier(
|
pub fn get_resolution_error_bare_node_specifier(
|
||||||
error: &ResolutionError,
|
error: &ResolutionError,
|
||||||
) -> Option<&str> {
|
) -> Option<&str> {
|
||||||
|
@ -897,4 +972,46 @@ mod test {
|
||||||
assert_eq!(get_resolution_error_bare_node_specifier(&err), output,);
|
assert_eq!(get_resolution_error_bare_node_specifier(&err), output,);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sloppy_import_resolution_to_message() {
|
||||||
|
// none
|
||||||
|
let url = ModuleSpecifier::parse("file:///dir/index.js").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
sloppy_import_resolution_to_suggestion_message(
|
||||||
|
&SloppyImportsResolution::None(&url)
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
// directory
|
||||||
|
assert_eq!(
|
||||||
|
sloppy_import_resolution_to_suggestion_message(
|
||||||
|
&SloppyImportsResolution::Directory(
|
||||||
|
ModuleSpecifier::parse("file:///dir/index.js").unwrap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
"Maybe specify path to 'index.js' file in directory instead"
|
||||||
|
);
|
||||||
|
// no ext
|
||||||
|
assert_eq!(
|
||||||
|
sloppy_import_resolution_to_suggestion_message(
|
||||||
|
&SloppyImportsResolution::NoExtension(
|
||||||
|
ModuleSpecifier::parse("file:///dir/index.mjs").unwrap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
"Maybe add a '.mjs' extension"
|
||||||
|
);
|
||||||
|
// js to ts
|
||||||
|
assert_eq!(
|
||||||
|
sloppy_import_resolution_to_suggestion_message(
|
||||||
|
&SloppyImportsResolution::JsToTs(
|
||||||
|
ModuleSpecifier::parse("file:///dir/index.mts").unwrap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
"Maybe change the extension to '.mts'"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ use deno_graph::Resolution;
|
||||||
use deno_graph::ResolutionError;
|
use deno_graph::ResolutionError;
|
||||||
use deno_graph::SpecifierError;
|
use deno_graph::SpecifierError;
|
||||||
use deno_lint::rules::LintRule;
|
use deno_lint::rules::LintRule;
|
||||||
|
use deno_runtime::deno_fs;
|
||||||
use deno_runtime::deno_node;
|
use deno_runtime::deno_node;
|
||||||
use deno_runtime::tokio_util::create_basic_runtime;
|
use deno_runtime::tokio_util::create_basic_runtime;
|
||||||
use deno_semver::npm::NpmPackageReqReference;
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
|
@ -1166,6 +1167,21 @@ impl DenoDiagnostic {
|
||||||
/// Convert to an lsp Diagnostic when the range the diagnostic applies to is
|
/// Convert to an lsp Diagnostic when the range the diagnostic applies to is
|
||||||
/// provided.
|
/// provided.
|
||||||
pub fn to_lsp_diagnostic(&self, range: &lsp::Range) -> lsp::Diagnostic {
|
pub fn to_lsp_diagnostic(&self, range: &lsp::Range) -> lsp::Diagnostic {
|
||||||
|
fn no_local_message(specifier: &ModuleSpecifier) -> String {
|
||||||
|
let fs: Arc<dyn deno_fs::FileSystem> = Arc::new(deno_fs::RealFs);
|
||||||
|
let mut message =
|
||||||
|
format!("Unable to load a local module: {}\n", specifier);
|
||||||
|
if let Some(additional_message) =
|
||||||
|
graph_util::maybe_sloppy_imports_suggestion_message(&fs, specifier)
|
||||||
|
{
|
||||||
|
message.push_str(&additional_message);
|
||||||
|
message.push('.');
|
||||||
|
} else {
|
||||||
|
message.push_str("Please check the file path.");
|
||||||
|
}
|
||||||
|
message
|
||||||
|
}
|
||||||
|
|
||||||
let (severity, message, data) = match self {
|
let (severity, message, data) = match self {
|
||||||
Self::DenoWarn(message) => (lsp::DiagnosticSeverity::WARNING, message.to_string(), None),
|
Self::DenoWarn(message) => (lsp::DiagnosticSeverity::WARNING, message.to_string(), None),
|
||||||
Self::ImportMapRemap { from, to } => (lsp::DiagnosticSeverity::HINT, format!("The import specifier can be remapped to \"{to}\" which will resolve it via the active import map."), Some(json!({ "from": from, "to": to }))),
|
Self::ImportMapRemap { from, to } => (lsp::DiagnosticSeverity::HINT, format!("The import specifier can be remapped to \"{to}\" which will resolve it via the active import map."), Some(json!({ "from": from, "to": to }))),
|
||||||
|
@ -1173,7 +1189,7 @@ impl DenoDiagnostic {
|
||||||
Self::NoAttributeType => (lsp::DiagnosticSeverity::ERROR, "The module is a JSON module and not being imported with an import attribute. Consider adding `with { type: \"json\" }` to the import statement.".to_string(), None),
|
Self::NoAttributeType => (lsp::DiagnosticSeverity::ERROR, "The module is a JSON module and not being imported with an import attribute. Consider adding `with { type: \"json\" }` to the import statement.".to_string(), None),
|
||||||
Self::NoCache(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing remote URL: {specifier}"), Some(json!({ "specifier": specifier }))),
|
Self::NoCache(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing remote URL: {specifier}"), Some(json!({ "specifier": specifier }))),
|
||||||
Self::NoCacheNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing npm package: {}", pkg_req), Some(json!({ "specifier": specifier }))),
|
Self::NoCacheNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing npm package: {}", pkg_req), Some(json!({ "specifier": specifier }))),
|
||||||
Self::NoLocal(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Unable to load a local module: {specifier}\n Please check the file path."), None),
|
Self::NoLocal(specifier) => (lsp::DiagnosticSeverity::ERROR, no_local_message(specifier), None),
|
||||||
Self::Redirect { from, to} => (lsp::DiagnosticSeverity::INFORMATION, format!("The import of \"{from}\" was redirected to \"{to}\"."), Some(json!({ "specifier": from, "redirect": to }))),
|
Self::Redirect { from, to} => (lsp::DiagnosticSeverity::INFORMATION, format!("The import of \"{from}\" was redirected to \"{to}\"."), Some(json!({ "specifier": from, "redirect": to }))),
|
||||||
Self::ResolutionError(err) => (
|
Self::ResolutionError(err) => (
|
||||||
lsp::DiagnosticSeverity::ERROR,
|
lsp::DiagnosticSeverity::ERROR,
|
||||||
|
|
|
@ -20,9 +20,9 @@ use crate::lsp::logging::lsp_warn;
|
||||||
use crate::npm::CliNpmResolver;
|
use crate::npm::CliNpmResolver;
|
||||||
use crate::resolver::CliGraphResolver;
|
use crate::resolver::CliGraphResolver;
|
||||||
use crate::resolver::CliGraphResolverOptions;
|
use crate::resolver::CliGraphResolverOptions;
|
||||||
use crate::resolver::UnstableSloppyImportsFsEntry;
|
use crate::resolver::SloppyImportsFsEntry;
|
||||||
use crate::resolver::UnstableSloppyImportsResolution;
|
use crate::resolver::SloppyImportsResolution;
|
||||||
use crate::resolver::UnstableSloppyImportsResolver;
|
use crate::resolver::SloppyImportsResolver;
|
||||||
use crate::util::glob;
|
use crate::util::glob;
|
||||||
use crate::util::path::specifier_to_file_path;
|
use crate::util::path::specifier_to_file_path;
|
||||||
use crate::util::text_encoding;
|
use crate::util::text_encoding;
|
||||||
|
@ -1065,20 +1065,20 @@ impl Documents {
|
||||||
fn resolve_unstable_sloppy_import<'a>(
|
fn resolve_unstable_sloppy_import<'a>(
|
||||||
&self,
|
&self,
|
||||||
specifier: &'a ModuleSpecifier,
|
specifier: &'a ModuleSpecifier,
|
||||||
) -> UnstableSloppyImportsResolution<'a> {
|
) -> SloppyImportsResolution<'a> {
|
||||||
UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
|
SloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
|
||||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
|
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
|
||||||
if self.open_docs.contains_key(&specifier)
|
if self.open_docs.contains_key(&specifier)
|
||||||
|| self.cache.contains(&specifier)
|
|| self.cache.contains(&specifier)
|
||||||
{
|
{
|
||||||
return Some(UnstableSloppyImportsFsEntry::File);
|
return Some(SloppyImportsFsEntry::File);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path.metadata().ok().and_then(|m| {
|
path.metadata().ok().and_then(|m| {
|
||||||
if m.is_file() {
|
if m.is_file() {
|
||||||
Some(UnstableSloppyImportsFsEntry::File)
|
Some(SloppyImportsFsEntry::File)
|
||||||
} else if m.is_dir() {
|
} else if m.is_dir() {
|
||||||
Some(UnstableSloppyImportsFsEntry::Dir)
|
Some(SloppyImportsFsEntry::Dir)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1732,18 +1732,18 @@ impl<'a> OpenDocumentsGraphLoader<'a> {
|
||||||
fn resolve_unstable_sloppy_import<'b>(
|
fn resolve_unstable_sloppy_import<'b>(
|
||||||
&self,
|
&self,
|
||||||
specifier: &'b ModuleSpecifier,
|
specifier: &'b ModuleSpecifier,
|
||||||
) -> UnstableSloppyImportsResolution<'b> {
|
) -> SloppyImportsResolution<'b> {
|
||||||
UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
|
SloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
|
||||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
|
if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
|
||||||
if self.open_docs.contains_key(&specifier) {
|
if self.open_docs.contains_key(&specifier) {
|
||||||
return Some(UnstableSloppyImportsFsEntry::File);
|
return Some(SloppyImportsFsEntry::File);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path.metadata().ok().and_then(|m| {
|
path.metadata().ok().and_then(|m| {
|
||||||
if m.is_file() {
|
if m.is_file() {
|
||||||
Some(UnstableSloppyImportsFsEntry::File)
|
Some(SloppyImportsFsEntry::File)
|
||||||
} else if m.is_dir() {
|
} else if m.is_dir() {
|
||||||
Some(UnstableSloppyImportsFsEntry::Dir)
|
Some(SloppyImportsFsEntry::Dir)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,6 +263,7 @@ impl LanguageServer {
|
||||||
.await?;
|
.await?;
|
||||||
graph_util::graph_valid(
|
graph_util::graph_valid(
|
||||||
&graph,
|
&graph,
|
||||||
|
factory.fs(),
|
||||||
&roots,
|
&roots,
|
||||||
graph_util::GraphValidOptions {
|
graph_util::GraphValidOptions {
|
||||||
is_vendoring: false,
|
is_vendoring: false,
|
||||||
|
|
|
@ -169,7 +169,7 @@ impl ModuleLoadPreparer {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
graph_valid_with_cli_options(graph, &roots, &self.options)?;
|
graph_valid_with_cli_options(graph, &self.fs, &roots, &self.options)?;
|
||||||
|
|
||||||
// If there is a lockfile...
|
// If there is a lockfile...
|
||||||
if let Some(lockfile) = &self.lockfile {
|
if let Some(lockfile) = &self.lockfile {
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl MappedSpecifierResolver {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CliGraphResolver {
|
pub struct CliGraphResolver {
|
||||||
fs: Arc<dyn FileSystem>,
|
fs: Arc<dyn FileSystem>,
|
||||||
sloppy_imports_resolver: Option<UnstableSloppyImportsResolver>,
|
sloppy_imports_resolver: Option<SloppyImportsResolver>,
|
||||||
mapped_specifier_resolver: MappedSpecifierResolver,
|
mapped_specifier_resolver: MappedSpecifierResolver,
|
||||||
maybe_default_jsx_import_source: Option<String>,
|
maybe_default_jsx_import_source: Option<String>,
|
||||||
maybe_jsx_import_source_module: Option<String>,
|
maybe_jsx_import_source_module: Option<String>,
|
||||||
|
@ -132,7 +132,7 @@ pub struct CliGraphResolver {
|
||||||
pub struct CliGraphResolverOptions<'a> {
|
pub struct CliGraphResolverOptions<'a> {
|
||||||
pub fs: Arc<dyn FileSystem>,
|
pub fs: Arc<dyn FileSystem>,
|
||||||
pub cjs_resolutions: Option<Arc<CjsResolutionStore>>,
|
pub cjs_resolutions: Option<Arc<CjsResolutionStore>>,
|
||||||
pub sloppy_imports_resolver: Option<UnstableSloppyImportsResolver>,
|
pub sloppy_imports_resolver: Option<SloppyImportsResolver>,
|
||||||
pub node_resolver: Option<Arc<NodeResolver>>,
|
pub node_resolver: Option<Arc<NodeResolver>>,
|
||||||
pub npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
pub npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||||
pub package_json_deps_provider: Arc<PackageJsonDepsProvider>,
|
pub package_json_deps_provider: Arc<PackageJsonDepsProvider>,
|
||||||
|
@ -399,13 +399,13 @@ impl Resolver for CliGraphResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sloppy_imports_resolve(
|
fn sloppy_imports_resolve(
|
||||||
resolver: &UnstableSloppyImportsResolver,
|
resolver: &SloppyImportsResolver,
|
||||||
specifier: ModuleSpecifier,
|
specifier: ModuleSpecifier,
|
||||||
referrer_range: &deno_graph::Range,
|
referrer_range: &deno_graph::Range,
|
||||||
) -> ModuleSpecifier {
|
) -> ModuleSpecifier {
|
||||||
let resolution = resolver.resolve(&specifier);
|
let resolution = resolver.resolve(&specifier);
|
||||||
let hint_message = match &resolution {
|
let hint_message = match &resolution {
|
||||||
UnstableSloppyImportsResolution::JsToTs(to_specifier) => {
|
SloppyImportsResolution::JsToTs(to_specifier) => {
|
||||||
let from_media_type = MediaType::from_specifier(&specifier);
|
let from_media_type = MediaType::from_specifier(&specifier);
|
||||||
let to_media_type = MediaType::from_specifier(to_specifier);
|
let to_media_type = MediaType::from_specifier(to_specifier);
|
||||||
format!(
|
format!(
|
||||||
|
@ -414,11 +414,11 @@ fn sloppy_imports_resolve(
|
||||||
to_media_type.as_ts_extension()
|
to_media_type.as_ts_extension()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
UnstableSloppyImportsResolution::NoExtension(to_specifier) => {
|
SloppyImportsResolution::NoExtension(to_specifier) => {
|
||||||
let to_media_type = MediaType::from_specifier(to_specifier);
|
let to_media_type = MediaType::from_specifier(to_specifier);
|
||||||
format!("add {} extension", to_media_type.as_ts_extension())
|
format!("add {} extension", to_media_type.as_ts_extension())
|
||||||
}
|
}
|
||||||
UnstableSloppyImportsResolution::Directory(to_specifier) => {
|
SloppyImportsResolution::Directory(to_specifier) => {
|
||||||
let file_name = to_specifier
|
let file_name = to_specifier
|
||||||
.path()
|
.path()
|
||||||
.rsplit_once('/')
|
.rsplit_once('/')
|
||||||
|
@ -426,7 +426,7 @@ fn sloppy_imports_resolve(
|
||||||
.unwrap_or(to_specifier.path());
|
.unwrap_or(to_specifier.path());
|
||||||
format!("specify path to {} file in directory instead", file_name)
|
format!("specify path to {} file in directory instead", file_name)
|
||||||
}
|
}
|
||||||
UnstableSloppyImportsResolution::None(_) => return specifier,
|
SloppyImportsResolution::None(_) => return specifier,
|
||||||
};
|
};
|
||||||
// show a warning when this happens in order to drive
|
// show a warning when this happens in order to drive
|
||||||
// the user towards correcting these specifiers
|
// the user towards correcting these specifiers
|
||||||
|
@ -541,12 +541,12 @@ impl NpmResolver for CliGraphResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct UnstableSloppyImportsStatCache {
|
struct SloppyImportsStatCache {
|
||||||
fs: Arc<dyn FileSystem>,
|
fs: Arc<dyn FileSystem>,
|
||||||
cache: Mutex<HashMap<PathBuf, Option<UnstableSloppyImportsFsEntry>>>,
|
cache: Mutex<HashMap<PathBuf, Option<SloppyImportsFsEntry>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnstableSloppyImportsStatCache {
|
impl SloppyImportsStatCache {
|
||||||
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
|
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fs,
|
fs,
|
||||||
|
@ -554,7 +554,7 @@ impl UnstableSloppyImportsStatCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stat_sync(&self, path: &Path) -> Option<UnstableSloppyImportsFsEntry> {
|
pub fn stat_sync(&self, path: &Path) -> Option<SloppyImportsFsEntry> {
|
||||||
// there will only ever be one thread in here at a
|
// there will only ever be one thread in here at a
|
||||||
// time, so it's ok to hold the lock for so long
|
// time, so it's ok to hold the lock for so long
|
||||||
let mut cache = self.cache.lock();
|
let mut cache = self.cache.lock();
|
||||||
|
@ -564,9 +564,9 @@ impl UnstableSloppyImportsStatCache {
|
||||||
|
|
||||||
let entry = self.fs.stat_sync(path).ok().and_then(|stat| {
|
let entry = self.fs.stat_sync(path).ok().and_then(|stat| {
|
||||||
if stat.is_file {
|
if stat.is_file {
|
||||||
Some(UnstableSloppyImportsFsEntry::File)
|
Some(SloppyImportsFsEntry::File)
|
||||||
} else if stat.is_directory {
|
} else if stat.is_directory {
|
||||||
Some(UnstableSloppyImportsFsEntry::Dir)
|
Some(SloppyImportsFsEntry::Dir)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -577,13 +577,13 @@ impl UnstableSloppyImportsStatCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum UnstableSloppyImportsFsEntry {
|
pub enum SloppyImportsFsEntry {
|
||||||
File,
|
File,
|
||||||
Dir,
|
Dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum UnstableSloppyImportsResolution<'a> {
|
pub enum SloppyImportsResolution<'a> {
|
||||||
/// No sloppy resolution was found.
|
/// No sloppy resolution was found.
|
||||||
None(&'a ModuleSpecifier),
|
None(&'a ModuleSpecifier),
|
||||||
/// Ex. `./file.js` to `./file.ts`
|
/// Ex. `./file.js` to `./file.ts`
|
||||||
|
@ -594,7 +594,7 @@ pub enum UnstableSloppyImportsResolution<'a> {
|
||||||
Directory(ModuleSpecifier),
|
Directory(ModuleSpecifier),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> UnstableSloppyImportsResolution<'a> {
|
impl<'a> SloppyImportsResolution<'a> {
|
||||||
pub fn into_specifier(self) -> Cow<'a, ModuleSpecifier> {
|
pub fn into_specifier(self) -> Cow<'a, ModuleSpecifier> {
|
||||||
match self {
|
match self {
|
||||||
Self::None(specifier) => Cow::Borrowed(specifier),
|
Self::None(specifier) => Cow::Borrowed(specifier),
|
||||||
|
@ -615,35 +615,35 @@ impl<'a> UnstableSloppyImportsResolution<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UnstableSloppyImportsResolver {
|
pub struct SloppyImportsResolver {
|
||||||
stat_cache: UnstableSloppyImportsStatCache,
|
stat_cache: SloppyImportsStatCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnstableSloppyImportsResolver {
|
impl SloppyImportsResolver {
|
||||||
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
|
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stat_cache: UnstableSloppyImportsStatCache::new(fs),
|
stat_cache: SloppyImportsStatCache::new(fs),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_with_stat_sync(
|
pub fn resolve_with_stat_sync(
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
stat_sync: impl Fn(&Path) -> Option<UnstableSloppyImportsFsEntry>,
|
stat_sync: impl Fn(&Path) -> Option<SloppyImportsFsEntry>,
|
||||||
) -> UnstableSloppyImportsResolution {
|
) -> SloppyImportsResolution {
|
||||||
if specifier.scheme() != "file" {
|
if specifier.scheme() != "file" {
|
||||||
return UnstableSloppyImportsResolution::None(specifier);
|
return SloppyImportsResolution::None(specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Ok(path) = specifier_to_file_path(specifier) else {
|
let Ok(path) = specifier_to_file_path(specifier) else {
|
||||||
return UnstableSloppyImportsResolution::None(specifier);
|
return SloppyImportsResolution::None(specifier);
|
||||||
};
|
};
|
||||||
let mut is_dir_resolution = false;
|
let mut is_dir_resolution = false;
|
||||||
let mut is_no_ext_resolution = false;
|
let mut is_no_ext_resolution = false;
|
||||||
let probe_paths = match (stat_sync)(&path) {
|
let probe_paths = match (stat_sync)(&path) {
|
||||||
Some(UnstableSloppyImportsFsEntry::File) => {
|
Some(SloppyImportsFsEntry::File) => {
|
||||||
return UnstableSloppyImportsResolution::None(specifier);
|
return SloppyImportsResolution::None(specifier);
|
||||||
}
|
}
|
||||||
Some(UnstableSloppyImportsFsEntry::Dir) => {
|
Some(SloppyImportsFsEntry::Dir) => {
|
||||||
is_dir_resolution = true;
|
is_dir_resolution = true;
|
||||||
// try to resolve at the index file
|
// try to resolve at the index file
|
||||||
vec![
|
vec![
|
||||||
|
@ -673,7 +673,7 @@ impl UnstableSloppyImportsResolver {
|
||||||
| MediaType::Wasm
|
| MediaType::Wasm
|
||||||
| MediaType::TsBuildInfo
|
| MediaType::TsBuildInfo
|
||||||
| MediaType::SourceMap => {
|
| MediaType::SourceMap => {
|
||||||
return UnstableSloppyImportsResolution::None(specifier)
|
return SloppyImportsResolution::None(specifier)
|
||||||
}
|
}
|
||||||
MediaType::Unknown => {
|
MediaType::Unknown => {
|
||||||
is_no_ext_resolution = true;
|
is_no_ext_resolution = true;
|
||||||
|
@ -692,7 +692,7 @@ impl UnstableSloppyImportsResolver {
|
||||||
MediaType::Unknown => old_path_str,
|
MediaType::Unknown => old_path_str,
|
||||||
_ => match old_path_str.strip_suffix(media_type.as_ts_extension()) {
|
_ => match old_path_str.strip_suffix(media_type.as_ts_extension()) {
|
||||||
Some(s) => Cow::Borrowed(s),
|
Some(s) => Cow::Borrowed(s),
|
||||||
None => return UnstableSloppyImportsResolution::None(specifier),
|
None => return SloppyImportsResolution::None(specifier),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
probe_media_type_types
|
probe_media_type_types
|
||||||
|
@ -709,26 +709,26 @@ impl UnstableSloppyImportsResolver {
|
||||||
};
|
};
|
||||||
|
|
||||||
for probe_path in probe_paths {
|
for probe_path in probe_paths {
|
||||||
if (stat_sync)(&probe_path) == Some(UnstableSloppyImportsFsEntry::File) {
|
if (stat_sync)(&probe_path) == Some(SloppyImportsFsEntry::File) {
|
||||||
if let Ok(specifier) = ModuleSpecifier::from_file_path(probe_path) {
|
if let Ok(specifier) = ModuleSpecifier::from_file_path(probe_path) {
|
||||||
if is_dir_resolution {
|
if is_dir_resolution {
|
||||||
return UnstableSloppyImportsResolution::Directory(specifier);
|
return SloppyImportsResolution::Directory(specifier);
|
||||||
} else if is_no_ext_resolution {
|
} else if is_no_ext_resolution {
|
||||||
return UnstableSloppyImportsResolution::NoExtension(specifier);
|
return SloppyImportsResolution::NoExtension(specifier);
|
||||||
} else {
|
} else {
|
||||||
return UnstableSloppyImportsResolution::JsToTs(specifier);
|
return SloppyImportsResolution::JsToTs(specifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnstableSloppyImportsResolution::None(specifier)
|
SloppyImportsResolution::None(specifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve<'a>(
|
pub fn resolve<'a>(
|
||||||
&self,
|
&self,
|
||||||
specifier: &'a ModuleSpecifier,
|
specifier: &'a ModuleSpecifier,
|
||||||
) -> UnstableSloppyImportsResolution<'a> {
|
) -> SloppyImportsResolution<'a> {
|
||||||
Self::resolve_with_stat_sync(specifier, |path| {
|
Self::resolve_with_stat_sync(specifier, |path| {
|
||||||
self.stat_cache.stat_sync(path)
|
self.stat_cache.stat_sync(path)
|
||||||
})
|
})
|
||||||
|
@ -806,13 +806,13 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unstable_sloppy_imports() {
|
fn test_unstable_sloppy_imports() {
|
||||||
fn resolve(specifier: &ModuleSpecifier) -> UnstableSloppyImportsResolution {
|
fn resolve(specifier: &ModuleSpecifier) -> SloppyImportsResolution {
|
||||||
UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
|
SloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
|
||||||
RealFs.stat_sync(path).ok().and_then(|stat| {
|
RealFs.stat_sync(path).ok().and_then(|stat| {
|
||||||
if stat.is_file {
|
if stat.is_file {
|
||||||
Some(UnstableSloppyImportsFsEntry::File)
|
Some(SloppyImportsFsEntry::File)
|
||||||
} else if stat.is_directory {
|
} else if stat.is_directory {
|
||||||
Some(UnstableSloppyImportsFsEntry::Dir)
|
Some(SloppyImportsFsEntry::Dir)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -830,7 +830,7 @@ mod test {
|
||||||
let ts_file_uri = ts_file.uri_file();
|
let ts_file_uri = ts_file.uri_file();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve(&ts_file.uri_file()),
|
resolve(&ts_file.uri_file()),
|
||||||
UnstableSloppyImportsResolution::None(&ts_file_uri),
|
SloppyImportsResolution::None(&ts_file_uri),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve(
|
resolve(
|
||||||
|
@ -839,7 +839,7 @@ mod test {
|
||||||
.join(&format!("file.{}", ext_from))
|
.join(&format!("file.{}", ext_from))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
),
|
),
|
||||||
UnstableSloppyImportsResolution::JsToTs(ts_file.uri_file()),
|
SloppyImportsResolution::JsToTs(ts_file.uri_file()),
|
||||||
);
|
);
|
||||||
ts_file.remove_file();
|
ts_file.remove_file();
|
||||||
}
|
}
|
||||||
|
@ -855,7 +855,7 @@ mod test {
|
||||||
.join("file") // no ext
|
.join("file") // no ext
|
||||||
.unwrap()
|
.unwrap()
|
||||||
),
|
),
|
||||||
UnstableSloppyImportsResolution::NoExtension(file.uri_file()),
|
SloppyImportsResolution::NoExtension(file.uri_file()),
|
||||||
);
|
);
|
||||||
file.remove_file();
|
file.remove_file();
|
||||||
}
|
}
|
||||||
|
@ -869,7 +869,7 @@ mod test {
|
||||||
let js_file_uri = js_file.uri_file();
|
let js_file_uri = js_file.uri_file();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve(&js_file.uri_file()),
|
resolve(&js_file.uri_file()),
|
||||||
UnstableSloppyImportsResolution::None(&js_file_uri),
|
SloppyImportsResolution::None(&js_file_uri),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,7 +881,7 @@ mod test {
|
||||||
index_file.write("");
|
index_file.write("");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve(&routes_dir.uri_file()),
|
resolve(&routes_dir.uri_file()),
|
||||||
UnstableSloppyImportsResolution::Directory(index_file.uri_file()),
|
SloppyImportsResolution::Directory(index_file.uri_file()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10668,3 +10668,55 @@ fn lsp_sloppy_imports_warn() {
|
||||||
|
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sloppy_imports_not_enabled() {
|
||||||
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
|
let temp_dir = temp_dir.path();
|
||||||
|
temp_dir.join("deno.json").write(r#"{}"#);
|
||||||
|
// The enhanced, more helpful error message is only available
|
||||||
|
// when the file exists on the file system at the moment because
|
||||||
|
// it's a little more complicated to hook it up otherwise.
|
||||||
|
temp_dir.join("a.ts").write("export class A {}");
|
||||||
|
let mut client = context.new_lsp_command().build();
|
||||||
|
client.initialize(|builder| {
|
||||||
|
builder.set_root_uri(temp_dir.uri_dir());
|
||||||
|
});
|
||||||
|
let diagnostics = client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.join("file.ts").uri_file(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import * as a from './a';\nconsole.log(a)\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
assert_eq!(
|
||||||
|
diagnostics.messages_with_source("deno"),
|
||||||
|
lsp::PublishDiagnosticsParams {
|
||||||
|
uri: temp_dir.join("file.ts").uri_file(),
|
||||||
|
diagnostics: vec![lsp::Diagnostic {
|
||||||
|
range: lsp::Range {
|
||||||
|
start: lsp::Position {
|
||||||
|
line: 0,
|
||||||
|
character: 19
|
||||||
|
},
|
||||||
|
end: lsp::Position {
|
||||||
|
line: 0,
|
||||||
|
character: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: Some(lsp::DiagnosticSeverity::ERROR),
|
||||||
|
code: Some(lsp::NumberOrString::String("no-local".to_string())),
|
||||||
|
source: Some("deno".to_string()),
|
||||||
|
message: format!(
|
||||||
|
"Unable to load a local module: {}\nMaybe add a '.ts' extension.",
|
||||||
|
temp_dir.join("a").uri_file(),
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
}],
|
||||||
|
version: Some(1),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
|
|
@ -4740,7 +4740,6 @@ itest!(unsafe_proto_flag {
|
||||||
fn test_unstable_sloppy_imports() {
|
fn test_unstable_sloppy_imports() {
|
||||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
let temp_dir = context.temp_dir();
|
let temp_dir = context.temp_dir();
|
||||||
temp_dir.write("deno.json", r#"{ "unstable": ["sloppy-imports"] }"#);
|
|
||||||
temp_dir.write("a.ts", "export class A {}");
|
temp_dir.write("a.ts", "export class A {}");
|
||||||
temp_dir.write("b.js", "export class B {}");
|
temp_dir.write("b.js", "export class B {}");
|
||||||
temp_dir.write("c.mts", "export class C {}");
|
temp_dir.write("c.mts", "export class C {}");
|
||||||
|
@ -4771,6 +4770,18 @@ console.log(g.G);
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// run without sloppy imports
|
||||||
|
context
|
||||||
|
.new_command()
|
||||||
|
.args("run main.ts")
|
||||||
|
.run()
|
||||||
|
.assert_matches_text(r#"error: Module not found "file:///[WILDCARD]/a.js". Maybe change the extension to '.ts' or run with --unstable-sloppy-imports
|
||||||
|
at file:///[WILDCARD]/main.ts:1:20
|
||||||
|
"#)
|
||||||
|
.assert_exit_code(1);
|
||||||
|
|
||||||
|
// now run with sloppy imports
|
||||||
|
temp_dir.write("deno.json", r#"{ "unstable": ["sloppy-imports"] }"#);
|
||||||
context
|
context
|
||||||
.new_command()
|
.new_command()
|
||||||
.args("run main.ts")
|
.args("run main.ts")
|
||||||
|
|
|
@ -495,7 +495,12 @@ pub async fn run_benchmarks_with_watch(
|
||||||
let graph = module_graph_builder
|
let graph = module_graph_builder
|
||||||
.create_graph(graph_kind, bench_modules.clone())
|
.create_graph(graph_kind, bench_modules.clone())
|
||||||
.await?;
|
.await?;
|
||||||
graph_valid_with_cli_options(&graph, &bench_modules, cli_options)?;
|
graph_valid_with_cli_options(
|
||||||
|
&graph,
|
||||||
|
factory.fs(),
|
||||||
|
&bench_modules,
|
||||||
|
cli_options,
|
||||||
|
)?;
|
||||||
|
|
||||||
let bench_modules_to_reload = if let Some(changed_paths) = changed_paths
|
let bench_modules_to_reload = if let Some(changed_paths) = changed_paths
|
||||||
{
|
{
|
||||||
|
|
|
@ -1280,7 +1280,12 @@ pub async fn run_tests_with_watch(
|
||||||
let graph = module_graph_builder
|
let graph = module_graph_builder
|
||||||
.create_graph(graph_kind, test_modules.clone())
|
.create_graph(graph_kind, test_modules.clone())
|
||||||
.await?;
|
.await?;
|
||||||
graph_valid_with_cli_options(&graph, &test_modules, &cli_options)?;
|
graph_valid_with_cli_options(
|
||||||
|
&graph,
|
||||||
|
factory.fs(),
|
||||||
|
&test_modules,
|
||||||
|
&cli_options,
|
||||||
|
)?;
|
||||||
|
|
||||||
let test_modules_to_reload = if let Some(changed_paths) = changed_paths
|
let test_modules_to_reload = if let Some(changed_paths) = changed_paths
|
||||||
{
|
{
|
||||||
|
|
3
cli/tools/vendor/build.rs
vendored
3
cli/tools/vendor/build.rs
vendored
|
@ -15,6 +15,7 @@ use deno_graph::source::ResolutionMode;
|
||||||
use deno_graph::EsmModule;
|
use deno_graph::EsmModule;
|
||||||
use deno_graph::Module;
|
use deno_graph::Module;
|
||||||
use deno_graph::ModuleGraph;
|
use deno_graph::ModuleGraph;
|
||||||
|
use deno_runtime::deno_fs;
|
||||||
use import_map::ImportMap;
|
use import_map::ImportMap;
|
||||||
use import_map::SpecifierMap;
|
use import_map::SpecifierMap;
|
||||||
|
|
||||||
|
@ -134,8 +135,10 @@ pub async fn build<
|
||||||
}
|
}
|
||||||
|
|
||||||
// surface any errors
|
// surface any errors
|
||||||
|
let fs: Arc<dyn deno_fs::FileSystem> = Arc::new(deno_fs::RealFs);
|
||||||
graph_util::graph_valid(
|
graph_util::graph_valid(
|
||||||
&graph,
|
&graph,
|
||||||
|
&fs,
|
||||||
&graph.roots,
|
&graph.roots,
|
||||||
graph_util::GraphValidOptions {
|
graph_util::GraphValidOptions {
|
||||||
is_vendoring: true,
|
is_vendoring: true,
|
||||||
|
|
Loading…
Reference in a new issue