mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 19:08:15 +00:00
refactor(deno_resolver): extract out CLI's deno_graph::source::Resolver
(#29143)
This commit is contained in:
parent
f42cb0816e
commit
7ae0f14a90
17 changed files with 434 additions and 233 deletions
9
.github/workflows/ci.generate.ts
vendored
9
.github/workflows/ci.generate.ts
vendored
|
@ -1220,12 +1220,13 @@ const ci = {
|
|||
},
|
||||
// we want these crates to be Wasm compatible
|
||||
{
|
||||
name: "Cargo build (deno_resolver)",
|
||||
run: "cargo build --target wasm32-unknown-unknown -p deno_resolver",
|
||||
name: "Cargo check (deno_resolver)",
|
||||
run:
|
||||
"cargo check --target wasm32-unknown-unknown -p deno_resolver && cargo check --target wasm32-unknown-unknown -p deno_resolver --features graph",
|
||||
},
|
||||
{
|
||||
name: "Cargo build (deno_npm_cache)",
|
||||
run: "cargo build --target wasm32-unknown-unknown -p deno_npm_cache",
|
||||
name: "Cargo check (deno_npm_cache)",
|
||||
run: "cargo check --target wasm32-unknown-unknown -p deno_npm_cache",
|
||||
},
|
||||
]),
|
||||
},
|
||||
|
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -795,11 +795,11 @@ jobs:
|
|||
- name: Install wasm target
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
if: '!(matrix.skip)'
|
||||
- name: Cargo build (deno_resolver)
|
||||
run: cargo build --target wasm32-unknown-unknown -p deno_resolver
|
||||
- name: Cargo check (deno_resolver)
|
||||
run: cargo check --target wasm32-unknown-unknown -p deno_resolver && cargo check --target wasm32-unknown-unknown -p deno_resolver --features graph
|
||||
if: '!(matrix.skip)'
|
||||
- name: Cargo build (deno_npm_cache)
|
||||
run: cargo build --target wasm32-unknown-unknown -p deno_npm_cache
|
||||
- name: Cargo check (deno_npm_cache)
|
||||
run: cargo check --target wasm32-unknown-unknown -p deno_npm_cache
|
||||
if: '!(matrix.skip)'
|
||||
publish-canary:
|
||||
name: publish canary
|
||||
|
|
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2542,12 +2542,14 @@ dependencies = [
|
|||
"deno_cache_dir",
|
||||
"deno_config",
|
||||
"deno_error",
|
||||
"deno_graph",
|
||||
"deno_media_type",
|
||||
"deno_npm",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
"deno_semver",
|
||||
"deno_terminal 0.2.2",
|
||||
"deno_unsync",
|
||||
"futures",
|
||||
"import_map",
|
||||
"indexmap 2.8.0",
|
||||
|
@ -5643,6 +5645,7 @@ dependencies = [
|
|||
"dashmap",
|
||||
"deno_config",
|
||||
"deno_error",
|
||||
"deno_graph",
|
||||
"deno_media_type",
|
||||
"deno_package_json",
|
||||
"deno_path_util",
|
||||
|
|
|
@ -60,7 +60,7 @@ deno_cache_dir = "=0.20.0"
|
|||
deno_config = { version = "=0.54.2", features = ["workspace"] }
|
||||
deno_doc = "=0.172.0"
|
||||
deno_error = "=0.5.6"
|
||||
deno_graph = "=0.90.0"
|
||||
deno_graph = { version = "=0.90.0", default-features = false }
|
||||
deno_lint = "=0.74.0"
|
||||
deno_lockfile = "=0.28.0"
|
||||
deno_media_type = { version = "=0.2.8", features = ["module_specifier"] }
|
||||
|
|
|
@ -75,7 +75,7 @@ deno_config = { workspace = true, features = ["sync", "workspace"] }
|
|||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_doc = { workspace = true, features = ["rust", "comrak"] }
|
||||
deno_error.workspace = true
|
||||
deno_graph.workspace = true
|
||||
deno_graph = { workspace = true, features = ["fast_check"] }
|
||||
deno_lib.workspace = true
|
||||
deno_lint.workspace = true
|
||||
deno_lockfile.workspace = true
|
||||
|
@ -85,7 +85,7 @@ deno_npm_cache.workspace = true
|
|||
deno_package_json = { workspace = true, features = ["sync"] }
|
||||
deno_panic = { version = "0.1.0", optional = true }
|
||||
deno_path_util.workspace = true
|
||||
deno_resolver = { workspace = true, features = ["sync"] }
|
||||
deno_resolver = { workspace = true, features = ["graph", "sync"] }
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_semver.workspace = true
|
||||
deno_snapshots.workspace = true
|
||||
|
@ -94,7 +94,7 @@ deno_telemetry.workspace = true
|
|||
deno_terminal.workspace = true
|
||||
eszip.workspace = true
|
||||
libsui.workspace = true
|
||||
node_resolver.workspace = true
|
||||
node_resolver = { workspace = true, features = ["graph", "sync"] }
|
||||
|
||||
anstream.workspace = true
|
||||
async-trait.workspace = true
|
||||
|
|
|
@ -38,6 +38,7 @@ use deno_resolver::factory::DenoDirPathProviderOptions;
|
|||
use deno_resolver::factory::NpmProcessStateOptions;
|
||||
use deno_resolver::factory::ResolverFactoryOptions;
|
||||
use deno_resolver::factory::SpecifiedImportMapProvider;
|
||||
use deno_resolver::graph::FoundPackageJsonDepFlag;
|
||||
use deno_resolver::npm::managed::NpmResolutionCell;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::workspace::WorkspaceResolver;
|
||||
|
@ -100,12 +101,12 @@ use crate::npm::CliNpmResolverManagedSnapshotOption;
|
|||
use crate::npm::CliNpmTarballCache;
|
||||
use crate::npm::NpmResolutionInitializer;
|
||||
use crate::npm::WorkspaceNpmPatchPackages;
|
||||
use crate::resolver::on_resolve_diagnostic;
|
||||
use crate::resolver::CliCjsTracker;
|
||||
use crate::resolver::CliDenoResolver;
|
||||
use crate::resolver::CliNpmGraphResolver;
|
||||
use crate::resolver::CliNpmReqResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::FoundPackageJsonDepFlag;
|
||||
use crate::standalone::binary::DenoCompileBinaryWriter;
|
||||
use crate::sys::CliSys;
|
||||
use crate::tools::coverage::CoverageCollector;
|
||||
|
@ -825,6 +826,7 @@ impl CliFactory {
|
|||
Ok(Arc::new(CliResolver::new(
|
||||
self.deno_resolver().await?.clone(),
|
||||
self.services.found_pkg_json_dep_flag.clone(),
|
||||
Box::new(on_resolve_diagnostic),
|
||||
)))
|
||||
}
|
||||
.boxed_local(),
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
|
@ -11,7 +10,6 @@ use deno_config::deno_json;
|
|||
use deno_config::deno_json::CompilerOptionTypesDeserializeError;
|
||||
use deno_config::deno_json::NodeModulesDirMode;
|
||||
use deno_config::workspace::JsrPackageConfig;
|
||||
use deno_config::workspace::JsxImportSourceConfig;
|
||||
use deno_config::workspace::ToMaybeJsxImportSourceConfigError;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
|
@ -21,7 +19,6 @@ use deno_error::JsErrorBox;
|
|||
use deno_error::JsErrorClass;
|
||||
use deno_graph::source::Loader;
|
||||
use deno_graph::source::LoaderChecksum;
|
||||
use deno_graph::source::ResolutionKind;
|
||||
use deno_graph::source::ResolveError;
|
||||
use deno_graph::CheckJsOption;
|
||||
use deno_graph::FillFromLockfileOptions;
|
||||
|
@ -37,6 +34,7 @@ use deno_graph::WorkspaceFastCheckOption;
|
|||
use deno_path_util::url_to_file_path;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::workspace::sloppy_imports_resolve;
|
||||
use deno_resolver::workspace::ScopedJsxImportSourceConfig;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrDepPackageReq;
|
||||
|
@ -751,7 +749,12 @@ impl ModuleGraphBuilder {
|
|||
Some(loader) => MutLoaderRef::Borrowed(loader),
|
||||
None => MutLoaderRef::Owned(self.create_graph_loader()),
|
||||
};
|
||||
let graph_resolver = self.create_graph_resolver()?;
|
||||
let scoped_jsx_config = ScopedJsxImportSourceConfig::from_workspace_dir(
|
||||
&self.cli_options.start_dir,
|
||||
)?;
|
||||
let graph_resolver = self
|
||||
.resolver
|
||||
.as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config);
|
||||
let maybe_file_watcher_reporter = self
|
||||
.maybe_file_watcher_reporter
|
||||
.as_ref()
|
||||
|
@ -893,7 +896,12 @@ impl ModuleGraphBuilder {
|
|||
None
|
||||
};
|
||||
let parser = self.parsed_source_cache.as_capturing_parser();
|
||||
let graph_resolver = self.create_graph_resolver()?;
|
||||
let scoped_jsx_config = ScopedJsxImportSourceConfig::from_workspace_dir(
|
||||
&self.cli_options.start_dir,
|
||||
)?;
|
||||
let graph_resolver = self
|
||||
.resolver
|
||||
.as_graph_resolver(self.cjs_tracker.as_ref(), &scoped_jsx_config);
|
||||
|
||||
graph.build_fast_check_type_graph(
|
||||
deno_graph::BuildFastCheckTypeGraphOptions {
|
||||
|
@ -967,29 +975,6 @@ impl ModuleGraphBuilder {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn create_graph_resolver(
|
||||
&self,
|
||||
) -> Result<CliGraphResolver, ToMaybeJsxImportSourceConfigError> {
|
||||
let jsx_import_source_config_unscoped = self
|
||||
.cli_options
|
||||
.start_dir
|
||||
.to_maybe_jsx_import_source_config()?;
|
||||
let mut jsx_import_source_config_by_scope = BTreeMap::default();
|
||||
for (dir_url, _) in self.cli_options.workspace().config_folders() {
|
||||
let dir = self.cli_options.workspace().resolve_member_dir(dir_url);
|
||||
let jsx_import_source_config_unscoped =
|
||||
dir.to_maybe_jsx_import_source_config()?;
|
||||
jsx_import_source_config_by_scope
|
||||
.insert(dir_url.clone(), jsx_import_source_config_unscoped);
|
||||
}
|
||||
Ok(CliGraphResolver {
|
||||
cjs_tracker: &self.cjs_tracker,
|
||||
resolver: &self.resolver,
|
||||
jsx_import_source_config_unscoped,
|
||||
jsx_import_source_config_by_scope,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds more explanatory information to a resolution error.
|
||||
|
@ -1309,8 +1294,6 @@ impl deno_graph::source::JsrUrlProvider for CliJsrUrlProvider {
|
|||
}
|
||||
}
|
||||
|
||||
// todo(dsherret): We should change ModuleError to use thiserror so that
|
||||
// we don't need to do this.
|
||||
fn format_deno_graph_error(err: &dyn Error) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
|
@ -1352,100 +1335,6 @@ fn format_deno_graph_error(err: &dyn Error) -> String {
|
|||
message
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CliGraphResolver<'a> {
|
||||
cjs_tracker: &'a CliCjsTracker,
|
||||
resolver: &'a CliResolver,
|
||||
jsx_import_source_config_unscoped: Option<JsxImportSourceConfig>,
|
||||
jsx_import_source_config_by_scope:
|
||||
BTreeMap<Arc<ModuleSpecifier>, Option<JsxImportSourceConfig>>,
|
||||
}
|
||||
|
||||
impl CliGraphResolver<'_> {
|
||||
fn resolve_jsx_import_source_config(
|
||||
&self,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Option<&JsxImportSourceConfig> {
|
||||
self
|
||||
.jsx_import_source_config_by_scope
|
||||
.iter()
|
||||
.rfind(|(s, _)| referrer.as_str().starts_with(s.as_str()))
|
||||
.map(|(_, c)| c.as_ref())
|
||||
.unwrap_or(self.jsx_import_source_config_unscoped.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_graph::source::Resolver for CliGraphResolver<'_> {
|
||||
fn default_jsx_import_source(
|
||||
&self,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Option<String> {
|
||||
self
|
||||
.resolve_jsx_import_source_config(referrer)
|
||||
.and_then(|c| c.import_source.as_ref().map(|s| s.specifier.clone()))
|
||||
}
|
||||
|
||||
fn default_jsx_import_source_types(
|
||||
&self,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Option<String> {
|
||||
self
|
||||
.resolve_jsx_import_source_config(referrer)
|
||||
.and_then(|c| c.import_source_types.as_ref().map(|s| s.specifier.clone()))
|
||||
}
|
||||
|
||||
fn jsx_import_source_module(&self, referrer: &ModuleSpecifier) -> &str {
|
||||
self
|
||||
.resolve_jsx_import_source_config(referrer)
|
||||
.map(|c| c.module.as_str())
|
||||
.unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer_range: &deno_graph::Range,
|
||||
resolution_kind: ResolutionKind,
|
||||
) -> Result<ModuleSpecifier, ResolveError> {
|
||||
self.resolver.resolve(
|
||||
raw_specifier,
|
||||
&referrer_range.specifier,
|
||||
referrer_range.range.start,
|
||||
referrer_range
|
||||
.resolution_mode
|
||||
.map(to_node_resolution_mode)
|
||||
.unwrap_or_else(|| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.get_referrer_kind(&referrer_range.specifier)
|
||||
}),
|
||||
to_node_resolution_kind(resolution_kind),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_node_resolution_kind(
|
||||
kind: ResolutionKind,
|
||||
) -> node_resolver::NodeResolutionKind {
|
||||
match kind {
|
||||
ResolutionKind::Execution => node_resolver::NodeResolutionKind::Execution,
|
||||
ResolutionKind::Types => node_resolver::NodeResolutionKind::Types,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_node_resolution_mode(
|
||||
mode: deno_graph::source::ResolutionMode,
|
||||
) -> node_resolver::ResolutionMode {
|
||||
match mode {
|
||||
deno_graph::source::ResolutionMode::Import => {
|
||||
node_resolver::ResolutionMode::Import
|
||||
}
|
||||
deno_graph::source::ResolutionMode::Require => {
|
||||
node_resolver::ResolutionMode::Require
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::Arc;
|
||||
|
|
|
@ -35,7 +35,6 @@ use super::registries::ModuleRegistry;
|
|||
use super::resolver::LspResolver;
|
||||
use super::search::PackageSearchApi;
|
||||
use super::tsc;
|
||||
use crate::graph_util::to_node_resolution_mode;
|
||||
use crate::jsr::JsrFetchResolver;
|
||||
use crate::util::path::is_importable_ext;
|
||||
use crate::util::path::relative_specifier;
|
||||
|
@ -167,7 +166,7 @@ pub async fn get_import_completions(
|
|||
let (text, _, graph_range) = module.dependency_at_position(position)?;
|
||||
let resolution_mode = graph_range
|
||||
.resolution_mode
|
||||
.map(to_node_resolution_mode)
|
||||
.map(node_resolver::ResolutionMode::from_deno_graph)
|
||||
.unwrap_or_else(|| module.resolution_mode);
|
||||
let range = to_narrow_lsp_range(module.text_info(), graph_range.range);
|
||||
let scoped_resolver = resolver.get_scoped_resolver(module.scope.as_deref());
|
||||
|
|
|
@ -22,6 +22,7 @@ use deno_npm::NpmSystemInfo;
|
|||
use deno_npm_cache::TarballCache;
|
||||
use deno_path_util::url_to_file_path;
|
||||
use deno_resolver::cjs::IsCjsResolutionMode;
|
||||
use deno_resolver::graph::FoundPackageJsonDepFlag;
|
||||
use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions;
|
||||
use deno_resolver::npm::managed::NpmResolutionCell;
|
||||
use deno_resolver::npm::CreateInNpmPkgCheckerOptions;
|
||||
|
@ -55,8 +56,6 @@ use crate::args::CliLockfile;
|
|||
use crate::args::LifecycleScriptsConfig;
|
||||
use crate::args::NpmInstallDepsProvider;
|
||||
use crate::factory::Deferred;
|
||||
use crate::graph_util::to_node_resolution_kind;
|
||||
use crate::graph_util::to_node_resolution_mode;
|
||||
use crate::graph_util::CliJsrUrlProvider;
|
||||
use crate::http_util::HttpClientProvider;
|
||||
use crate::lsp::config::Config;
|
||||
|
@ -77,11 +76,11 @@ use crate::npm::CliNpmResolverCreateOptions;
|
|||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::NpmResolutionInitializer;
|
||||
use crate::npm::WorkspaceNpmPatchPackages;
|
||||
use crate::resolver::on_resolve_diagnostic;
|
||||
use crate::resolver::CliDenoResolver;
|
||||
use crate::resolver::CliIsCjsResolver;
|
||||
use crate::resolver::CliNpmReqResolver;
|
||||
use crate::resolver::CliResolver;
|
||||
use crate::resolver::FoundPackageJsonDepFlag;
|
||||
use crate::sys::CliSys;
|
||||
use crate::tsc::into_specifier_and_media_type;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
|
@ -952,6 +951,7 @@ impl<'a> ResolverFactory<'a> {
|
|||
Arc::new(CliResolver::new(
|
||||
deno_resolver,
|
||||
self.services.found_pkg_json_dep_flag.clone(),
|
||||
Box::new(on_resolve_diagnostic),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
@ -1119,9 +1119,9 @@ impl deno_graph::source::Resolver for SingleReferrerGraphResolver<'_> {
|
|||
referrer_range.range.start,
|
||||
referrer_range
|
||||
.resolution_mode
|
||||
.map(to_node_resolution_mode)
|
||||
.map(node_resolver::ResolutionMode::from_deno_graph)
|
||||
.unwrap_or(self.module_resolution_mode),
|
||||
to_node_resolution_kind(resolution_kind),
|
||||
node_resolver::NodeResolutionKind::from_deno_graph(resolution_kind),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
107
cli/resolver.rs
107
cli/resolver.rs
|
@ -3,28 +3,21 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use dashmap::DashSet;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_graph::source::ResolveError;
|
||||
use deno_graph::NpmLoadError;
|
||||
use deno_graph::NpmResolvePkgReqsResult;
|
||||
use deno_npm::resolution::NpmResolutionError;
|
||||
use deno_resolver::graph::FoundPackageJsonDepFlag;
|
||||
use deno_resolver::npm::DenoInNpmPackageChecker;
|
||||
use deno_resolver::workspace::MappedResolutionDiagnostic;
|
||||
use deno_resolver::workspace::MappedResolutionError;
|
||||
use deno_runtime::colors;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::DenoIsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NodeResolutionKind;
|
||||
use node_resolver::ResolutionMode;
|
||||
|
||||
use crate::args::NpmCachingStrategy;
|
||||
use crate::npm::installer::NpmInstaller;
|
||||
use crate::npm::installer::PackageCaching;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::sys::CliSys;
|
||||
use crate::util::sync::AtomicFlag;
|
||||
|
||||
pub type CliCjsTracker =
|
||||
deno_resolver::cjs::CjsTracker<DenoInNpmPackageChecker, CliSys>;
|
||||
|
@ -42,82 +35,25 @@ pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver<
|
|||
CliNpmResolver,
|
||||
CliSys,
|
||||
>;
|
||||
pub type CliResolver = deno_resolver::graph::DenoGraphResolver<
|
||||
DenoInNpmPackageChecker,
|
||||
DenoIsBuiltInNodeModuleChecker,
|
||||
CliNpmResolver,
|
||||
CliSys,
|
||||
>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FoundPackageJsonDepFlag(AtomicFlag);
|
||||
|
||||
/// A resolver that takes care of resolution, taking into account loaded
|
||||
/// import map, JSX settings.
|
||||
#[derive(Debug)]
|
||||
pub struct CliResolver {
|
||||
deno_resolver: Arc<CliDenoResolver>,
|
||||
found_package_json_dep_flag: Arc<FoundPackageJsonDepFlag>,
|
||||
warned_pkgs: DashSet<PackageReq>,
|
||||
}
|
||||
|
||||
impl CliResolver {
|
||||
pub fn new(
|
||||
deno_resolver: Arc<CliDenoResolver>,
|
||||
found_package_json_dep_flag: Arc<FoundPackageJsonDepFlag>,
|
||||
) -> Self {
|
||||
Self {
|
||||
deno_resolver,
|
||||
found_package_json_dep_flag,
|
||||
warned_pkgs: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer_range_start: deno_graph::Position,
|
||||
resolution_mode: ResolutionMode,
|
||||
resolution_kind: NodeResolutionKind,
|
||||
) -> Result<ModuleSpecifier, ResolveError> {
|
||||
let resolution = self
|
||||
.deno_resolver
|
||||
.resolve(raw_specifier, referrer, resolution_mode, resolution_kind)
|
||||
.map_err(|err| match err.into_kind() {
|
||||
deno_resolver::DenoResolveErrorKind::MappedResolution(
|
||||
mapped_resolution_error,
|
||||
) => match mapped_resolution_error {
|
||||
MappedResolutionError::Specifier(e) => ResolveError::Specifier(e),
|
||||
// deno_graph checks specifically for an ImportMapError
|
||||
MappedResolutionError::ImportMap(e) => ResolveError::ImportMap(e),
|
||||
MappedResolutionError::Workspace(e) => {
|
||||
ResolveError::Other(JsErrorBox::from_err(e))
|
||||
}
|
||||
},
|
||||
err => ResolveError::Other(JsErrorBox::from_err(err)),
|
||||
})?;
|
||||
|
||||
if resolution.found_package_json_dep {
|
||||
// mark that we need to do an "npm install" later
|
||||
self.found_package_json_dep_flag.0.raise();
|
||||
}
|
||||
|
||||
if let Some(diagnostic) = resolution.maybe_diagnostic {
|
||||
match &*diagnostic {
|
||||
MappedResolutionDiagnostic::ConstraintNotMatchedLocalVersion {
|
||||
reference,
|
||||
..
|
||||
} => {
|
||||
if self.warned_pkgs.insert(reference.req().clone()) {
|
||||
log::warn!(
|
||||
"{} {}\n at {}:{}",
|
||||
colors::yellow("Warning"),
|
||||
diagnostic,
|
||||
referrer,
|
||||
referrer_range_start,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(resolution.url)
|
||||
}
|
||||
pub fn on_resolve_diagnostic(
|
||||
diagnostic: &deno_resolver::workspace::MappedResolutionDiagnostic,
|
||||
referrer: &ModuleSpecifier,
|
||||
position: deno_graph::Position,
|
||||
) {
|
||||
log::warn!(
|
||||
"{} {}\n at {}:{}",
|
||||
deno_runtime::colors::yellow("Warning"),
|
||||
diagnostic,
|
||||
referrer,
|
||||
position,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -159,8 +95,7 @@ impl deno_graph::source::NpmResolver for CliNpmGraphResolver {
|
|||
) -> NpmResolvePkgReqsResult {
|
||||
match &self.npm_installer {
|
||||
Some(npm_installer) => {
|
||||
let top_level_result = if self.found_package_json_dep_flag.0.is_raised()
|
||||
{
|
||||
let top_level_result = if self.found_package_json_dep_flag.is_raised() {
|
||||
npm_installer
|
||||
.ensure_top_level_package_json_install()
|
||||
.await
|
||||
|
|
|
@ -14,6 +14,7 @@ description = "Deno resolution algorithm"
|
|||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
graph = ["deno_graph", "node_resolver/graph"]
|
||||
sync = ["dashmap", "deno_package_json/sync", "node_resolver/sync", "deno_config/sync", "deno_cache_dir/sync"]
|
||||
|
||||
[dependencies]
|
||||
|
@ -26,12 +27,14 @@ dashmap = { workspace = true, optional = true }
|
|||
deno_cache_dir.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_error.workspace = true
|
||||
deno_graph = { workspace = true, optional = true }
|
||||
deno_media_type.workspace = true
|
||||
deno_npm.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
deno_semver.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
deno_unsync.workspace = true
|
||||
futures.workspace = true
|
||||
import_map.workspace = true
|
||||
indexmap.workspace = true
|
||||
|
|
271
resolvers/deno/graph.rs
Normal file
271
resolvers/deno/graph.rs
Normal file
|
@ -0,0 +1,271 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use deno_error::JsErrorBox;
|
||||
use deno_graph::source::ResolveError;
|
||||
use deno_semver::package::PackageReq;
|
||||
use deno_unsync::sync::AtomicFlag;
|
||||
use node_resolver::InNpmPackageChecker;
|
||||
use node_resolver::IsBuiltInNodeModuleChecker;
|
||||
use node_resolver::NpmPackageFolderResolver;
|
||||
use url::Url;
|
||||
|
||||
use crate::cjs::CjsTracker;
|
||||
use crate::workspace::MappedResolutionDiagnostic;
|
||||
use crate::workspace::MappedResolutionError;
|
||||
use crate::workspace::ScopedJsxImportSourceConfig;
|
||||
use crate::DenoResolveErrorKind;
|
||||
use crate::DenoResolverRc;
|
||||
use crate::DenoResolverSys;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type FoundPackageJsonDepFlagRc =
|
||||
crate::sync::MaybeArc<FoundPackageJsonDepFlag>;
|
||||
|
||||
/// A flag that indicates if a package.json dependency was
|
||||
/// found during resolution.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FoundPackageJsonDepFlag(AtomicFlag);
|
||||
|
||||
impl FoundPackageJsonDepFlag {
|
||||
#[inline(always)]
|
||||
pub fn raise(&self) -> bool {
|
||||
self.0.raise()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_raised(&self) -> bool {
|
||||
self.0.is_raised()
|
||||
}
|
||||
}
|
||||
|
||||
type OnWarningFn = Box<
|
||||
dyn Fn(&MappedResolutionDiagnostic, &Url, deno_graph::Position) + Send + Sync,
|
||||
>;
|
||||
|
||||
/// A resolver for interfacing with deno_graph and displaying warnings.
|
||||
pub struct DenoGraphResolver<
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoResolverSys,
|
||||
> {
|
||||
resolver: DenoResolverRc<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>,
|
||||
found_package_json_dep_flag: FoundPackageJsonDepFlagRc,
|
||||
warned_pkgs: crate::sync::MaybeDashSet<PackageReq>,
|
||||
on_warning: OnWarningFn,
|
||||
}
|
||||
|
||||
impl<
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoResolverSys,
|
||||
> std::fmt::Debug
|
||||
for DenoGraphResolver<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DenoGraphResolver").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoResolverSys,
|
||||
>
|
||||
DenoGraphResolver<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>
|
||||
{
|
||||
pub fn new(
|
||||
resolver: DenoResolverRc<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>,
|
||||
found_package_json_dep_flag: FoundPackageJsonDepFlagRc,
|
||||
on_warning: OnWarningFn,
|
||||
) -> Self {
|
||||
Self {
|
||||
resolver,
|
||||
found_package_json_dep_flag,
|
||||
warned_pkgs: Default::default(),
|
||||
on_warning,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer: &Url,
|
||||
referrer_range_start: deno_graph::Position,
|
||||
resolution_mode: node_resolver::ResolutionMode,
|
||||
resolution_kind: node_resolver::NodeResolutionKind,
|
||||
) -> Result<Url, ResolveError> {
|
||||
let resolution = self
|
||||
.resolver
|
||||
.resolve(raw_specifier, referrer, resolution_mode, resolution_kind)
|
||||
.map_err(|err| match err.into_kind() {
|
||||
DenoResolveErrorKind::MappedResolution(mapped_resolution_error) => {
|
||||
match mapped_resolution_error {
|
||||
MappedResolutionError::Specifier(e) => ResolveError::Specifier(e),
|
||||
// deno_graph checks specifically for an ImportMapError
|
||||
MappedResolutionError::ImportMap(e) => ResolveError::ImportMap(e),
|
||||
MappedResolutionError::Workspace(e) => {
|
||||
ResolveError::Other(JsErrorBox::from_err(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
err => ResolveError::Other(JsErrorBox::from_err(err)),
|
||||
})?;
|
||||
|
||||
if resolution.found_package_json_dep {
|
||||
// mark that we need to do an "npm install" later
|
||||
self.found_package_json_dep_flag.raise();
|
||||
}
|
||||
|
||||
if let Some(diagnostic) = resolution.maybe_diagnostic {
|
||||
let diagnostic = &*diagnostic;
|
||||
match diagnostic {
|
||||
MappedResolutionDiagnostic::ConstraintNotMatchedLocalVersion {
|
||||
reference,
|
||||
..
|
||||
} => {
|
||||
if self.warned_pkgs.insert(reference.req().clone()) {
|
||||
(self.on_warning)(diagnostic, referrer, referrer_range_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(resolution.url)
|
||||
}
|
||||
|
||||
pub fn as_graph_resolver<'a>(
|
||||
&'a self,
|
||||
cjs_tracker: &'a CjsTracker<TInNpmPackageChecker, TSys>,
|
||||
scoped_jsx_import_source_config: &'a ScopedJsxImportSourceConfig,
|
||||
) -> DenoGraphResolverAdapter<
|
||||
'a,
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
> {
|
||||
DenoGraphResolverAdapter {
|
||||
cjs_tracker,
|
||||
resolver: self,
|
||||
scoped_jsx_import_source_config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DenoGraphResolverAdapter<
|
||||
'a,
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoResolverSys,
|
||||
> {
|
||||
cjs_tracker: &'a CjsTracker<TInNpmPackageChecker, TSys>,
|
||||
resolver: &'a DenoGraphResolver<
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>,
|
||||
scoped_jsx_import_source_config: &'a ScopedJsxImportSourceConfig,
|
||||
}
|
||||
|
||||
impl<
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoResolverSys,
|
||||
> std::fmt::Debug
|
||||
for DenoGraphResolverAdapter<
|
||||
'_,
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DenoGraphResolverAdapter").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: DenoResolverSys,
|
||||
> deno_graph::source::Resolver
|
||||
for DenoGraphResolverAdapter<
|
||||
'_,
|
||||
TInNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TSys,
|
||||
>
|
||||
{
|
||||
fn default_jsx_import_source(&self, referrer: &Url) -> Option<String> {
|
||||
self
|
||||
.scoped_jsx_import_source_config
|
||||
.resolve_by_referrer(referrer)
|
||||
.and_then(|c| c.import_source.as_ref().map(|s| s.specifier.clone()))
|
||||
}
|
||||
|
||||
fn default_jsx_import_source_types(&self, referrer: &Url) -> Option<String> {
|
||||
self
|
||||
.scoped_jsx_import_source_config
|
||||
.resolve_by_referrer(referrer)
|
||||
.and_then(|c| c.import_source_types.as_ref().map(|s| s.specifier.clone()))
|
||||
}
|
||||
|
||||
fn jsx_import_source_module(&self, referrer: &Url) -> &str {
|
||||
self
|
||||
.scoped_jsx_import_source_config
|
||||
.resolve_by_referrer(referrer)
|
||||
.map(|c| c.module.as_str())
|
||||
.unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
raw_specifier: &str,
|
||||
referrer_range: &deno_graph::Range,
|
||||
resolution_kind: deno_graph::source::ResolutionKind,
|
||||
) -> Result<Url, ResolveError> {
|
||||
self.resolver.resolve(
|
||||
raw_specifier,
|
||||
&referrer_range.specifier,
|
||||
referrer_range.range.start,
|
||||
referrer_range
|
||||
.resolution_mode
|
||||
.map(node_resolver::ResolutionMode::from_deno_graph)
|
||||
.unwrap_or_else(|| {
|
||||
self
|
||||
.cjs_tracker
|
||||
.get_referrer_kind(&referrer_range.specifier)
|
||||
}),
|
||||
node_resolver::NodeResolutionKind::from_deno_graph(resolution_kind),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -42,6 +42,8 @@ use crate::workspace::WorkspaceResolver;
|
|||
|
||||
pub mod cjs;
|
||||
pub mod factory;
|
||||
#[cfg(feature = "graph")]
|
||||
pub mod graph;
|
||||
pub mod npm;
|
||||
pub mod npmrc;
|
||||
mod sync;
|
||||
|
@ -128,12 +130,22 @@ pub struct NodeAndNpmReqResolver<
|
|||
>,
|
||||
}
|
||||
|
||||
pub trait DenoResolverSys:
|
||||
FsCanonicalize + FsMetadata + FsRead + FsReadDir + std::fmt::Debug
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> DenoResolverSys for T where
|
||||
T: FsCanonicalize + FsMetadata + FsRead + FsReadDir + std::fmt::Debug
|
||||
{
|
||||
}
|
||||
|
||||
pub struct DenoResolverOptions<
|
||||
'a,
|
||||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
|
||||
TSys: DenoResolverSys,
|
||||
> {
|
||||
pub in_npm_pkg_checker: TInNpmPackageChecker,
|
||||
pub node_and_req_resolver: Option<
|
||||
|
@ -185,7 +197,7 @@ pub struct DenoResolver<
|
|||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
|
||||
TSys: DenoResolverSys,
|
||||
> {
|
||||
in_npm_pkg_checker: TInNpmPackageChecker,
|
||||
node_and_npm_resolver: Option<
|
||||
|
@ -206,7 +218,7 @@ impl<
|
|||
TInNpmPackageChecker: InNpmPackageChecker,
|
||||
TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver,
|
||||
TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir,
|
||||
TSys: DenoResolverSys,
|
||||
>
|
||||
DenoResolver<
|
||||
TInNpmPackageChecker,
|
||||
|
|
|
@ -11,6 +11,8 @@ mod inner {
|
|||
pub use std::sync::Arc as MaybeArc;
|
||||
|
||||
pub use dashmap::DashMap as MaybeDashMap;
|
||||
#[cfg(feature = "graph")]
|
||||
pub use dashmap::DashSet as MaybeDashSet;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sync"))]
|
||||
|
@ -58,6 +60,32 @@ mod inner {
|
|||
inner.insert(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper struct that exposes a subset of `DashMap` API.
|
||||
#[cfg(feature = "graph")]
|
||||
#[derive(Debug)]
|
||||
pub struct MaybeDashSet<V, S = RandomState>(
|
||||
RefCell<std::collections::HashSet<V, S>>,
|
||||
);
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
impl<V, S> Default for MaybeDashSet<V, S>
|
||||
where
|
||||
V: Eq + Hash,
|
||||
S: Default + BuildHasher + Clone,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self(RefCell::new(Default::default()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
impl<V: Eq + Hash, S: BuildHasher> MaybeDashSet<V, S> {
|
||||
pub fn insert(&self, value: V) -> bool {
|
||||
let mut inner = self.0.borrow_mut();
|
||||
inner.insert(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
|
|
|
@ -10,8 +10,11 @@ use std::path::PathBuf;
|
|||
|
||||
use deno_config::deno_json::ConfigFile;
|
||||
use deno_config::deno_json::ConfigFileError;
|
||||
use deno_config::workspace::JsxImportSourceConfig;
|
||||
use deno_config::workspace::ResolverWorkspaceJsrPackage;
|
||||
use deno_config::workspace::ToMaybeJsxImportSourceConfigError;
|
||||
use deno_config::workspace::Workspace;
|
||||
use deno_config::workspace::WorkspaceDirectory;
|
||||
use deno_error::JsError;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
|
@ -1634,6 +1637,41 @@ impl BaseUrl<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScopedJsxImportSourceConfig {
|
||||
unscoped: Option<JsxImportSourceConfig>,
|
||||
by_scope: BTreeMap<UrlRc, Option<JsxImportSourceConfig>>,
|
||||
}
|
||||
|
||||
impl ScopedJsxImportSourceConfig {
|
||||
pub fn from_workspace_dir(
|
||||
start_dir: &WorkspaceDirectory,
|
||||
) -> Result<Self, ToMaybeJsxImportSourceConfigError> {
|
||||
let unscoped = start_dir.to_maybe_jsx_import_source_config()?;
|
||||
let mut by_scope = BTreeMap::default();
|
||||
for (dir_url, _) in start_dir.workspace.config_folders() {
|
||||
let dir = start_dir.workspace.resolve_member_dir(dir_url);
|
||||
let jsx_import_source_config_unscoped =
|
||||
dir.to_maybe_jsx_import_source_config()?;
|
||||
by_scope.insert(dir_url.clone(), jsx_import_source_config_unscoped);
|
||||
}
|
||||
Ok(Self { unscoped, by_scope })
|
||||
}
|
||||
|
||||
/// Resolves the `JsxImportSourceConfig` to use for the provided referrer.
|
||||
pub fn resolve_by_referrer(
|
||||
&self,
|
||||
referrer: &Url,
|
||||
) -> Option<&JsxImportSourceConfig> {
|
||||
self
|
||||
.by_scope
|
||||
.iter()
|
||||
.rfind(|(s, _)| referrer.as_str().starts_with(s.as_str()))
|
||||
.map(|(_, c)| c.as_ref())
|
||||
.unwrap_or(self.unscoped.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::Path;
|
||||
|
|
|
@ -14,6 +14,7 @@ description = "Node.js module resolution algorithm used in Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
graph = ["deno_graph"]
|
||||
sync = ["deno_package_json/sync"]
|
||||
|
||||
[dependencies]
|
||||
|
@ -23,6 +24,7 @@ boxed_error.workspace = true
|
|||
dashmap.workspace = true
|
||||
deno_config.workspace = true
|
||||
deno_error.workspace = true
|
||||
deno_graph = { workspace = true, optional = true }
|
||||
deno_media_type.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
deno_path_util.workspace = true
|
||||
|
|
|
@ -106,6 +106,15 @@ impl ResolutionMode {
|
|||
ResolutionMode::Require => REQUIRE_CONDITIONS,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
pub fn from_deno_graph(mode: deno_graph::source::ResolutionMode) -> Self {
|
||||
use deno_graph::source::ResolutionMode::*;
|
||||
match mode {
|
||||
Import => Self::Import,
|
||||
Require => Self::Require,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -118,6 +127,15 @@ impl NodeResolutionKind {
|
|||
pub fn is_types(&self) -> bool {
|
||||
matches!(self, NodeResolutionKind::Types)
|
||||
}
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
pub fn from_deno_graph(kind: deno_graph::source::ResolutionKind) -> Self {
|
||||
use deno_graph::source::ResolutionKind::*;
|
||||
match kind {
|
||||
Execution => Self::Execution,
|
||||
Types => Self::Types,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue