use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_config::glob::FilePatterns;
use deno_config::glob::PathOrPatternSet;
use deno_core::error::AnyError;
use deno_core::parking_lot::RwLock;
use deno_graph::ModuleGraph;
use deno_runtime::colors;
use deno_runtime::deno_permissions::PermissionsContainer;
use crate::args::CliOptions;
use crate::module_loader::ModuleLoadPreparer;
use crate::module_loader::PrepareModuleLoadOptions;
use crate::util::fs::collect_specifiers;
use crate::util::path::is_script_ext;
pub trait ModuleGraphContainer: Clone + 'static {
async fn acquire_update_permit(&self) -> impl ModuleGraphUpdatePermit;
fn graph(&self) -> Arc<ModuleGraph>;
}
pub trait ModuleGraphUpdatePermit {
fn graph_mut(&mut self) -> &mut ModuleGraph;
fn commit(self);
}
#[derive(Clone)]
pub struct MainModuleGraphContainer {
update_queue: Arc<deno_core::unsync::sync::TaskQueue>,
inner: Arc<RwLock<Arc<ModuleGraph>>>,
cli_options: Arc<CliOptions>,
module_load_preparer: Arc<ModuleLoadPreparer>,
root_permissions: PermissionsContainer,
}
#[derive(Default, Debug)]
pub struct CheckSpecifiersOptions<'a> {
pub ext_overwrite: Option<&'a String>,
pub allow_unknown_media_types: bool,
}
pub struct CollectSpecifiersOptions {
pub include_ignored_specified: bool,
}
impl MainModuleGraphContainer {
pub fn new(
cli_options: Arc<CliOptions>,
module_load_preparer: Arc<ModuleLoadPreparer>,
root_permissions: PermissionsContainer,
) -> Self {
Self {
update_queue: Default::default(),
inner: Arc::new(RwLock::new(Arc::new(ModuleGraph::new(
cli_options.graph_kind(),
)))),
cli_options,
module_load_preparer,
root_permissions,
}
}
pub async fn check_specifiers(
&self,
specifiers: &[ModuleSpecifier],
options: CheckSpecifiersOptions<'_>,
) -> Result<(), AnyError> {
let mut graph_permit = self.acquire_update_permit().await;
let graph = graph_permit.graph_mut();
self
.module_load_preparer
.prepare_module_load(
graph,
specifiers,
PrepareModuleLoadOptions {
is_dynamic: false,
lib: self.cli_options.ts_type_lib_window(),
permissions: self.root_permissions.clone(),
ext_overwrite: options.ext_overwrite,
allow_unknown_media_types: options.allow_unknown_media_types,
skip_graph_roots_validation: false,
},
)
.await?;
graph_permit.commit();
Ok(())
}
pub async fn load_and_type_check_files(
&self,
files: &[String],
options: CollectSpecifiersOptions,
) -> Result<(), AnyError> {
let specifiers = self.collect_specifiers(files, options)?;
if specifiers.is_empty() {
log::warn!("{} No matching files found.", colors::yellow("Warning"));
}
self.check_specifiers(&specifiers, Default::default()).await
}
pub fn collect_specifiers(
&self,
files: &[String],
options: CollectSpecifiersOptions,
) -> Result<Vec<ModuleSpecifier>, AnyError> {
let excludes = self.cli_options.workspace().resolve_config_excludes()?;
let include_patterns =
PathOrPatternSet::from_include_relative_path_or_patterns(
self.cli_options.initial_cwd(),
files,
)?;
let file_patterns = FilePatterns {
base: self.cli_options.initial_cwd().to_path_buf(),
include: Some(include_patterns),
exclude: excludes,
};
collect_specifiers(
crate::util::fs::CollectSpecifiersOptions {
file_patterns,
vendor_folder: self
.cli_options
.vendor_dir_path()
.map(ToOwned::to_owned),
include_ignored_specified: options.include_ignored_specified,
},
|e| is_script_ext(e.path),
)
}
}
impl ModuleGraphContainer for MainModuleGraphContainer {
async fn acquire_update_permit(&self) -> impl ModuleGraphUpdatePermit {
let permit = self.update_queue.acquire().await;
MainModuleGraphUpdatePermit {
permit,
inner: self.inner.clone(),
graph: (**self.inner.read()).clone(),
}
}
fn graph(&self) -> Arc<ModuleGraph> {
self.inner.read().clone()
}
}
pub struct MainModuleGraphUpdatePermit<'a> {
permit: deno_core::unsync::sync::TaskQueuePermit<'a>,
inner: Arc<RwLock<Arc<ModuleGraph>>>,
graph: ModuleGraph,
}
impl ModuleGraphUpdatePermit for MainModuleGraphUpdatePermit<'_> {
fn graph_mut(&mut self) -> &mut ModuleGraph {
&mut self.graph
}
fn commit(self) {
*self.inner.write() = Arc::new(self.graph);
drop(self.permit); }
}