summaryrefslogtreecommitdiff
path: root/cli/tools
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools')
-rw-r--r--cli/tools/bench.rs245
-rw-r--r--cli/tools/bundle.rs203
-rw-r--r--cli/tools/fmt.rs147
-rw-r--r--cli/tools/lint.rs258
-rw-r--r--cli/tools/run.rs66
-rw-r--r--cli/tools/test.rs305
6 files changed, 540 insertions, 684 deletions
diff --git a/cli/tools/bench.rs b/cli/tools/bench.rs
index a7b75d8be..318ac4f36 100644
--- a/cli/tools/bench.rs
+++ b/cli/tools/bench.rs
@@ -1,17 +1,19 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::args::BenchOptions;
+use crate::args::BenchFlags;
use crate::args::CliOptions;
+use crate::args::Flags;
use crate::colors;
use crate::display::write_json_to_stdout;
use crate::factory::CliFactory;
+use crate::factory::CliFactoryBuilder;
use crate::graph_util::graph_valid_with_cli_options;
+use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::module_loader::ModuleLoadPreparer;
use crate::ops;
use crate::tools::test::format_test_error;
use crate::tools::test::TestFilter;
use crate::util::file_watcher;
-use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers;
use crate::util::path::is_supported_ext;
use crate::version::get_user_agent;
@@ -22,7 +24,6 @@ use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::futures::future;
use deno_core::futures::stream;
-use deno_core::futures::FutureExt;
use deno_core::futures::StreamExt;
use deno_core::located_script_name;
use deno_core::serde_v8;
@@ -40,7 +41,6 @@ use serde::Deserialize;
use serde::Serialize;
use std::collections::HashSet;
use std::path::Path;
-use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedSender;
@@ -630,9 +630,11 @@ fn is_supported_bench_path(path: &Path) -> bool {
}
pub async fn run_benchmarks(
- cli_options: CliOptions,
- bench_options: BenchOptions,
+ flags: Flags,
+ bench_flags: BenchFlags,
) -> Result<(), AnyError> {
+ let cli_options = CliOptions::from_flags(flags)?;
+ let bench_options = cli_options.resolve_bench_options(bench_flags)?;
let factory = CliFactory::from_cli_options(Arc::new(cli_options));
let cli_options = factory.cli_options();
// Various bench files should not share the same permissions in terms of
@@ -679,168 +681,101 @@ pub async fn run_benchmarks(
// TODO(bartlomieju): heavy duplication of code with `cli/tools/test.rs`
pub async fn run_benchmarks_with_watch(
- cli_options: CliOptions,
- bench_options: BenchOptions,
+ flags: Flags,
+ bench_flags: BenchFlags,
) -> Result<(), AnyError> {
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
- let cli_options = factory.cli_options();
- let module_graph_builder = factory.module_graph_builder().await?;
- let file_watcher = factory.file_watcher()?;
- let module_load_preparer = factory.module_load_preparer().await?;
- // Various bench files should not share the same permissions in terms of
- // `PermissionsContainer` - otherwise granting/revoking permissions in one
- // file would have impact on other files, which is undesirable.
- let permissions =
- Permissions::from_options(&cli_options.permissions_options())?;
- let graph_kind = cli_options.type_check_mode().as_graph_kind();
-
- let resolver = |changed: Option<Vec<PathBuf>>| {
- let paths_to_watch = bench_options.files.include.clone();
- let paths_to_watch_clone = paths_to_watch.clone();
- let files_changed = changed.is_some();
- let bench_options = &bench_options;
- let module_graph_builder = module_graph_builder.clone();
- let cli_options = cli_options.clone();
-
- async move {
- let bench_modules =
- collect_specifiers(&bench_options.files, is_supported_bench_path)?;
-
- let mut paths_to_watch = paths_to_watch_clone;
- let mut modules_to_reload = if files_changed {
- Vec::new()
- } else {
- bench_modules.clone()
- };
- let graph = module_graph_builder
- .create_graph(graph_kind, bench_modules.clone())
- .await?;
- graph_valid_with_cli_options(&graph, &bench_modules, &cli_options)?;
-
- // TODO(@kitsonk) - This should be totally derivable from the graph.
- for specifier in bench_modules {
- fn get_dependencies<'a>(
- graph: &'a deno_graph::ModuleGraph,
- maybe_module: Option<&'a deno_graph::Module>,
- // This needs to be accessible to skip getting dependencies if they're already there,
- // otherwise this will cause a stack overflow with circular dependencies
- output: &mut HashSet<&'a ModuleSpecifier>,
- ) {
- if let Some(module) = maybe_module.and_then(|m| m.esm()) {
- for dep in module.dependencies.values() {
- if let Some(specifier) = &dep.get_code() {
- if !output.contains(specifier) {
- output.insert(specifier);
- get_dependencies(graph, graph.get(specifier), output);
- }
- }
- if let Some(specifier) = &dep.get_type() {
- if !output.contains(specifier) {
- output.insert(specifier);
- get_dependencies(graph, graph.get(specifier), output);
- }
- }
- }
- }
+ let clear_screen = !flags.no_clear_screen;
+ file_watcher::watch_func(
+ flags,
+ file_watcher::PrintConfig {
+ job_name: "Bench".to_string(),
+ clear_screen,
+ },
+ move |flags, sender, changed_paths| {
+ let bench_flags = bench_flags.clone();
+ Ok(async move {
+ let factory = CliFactoryBuilder::new()
+ .with_watcher(sender.clone())
+ .build_from_flags(flags)
+ .await?;
+ let cli_options = factory.cli_options();
+ let bench_options = cli_options.resolve_bench_options(bench_flags)?;
+
+ if let Some(watch_paths) = cli_options.watch_paths() {
+ let _ = sender.send(watch_paths);
}
+ let _ = sender.send(bench_options.files.include.clone());
- // This bench module and all it's dependencies
- let mut modules = HashSet::new();
- modules.insert(&specifier);
- get_dependencies(&graph, graph.get(&specifier), &mut modules);
+ let graph_kind = cli_options.type_check_mode().as_graph_kind();
+ let module_graph_builder = factory.module_graph_builder().await?;
+ let module_load_preparer = factory.module_load_preparer().await?;
- paths_to_watch.extend(
- modules
- .iter()
- .filter_map(|specifier| specifier.to_file_path().ok()),
- );
+ let bench_modules =
+ collect_specifiers(&bench_options.files, is_supported_bench_path)?;
- if let Some(changed) = &changed {
- for path in changed
- .iter()
- .filter_map(|path| ModuleSpecifier::from_file_path(path).ok())
- {
- if modules.contains(&path) {
- modules_to_reload.push(specifier);
- break;
- }
- }
- }
- }
+ // Various bench files should not share the same permissions in terms of
+ // `PermissionsContainer` - otherwise granting/revoking permissions in one
+ // file would have impact on other files, which is undesirable.
+ let permissions =
+ Permissions::from_options(&cli_options.permissions_options())?;
- Ok((paths_to_watch, modules_to_reload))
- }
- .map(move |result| {
- if files_changed
- && matches!(result, Ok((_, ref modules)) if modules.is_empty())
- {
- ResolutionResult::Ignore
- } else {
- match result {
- Ok((paths_to_watch, modules_to_reload)) => {
- ResolutionResult::Restart {
- paths_to_watch,
- result: Ok(modules_to_reload),
+ let graph = module_graph_builder
+ .create_graph(graph_kind, bench_modules.clone())
+ .await?;
+ graph_valid_with_cli_options(&graph, &bench_modules, cli_options)?;
+
+ let bench_modules_to_reload = if let Some(changed_paths) = changed_paths
+ {
+ let changed_specifiers = changed_paths
+ .into_iter()
+ .filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
+ .collect::<HashSet<_>>();
+ let mut result = Vec::new();
+ for bench_module_specifier in bench_modules {
+ if has_graph_root_local_dependent_changed(
+ &graph,
+ &bench_module_specifier,
+ &changed_specifiers,
+ ) {
+ result.push(bench_module_specifier.clone());
}
}
- Err(e) => ResolutionResult::Restart {
- paths_to_watch,
- result: Err(e),
- },
- }
- }
- })
- };
+ result
+ } else {
+ bench_modules.clone()
+ };
- let create_cli_main_worker_factory =
- factory.create_cli_main_worker_factory_func().await?;
- let operation = |modules_to_reload: Vec<ModuleSpecifier>| {
- let permissions = &permissions;
- let bench_options = &bench_options;
- file_watcher.reset();
- let module_load_preparer = module_load_preparer.clone();
- let cli_options = cli_options.clone();
- let create_cli_main_worker_factory = create_cli_main_worker_factory.clone();
-
- async move {
- let worker_factory = Arc::new(create_cli_main_worker_factory());
- let specifiers =
- collect_specifiers(&bench_options.files, is_supported_bench_path)?
- .into_iter()
- .filter(|specifier| modules_to_reload.contains(specifier))
- .collect::<Vec<ModuleSpecifier>>();
-
- check_specifiers(&cli_options, &module_load_preparer, specifiers.clone())
- .await?;
+ let worker_factory =
+ Arc::new(factory.create_cli_main_worker_factory().await?);
- if bench_options.no_run {
- return Ok(());
- }
+ let specifiers =
+ collect_specifiers(&bench_options.files, is_supported_bench_path)?
+ .into_iter()
+ .filter(|specifier| bench_modules_to_reload.contains(specifier))
+ .collect::<Vec<ModuleSpecifier>>();
- let log_level = cli_options.log_level();
- bench_specifiers(
- worker_factory,
- permissions,
- specifiers,
- BenchSpecifierOptions {
- filter: TestFilter::from_flag(&bench_options.filter),
- json: bench_options.json,
- log_level,
- },
- )
- .await?;
+ check_specifiers(cli_options, module_load_preparer, specifiers.clone())
+ .await?;
- Ok(())
- }
- };
+ if bench_options.no_run {
+ return Ok(());
+ }
- let clear_screen = !cli_options.no_clear_screen();
- file_watcher::watch_func(
- resolver,
- operation,
- file_watcher::PrintConfig {
- job_name: "Bench".to_string(),
- clear_screen,
+ let log_level = cli_options.log_level();
+ bench_specifiers(
+ worker_factory,
+ &permissions,
+ specifiers,
+ BenchSpecifierOptions {
+ filter: TestFilter::from_flag(&bench_options.filter),
+ json: bench_options.json,
+ log_level,
+ },
+ )
+ .await?;
+
+ Ok(())
+ })
},
)
.await?;
diff --git a/cli/tools/bundle.rs b/cli/tools/bundle.rs
index f38948776..1800d03cc 100644
--- a/cli/tools/bundle.rs
+++ b/cli/tools/bundle.rs
@@ -1,10 +1,8 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::path::PathBuf;
-use std::sync::Arc;
use deno_core::error::AnyError;
-use deno_core::futures::FutureExt;
use deno_graph::Module;
use deno_runtime::colors;
@@ -13,17 +11,15 @@ use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::TsConfigType;
use crate::factory::CliFactory;
+use crate::factory::CliFactoryBuilder;
use crate::graph_util::error_for_any_npm_specifier;
use crate::util;
use crate::util::display;
-use crate::util::file_watcher::ResolutionResult;
pub async fn bundle(
flags: Flags,
bundle_flags: BundleFlags,
) -> Result<(), AnyError> {
- let cli_options = Arc::new(CliOptions::from_flags(flags)?);
-
log::info!(
"{} \"deno bundle\" is deprecated and will be removed in the future.",
colors::yellow("Warning"),
@@ -32,119 +28,112 @@ pub async fn bundle(
"Use alternative bundlers like \"deno_emit\", \"esbuild\" or \"rollup\" instead."
);
- let module_specifier = cli_options.resolve_main_module()?;
-
- let resolver = |_| {
- let cli_options = cli_options.clone();
- let module_specifier = &module_specifier;
- async move {
- log::debug!(">>>>> bundle START");
- let factory = CliFactory::from_cli_options(cli_options);
- let module_graph_builder = factory.module_graph_builder().await?;
- let cli_options = factory.cli_options();
-
- let graph = module_graph_builder
- .create_graph_and_maybe_check(vec![module_specifier.clone()])
- .await?;
-
- let mut paths_to_watch: Vec<PathBuf> = graph
- .specifiers()
- .filter_map(|(_, r)| {
- r.ok().and_then(|module| match module {
- Module::Esm(m) => m.specifier.to_file_path().ok(),
- Module::Json(m) => m.specifier.to_file_path().ok(),
- // nothing to watch
- Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
- })
- })
- .collect();
-
- if let Ok(Some(import_map_path)) = cli_options
- .resolve_import_map_specifier()
- .map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
- {
- paths_to_watch.push(import_map_path);
- }
-
- Ok((paths_to_watch, graph, cli_options.clone()))
- }
- .map(move |result| match result {
- Ok((paths_to_watch, graph, ps)) => ResolutionResult::Restart {
- paths_to_watch,
- result: Ok((ps, graph)),
- },
- Err(e) => ResolutionResult::Restart {
- paths_to_watch: vec![module_specifier.to_file_path().unwrap()],
- result: Err(e),
+ if flags.watch.is_some() {
+ let clear_screen = !flags.no_clear_screen;
+ util::file_watcher::watch_func(
+ flags,
+ util::file_watcher::PrintConfig {
+ job_name: "Bundle".to_string(),
+ clear_screen,
},
- })
- };
-
- let operation =
- |(cli_options, graph): (Arc<CliOptions>, Arc<deno_graph::ModuleGraph>)| {
- let out_file = &bundle_flags.out_file;
- async move {
- // at the moment, we don't support npm specifiers in deno bundle, so show an error
- error_for_any_npm_specifier(&graph)?;
-
- let bundle_output = bundle_module_graph(graph.as_ref(), &cli_options)?;
- log::debug!(">>>>> bundle END");
-
- if let Some(out_file) = out_file {
- let output_bytes = bundle_output.code.as_bytes();
- let output_len = output_bytes.len();
- util::fs::write_file(out_file, output_bytes, 0o644)?;
- log::info!(
- "{} {:?} ({})",
- colors::green("Emit"),
- out_file,
- colors::gray(display::human_size(output_len as f64))
- );
- if let Some(bundle_map) = bundle_output.maybe_map {
- let map_bytes = bundle_map.as_bytes();
- let map_len = map_bytes.len();
- let ext = if let Some(curr_ext) = out_file.extension() {
- format!("{}.map", curr_ext.to_string_lossy())
- } else {
- "map".to_string()
- };
- let map_out_file = out_file.with_extension(ext);
- util::fs::write_file(&map_out_file, map_bytes, 0o644)?;
- log::info!(
- "{} {:?} ({})",
- colors::green("Emit"),
- map_out_file,
- colors::gray(display::human_size(map_len as f64))
- );
+ move |flags, sender, _changed_paths| {
+ let bundle_flags = bundle_flags.clone();
+ Ok(async move {
+ let factory = CliFactoryBuilder::new()
+ .with_watcher(sender.clone())
+ .build_from_flags(flags)
+ .await?;
+ let cli_options = factory.cli_options();
+
+ if let Some(watch_paths) = cli_options.watch_paths() {
+ let _ = sender.send(watch_paths);
}
- } else {
- println!("{}", bundle_output.code);
- }
- Ok(())
- }
- };
+ bundle_action(factory, &bundle_flags).await?;
- if cli_options.watch_paths().is_some() {
- util::file_watcher::watch_func(
- resolver,
- operation,
- util::file_watcher::PrintConfig {
- job_name: "Bundle".to_string(),
- clear_screen: !cli_options.no_clear_screen(),
+ Ok(())
+ })
},
)
.await?;
} else {
- let module_graph =
- if let ResolutionResult::Restart { result, .. } = resolver(None).await {
- result?
+ let factory = CliFactory::from_flags(flags).await?;
+ bundle_action(factory, &bundle_flags).await?;
+ }
+
+ Ok(())
+}
+
+async fn bundle_action(
+ factory: CliFactory,
+ bundle_flags: &BundleFlags,
+) -> Result<(), AnyError> {
+ let cli_options = factory.cli_options();
+ let module_specifier = cli_options.resolve_main_module()?;
+ log::debug!(">>>>> bundle START");
+ let module_graph_builder = factory.module_graph_builder().await?;
+ let cli_options = factory.cli_options();
+
+ let graph = module_graph_builder
+ .create_graph_and_maybe_check(vec![module_specifier.clone()])
+ .await?;
+
+ let mut paths_to_watch: Vec<PathBuf> = graph
+ .specifiers()
+ .filter_map(|(_, r)| {
+ r.ok().and_then(|module| match module {
+ Module::Esm(m) => m.specifier.to_file_path().ok(),
+ Module::Json(m) => m.specifier.to_file_path().ok(),
+ // nothing to watch
+ Module::Node(_) | Module::Npm(_) | Module::External(_) => None,
+ })
+ })
+ .collect();
+
+ if let Ok(Some(import_map_path)) = cli_options
+ .resolve_import_map_specifier()
+ .map(|ms| ms.and_then(|ref s| s.to_file_path().ok()))
+ {
+ paths_to_watch.push(import_map_path);
+ }
+
+ // at the moment, we don't support npm specifiers in deno bundle, so show an error
+ error_for_any_npm_specifier(&graph)?;
+
+ let bundle_output = bundle_module_graph(graph.as_ref(), cli_options)?;
+ log::debug!(">>>>> bundle END");
+ let out_file = &bundle_flags.out_file;
+
+ if let Some(out_file) = out_file {
+ let output_bytes = bundle_output.code.as_bytes();
+ let output_len = output_bytes.len();
+ util::fs::write_file(out_file, output_bytes, 0o644)?;
+ log::info!(
+ "{} {:?} ({})",
+ colors::green("Emit"),
+ out_file,
+ colors::gray(display::human_size(output_len as f64))
+ );
+ if let Some(bundle_map) = bundle_output.maybe_map {
+ let map_bytes = bundle_map.as_bytes();
+ let map_len = map_bytes.len();
+ let ext = if let Some(curr_ext) = out_file.extension() {
+ format!("{}.map", curr_ext.to_string_lossy())
} else {
- unreachable!();
+ "map".to_string()
};
- operation(module_graph).await?;
+ let map_out_file = out_file.with_extension(ext);
+ util::fs::write_file(&map_out_file, map_bytes, 0o644)?;
+ log::info!(
+ "{} {:?} ({})",
+ colors::green("Emit"),
+ map_out_file,
+ colors::gray(display::human_size(map_len as f64))
+ );
+ }
+ } else {
+ println!("{}", bundle_output.code);
}
-
Ok(())
}
diff --git a/cli/tools/fmt.rs b/cli/tools/fmt.rs
index f2fec9302..7116c78cc 100644
--- a/cli/tools/fmt.rs
+++ b/cli/tools/fmt.rs
@@ -9,6 +9,8 @@
use crate::args::CliOptions;
use crate::args::FilesConfig;
+use crate::args::Flags;
+use crate::args::FmtFlags;
use crate::args::FmtOptions;
use crate::args::FmtOptionsConfig;
use crate::args::ProseWrap;
@@ -16,7 +18,6 @@ use crate::colors;
use crate::factory::CliFactory;
use crate::util::diff::diff;
use crate::util::file_watcher;
-use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::FileCollector;
use crate::util::path::get_extension;
use crate::util::text_encoding;
@@ -46,11 +47,10 @@ use std::sync::Arc;
use crate::cache::IncrementalCache;
/// Format JavaScript/TypeScript files.
-pub async fn format(
- cli_options: CliOptions,
- fmt_options: FmtOptions,
-) -> Result<(), AnyError> {
- if fmt_options.is_stdin {
+pub async fn format(flags: Flags, fmt_flags: FmtFlags) -> Result<(), AnyError> {
+ if fmt_flags.is_stdin() {
+ let cli_options = CliOptions::from_flags(flags)?;
+ let fmt_options = cli_options.resolve_fmt_options(fmt_flags)?;
return format_stdin(
fmt_options,
cli_options
@@ -61,90 +61,93 @@ pub async fn format(
);
}
- let files = fmt_options.files;
- let check = fmt_options.check;
- let fmt_config_options = fmt_options.options;
-
- let resolver = |changed: Option<Vec<PathBuf>>| {
- let files_changed = changed.is_some();
-
- let result = collect_fmt_files(&files).map(|files| {
- let refmt_files = if let Some(paths) = changed {
- if check {
- files
- .iter()
- .any(|path| paths.contains(path))
- .then_some(files)
- .unwrap_or_else(|| [].to_vec())
- } else {
- files
- .into_iter()
- .filter(|path| paths.contains(path))
- .collect::<Vec<_>>()
- }
- } else {
- files
- };
- (refmt_files, fmt_config_options.clone())
- });
-
- let paths_to_watch = files.include.clone();
- async move {
- if files_changed
- && matches!(result, Ok((ref files, _)) if files.is_empty())
- {
- ResolutionResult::Ignore
- } else {
- ResolutionResult::Restart {
- paths_to_watch,
- result,
- }
- }
- }
- };
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
- let cli_options = factory.cli_options();
- let caches = factory.caches()?;
- let operation = |(paths, fmt_options): (Vec<PathBuf>, FmtOptionsConfig)| async {
- let incremental_cache = Arc::new(IncrementalCache::new(
- caches.fmt_incremental_cache_db(),
- &fmt_options,
- &paths,
- ));
- if check {
- check_source_files(paths, fmt_options, incremental_cache.clone()).await?;
- } else {
- format_source_files(paths, fmt_options, incremental_cache.clone())
- .await?;
- }
- incremental_cache.wait_completion().await;
- Ok(())
- };
-
- if cli_options.watch_paths().is_some() {
+ if flags.watch.is_some() {
+ let clear_screen = !flags.no_clear_screen;
file_watcher::watch_func(
- resolver,
- operation,
+ flags,
file_watcher::PrintConfig {
job_name: "Fmt".to_string(),
- clear_screen: !cli_options.no_clear_screen(),
+ clear_screen,
+ },
+ move |flags, sender, changed_paths| {
+ let fmt_flags = fmt_flags.clone();
+ Ok(async move {
+ let factory = CliFactory::from_flags(flags).await?;
+ let cli_options = factory.cli_options();
+ let fmt_options = cli_options.resolve_fmt_options(fmt_flags)?;
+ let files =
+ collect_fmt_files(&fmt_options.files).and_then(|files| {
+ if files.is_empty() {
+ Err(generic_error("No target files found."))
+ } else {
+ Ok(files)
+ }
+ })?;
+ _ = sender.send(files.clone());
+ let refmt_files = if let Some(paths) = changed_paths {
+ if fmt_options.check {
+ // check all files on any changed (https://github.com/denoland/deno/issues/12446)
+ files
+ .iter()
+ .any(|path| paths.contains(path))
+ .then_some(files)
+ .unwrap_or_else(|| [].to_vec())
+ } else {
+ files
+ .into_iter()
+ .filter(|path| paths.contains(path))
+ .collect::<Vec<_>>()
+ }
+ } else {
+ files
+ };
+ format_files(factory, fmt_options, refmt_files).await?;
+
+ Ok(())
+ })
},
)
.await?;
} else {
- let files = collect_fmt_files(&files).and_then(|files| {
+ let factory = CliFactory::from_flags(flags).await?;
+ let cli_options = factory.cli_options();
+ let fmt_options = cli_options.resolve_fmt_options(fmt_flags)?;
+ let files = collect_fmt_files(&fmt_options.files).and_then(|files| {
if files.is_empty() {
Err(generic_error("No target files found."))
} else {
Ok(files)
}
})?;
- operation((files, fmt_config_options)).await?;
+ format_files(factory, fmt_options, files).await?;
}
Ok(())
}
+async fn format_files(
+ factory: CliFactory,
+ fmt_options: FmtOptions,
+ paths: Vec<PathBuf>,
+) -> Result<(), AnyError> {
+ let caches = factory.caches()?;
+ let check = fmt_options.check;
+ let incremental_cache = Arc::new(IncrementalCache::new(
+ caches.fmt_incremental_cache_db(),
+ &fmt_options.options,
+ &paths,
+ ));
+ if check {
+ check_source_files(paths, fmt_options.options, incremental_cache.clone())
+ .await?;
+ } else {
+ format_source_files(paths, fmt_options.options, incremental_cache.clone())
+ .await?;
+ }
+ incremental_cache.wait_completion().await;
+ Ok(())
+}
+
fn collect_fmt_files(files: &FilesConfig) -> Result<Vec<PathBuf>, AnyError> {
FileCollector::new(is_supported_ext_fmt)
.ignore_git_folder()
diff --git a/cli/tools/lint.rs b/cli/tools/lint.rs
index 40c37ce77..9bfe1fd16 100644
--- a/cli/tools/lint.rs
+++ b/cli/tools/lint.rs
@@ -2,12 +2,9 @@
//! This module provides file linting utilities using
//! [`deno_lint`](https://github.com/denoland/deno_lint).
-//!
-//! At the moment it is only consumed using CLI but in
-//! the future it can be easily extended to provide
-//! the same functions as ops available in JS runtime.
-use crate::args::CliOptions;
use crate::args::FilesConfig;
+use crate::args::Flags;
+use crate::args::LintFlags;
use crate::args::LintOptions;
use crate::args::LintReporterKind;
use crate::args::LintRulesConfig;
@@ -15,9 +12,9 @@ use crate::colors;
use crate::factory::CliFactory;
use crate::tools::fmt::run_parallelized;
use crate::util::file_watcher;
-use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::FileCollector;
use crate::util::path::is_supported_ext;
+use crate::util::sync::AtomicFlag;
use deno_ast::MediaType;
use deno_core::anyhow::bail;
use deno_core::error::generic_error;
@@ -38,8 +35,6 @@ use std::io::stdin;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::sync::Mutex;
@@ -55,133 +50,70 @@ fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> {
}
}
-pub async fn lint(
- cli_options: CliOptions,
- lint_options: LintOptions,
-) -> Result<(), AnyError> {
- // Try to get lint rules. If none were set use recommended rules.
- let lint_rules = get_configured_rules(lint_options.rules);
-
- if lint_rules.is_empty() {
- bail!("No rules have been configured")
- }
-
- let files = lint_options.files;
- let reporter_kind = lint_options.reporter_kind;
-
- let resolver = |changed: Option<Vec<PathBuf>>| {
- let files_changed = changed.is_some();
- let result = collect_lint_files(&files).map(|files| {
- if let Some(paths) = changed {
- files
- .iter()
- .any(|path| paths.contains(path))
- .then_some(files)
- .unwrap_or_else(|| [].to_vec())
- } else {
- files
- }
- });
-
- let paths_to_watch = files.include.clone();
-
- async move {
- if files_changed && matches!(result, Ok(ref files) if files.is_empty()) {
- ResolutionResult::Ignore
- } else {
- ResolutionResult::Restart {
- paths_to_watch,
- result,
- }
- }
- }
- };
-
- let has_error = Arc::new(AtomicBool::new(false));
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
- let cli_options = factory.cli_options();
- let caches = factory.caches()?;
- let operation = |paths: Vec<PathBuf>| async {
- let incremental_cache = Arc::new(IncrementalCache::new(
- caches.lint_incremental_cache_db(),
- // use a hash of the rule names in order to bust the cache
- &{
- // ensure this is stable by sorting it
- let mut names = lint_rules.iter().map(|r| r.code()).collect::<Vec<_>>();
- names.sort_unstable();
- names
- },
- &paths,
- ));
- let target_files_len = paths.len();
- let reporter_lock =
- Arc::new(Mutex::new(create_reporter(reporter_kind.clone())));
-
- run_parallelized(paths, {
- let has_error = has_error.clone();
- let lint_rules = lint_rules.clone();
- let reporter_lock = reporter_lock.clone();
- let incremental_cache = incremental_cache.clone();
- move |file_path| {
- let file_text = fs::read_to_string(&file_path)?;
-
- // don't bother rechecking this file if it didn't have any diagnostics before
- if incremental_cache.is_file_same(&file_path, &file_text) {
- return Ok(());
- }
-
- let r = lint_file(&file_path, file_text, lint_rules);
- if let Ok((file_diagnostics, file_text)) = &r {
- if file_diagnostics.is_empty() {
- // update the incremental cache if there were no diagnostics
- incremental_cache.update_file(&file_path, file_text)
- }
- }
-
- handle_lint_result(
- &file_path.to_string_lossy(),
- r,
- reporter_lock.clone(),
- has_error,
- );
-
- Ok(())
- }
- })
- .await?;
- incremental_cache.wait_completion().await;
- reporter_lock.lock().unwrap().close(target_files_len);
-
- Ok(())
- };
- if cli_options.watch_paths().is_some() {
- if lint_options.is_stdin {
+pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
+ if flags.watch.is_some() {
+ if lint_flags.is_stdin() {
return Err(generic_error(
"Lint watch on standard input is not supported.",
));
}
+ let clear_screen = !flags.no_clear_screen;
file_watcher::watch_func(
- resolver,
- operation,
+ flags,
file_watcher::PrintConfig {
job_name: "Lint".to_string(),
- clear_screen: !cli_options.no_clear_screen(),
+ clear_screen,
+ },
+ move |flags, sender, changed_paths| {
+ let lint_flags = lint_flags.clone();
+ Ok(async move {
+ let factory = CliFactory::from_flags(flags).await?;
+ let cli_options = factory.cli_options();
+ let lint_options = cli_options.resolve_lint_options(lint_flags)?;
+ let files =
+ collect_lint_files(&lint_options.files).and_then(|files| {
+ if files.is_empty() {
+ Err(generic_error("No target files found."))
+ } else {
+ Ok(files)
+ }
+ })?;
+ _ = sender.send(files.clone());
+
+ let lint_paths = if let Some(paths) = changed_paths {
+ // lint all files on any changed (https://github.com/denoland/deno/issues/12446)
+ files
+ .iter()
+ .any(|path| paths.contains(path))
+ .then_some(files)
+ .unwrap_or_else(|| [].to_vec())
+ } else {
+ files
+ };
+
+ lint_files(factory, lint_options, lint_paths).await?;
+ Ok(())
+ })
},
)
.await?;
} else {
- if lint_options.is_stdin {
+ let factory = CliFactory::from_flags(flags).await?;
+ let cli_options = factory.cli_options();
+ let is_stdin = lint_flags.is_stdin();
+ let lint_options = cli_options.resolve_lint_options(lint_flags)?;
+ let files = &lint_options.files;
+ let success = if is_stdin {
+ let reporter_kind = lint_options.reporter_kind;
let reporter_lock = Arc::new(Mutex::new(create_reporter(reporter_kind)));
+ let lint_rules = get_config_rules_err_empty(lint_options.rules)?;
let r = lint_stdin(lint_rules);
- handle_lint_result(
- STDIN_FILE_NAME,
- r,
- reporter_lock.clone(),
- has_error.clone(),
- );
+ let success =
+ handle_lint_result(STDIN_FILE_NAME, r, reporter_lock.clone());
reporter_lock.lock().unwrap().close(1);
+ success
} else {
- let target_files = collect_lint_files(&files).and_then(|files| {
+ let target_files = collect_lint_files(files).and_then(|files| {
if files.is_empty() {
Err(generic_error("No target files found."))
} else {
@@ -189,10 +121,9 @@ pub async fn lint(
}
})?;
debug!("Found {} files", target_files.len());
- operation(target_files).await?;
+ lint_files(factory, lint_options, target_files).await?
};
- let has_error = has_error.load(Ordering::Relaxed);
- if has_error {
+ if !success {
std::process::exit(1);
}
}
@@ -200,6 +131,70 @@ pub async fn lint(
Ok(())
}
+async fn lint_files(
+ factory: CliFactory,
+ lint_options: LintOptions,
+ paths: Vec<PathBuf>,
+) -> Result<bool, AnyError> {
+ let caches = factory.caches()?;
+ let lint_rules = get_config_rules_err_empty(lint_options.rules)?;
+ let incremental_cache = Arc::new(IncrementalCache::new(
+ caches.lint_incremental_cache_db(),
+ // use a hash of the rule names in order to bust the cache
+ &{
+ // ensure this is stable by sorting it
+ let mut names = lint_rules.iter().map(|r| r.code()).collect::<Vec<_>>();
+ names.sort_unstable();
+ names
+ },
+ &paths,
+ ));
+ let target_files_len = paths.len();
+ let reporter_kind = lint_options.reporter_kind;
+ let reporter_lock =
+ Arc::new(Mutex::new(create_reporter(reporter_kind.clone())));
+ let has_error = Arc::new(AtomicFlag::default());
+
+ run_parallelized(paths, {
+ let has_error = has_error.clone();
+ let lint_rules = lint_rules.clone();
+ let reporter_lock = reporter_lock.clone();
+ let incremental_cache = incremental_cache.clone();
+ move |file_path| {
+ let file_text = fs::read_to_string(&file_path)?;
+
+ // don't bother rechecking this file if it didn't have any diagnostics before
+ if incremental_cache.is_file_same(&file_path, &file_text) {
+ return Ok(());
+ }
+
+ let r = lint_file(&file_path, file_text, lint_rules);
+ if let Ok((file_diagnostics, file_text)) = &r {
+ if file_diagnostics.is_empty() {
+ // update the incremental cache if there were no diagnostics
+ incremental_cache.update_file(&file_path, file_text)
+ }
+ }
+
+ let success = handle_lint_result(
+ &file_path.to_string_lossy(),
+ r,
+ reporter_lock.clone(),
+ );
+ if !success {
+ has_error.raise();
+ }
+
+ Ok(())
+ }
+ })
+ .await?;
+ incremental_cache.wait_completion().await;
+ reporter_lock.lock().unwrap().close(target_files_len);
+
+ Ok(!has_error.is_raised())
+}
+
fn collect_lint_files(files: &FilesConfig) -> Result<Vec<PathBuf>, AnyError> {
FileCollector::new(is_supported_ext)
.ignore_git_folder()
@@ -286,21 +281,20 @@ fn handle_lint_result(
file_path: &str,
result: Result<(Vec<LintDiagnostic>, String), AnyError>,
reporter_lock: Arc<Mutex<Box<dyn LintReporter + Send>>>,
- has_error: Arc<AtomicBool>,
-) {
+) -> bool {
let mut reporter = reporter_lock.lock().unwrap();
match result {
Ok((mut file_diagnostics, source)) => {
sort_diagnostics(&mut file_diagnostics);
for d in file_diagnostics.iter() {
- has_error.store(true, Ordering::Relaxed);
reporter.visit_diagnostic(d, source.split('\n').collect());
}
+ file_diagnostics.is_empty()
}
Err(err) => {
- has_error.store(true, Ordering::Relaxed);
reporter.visit_error(file_path, &err);
+ false
}
}
}
@@ -534,6 +528,16 @@ fn sort_diagnostics(diagnostics: &mut [LintDiagnostic]) {
});
}
+fn get_config_rules_err_empty(
+ rules: LintRulesConfig,
+) -> Result<Vec<&'static dyn LintRule>, AnyError> {
+ let lint_rules = get_configured_rules(rules);
+ if lint_rules.is_empty() {
+ bail!("No rules have been configured")
+ }
+ Ok(lint_rules)
+}
+
pub fn get_configured_rules(
rules: LintRulesConfig,
) -> Vec<&'static dyn LintRule> {
diff --git a/cli/tools/run.rs b/cli/tools/run.rs
index 4805ea704..cbc9c3eae 100644
--- a/cli/tools/run.rs
+++ b/cli/tools/run.rs
@@ -3,7 +3,6 @@
use std::io::Read;
use deno_ast::MediaType;
-use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_runtime::permissions::Permissions;
use deno_runtime::permissions::PermissionsContainer;
@@ -98,45 +97,42 @@ pub async fn run_from_stdin(flags: Flags) -> Result<i32, AnyError> {
// TODO(bartlomieju): this function is not handling `exit_code` set by the runtime
// code properly.
async fn run_with_watch(flags: Flags) -> Result<i32, AnyError> {
- let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
- let factory = CliFactoryBuilder::new()
- .with_watcher(sender.clone())
- .build_from_flags(flags)
- .await?;
- let file_watcher = factory.file_watcher()?;
- let cli_options = factory.cli_options();
- let clear_screen = !cli_options.no_clear_screen();
- let main_module = cli_options.resolve_main_module()?;
-
- maybe_npm_install(&factory).await?;
-
- let create_cli_main_worker_factory =
- factory.create_cli_main_worker_factory_func().await?;
- let operation = |main_module: ModuleSpecifier| {
- file_watcher.reset();
- let permissions = PermissionsContainer::new(Permissions::from_options(
- &cli_options.permissions_options(),
- )?);
- let create_cli_main_worker_factory = create_cli_main_worker_factory.clone();
-
- Ok(async move {
- let worker = create_cli_main_worker_factory()
- .create_main_worker(main_module, permissions)
- .await?;
- worker.run_for_watcher().await?;
-
- Ok(())
- })
- };
+ let clear_screen = !flags.no_clear_screen;
- util::file_watcher::watch_func2(
- receiver,
- operation,
- main_module,
+ util::file_watcher::watch_func(
+ flags,
util::file_watcher::PrintConfig {
job_name: "Process".to_string(),
clear_screen,
},
+ move |flags, sender, _changed_paths| {
+ Ok(async move {
+ let factory = CliFactoryBuilder::new()
+ .with_watcher(sender.clone())
+ .build_from_flags(flags)
+ .await?;
+ let cli_options = factory.cli_options();
+ let main_module = cli_options.resolve_main_module()?;
+
+ maybe_npm_install(&factory).await?;
+
+ if let Some(watch_paths) = cli_options.watch_paths() {
+ let _ = sender.send(watch_paths);
+ }
+
+ let permissions = PermissionsContainer::new(Permissions::from_options(
+ &cli_options.permissions_options(),
+ )?);
+ let worker = factory
+ .create_cli_main_worker_factory()
+ .await?
+ .create_main_worker(main_module, permissions)
+ .await?;
+ worker.run_for_watcher().await?;
+
+ Ok(())
+ })
+ },
)
.await?;
diff --git a/cli/tools/test.rs b/cli/tools/test.rs
index 6f32d69e4..159de8ec8 100644
--- a/cli/tools/test.rs
+++ b/cli/tools/test.rs
@@ -2,18 +2,20 @@
use crate::args::CliOptions;
use crate::args::FilesConfig;
-use crate::args::TestOptions;
+use crate::args::Flags;
+use crate::args::TestFlags;
use crate::colors;
use crate::display;
use crate::factory::CliFactory;
+use crate::factory::CliFactoryBuilder;
use crate::file_fetcher::File;
use crate::file_fetcher::FileFetcher;
use crate::graph_util::graph_valid_with_cli_options;
+use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::module_loader::ModuleLoadPreparer;
use crate::ops;
use crate::util::checksum;
use crate::util::file_watcher;
-use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers;
use crate::util::path::get_extension;
use crate::util::path::is_supported_ext;
@@ -62,7 +64,6 @@ use std::io::Read;
use std::io::Write;
use std::num::NonZeroUsize;
use std::path::Path;
-use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
@@ -1641,11 +1642,12 @@ async fn fetch_specifiers_with_test_mode(
}
pub async fn run_tests(
- cli_options: CliOptions,
- test_options: TestOptions,
+ flags: Flags,
+ test_flags: TestFlags,
) -> Result<(), AnyError> {
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
+ let factory = CliFactory::from_flags(flags).await?;
let cli_options = factory.cli_options();
+ let test_options = cli_options.resolve_test_options(test_flags)?;
let file_fetcher = factory.file_fetcher()?;
let module_load_preparer = factory.module_load_preparer().await?;
// Various test files should not share the same permissions in terms of
@@ -1708,186 +1710,9 @@ pub async fn run_tests(
}
pub async fn run_tests_with_watch(
- cli_options: CliOptions,
- test_options: TestOptions,
+ flags: Flags,
+ test_flags: TestFlags,
) -> Result<(), AnyError> {
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
- let cli_options = factory.cli_options();
- let module_graph_builder = factory.module_graph_builder().await?;
- let module_load_preparer = factory.module_load_preparer().await?;
- let file_fetcher = factory.file_fetcher()?;
- let file_watcher = factory.file_watcher()?;
- // Various test files should not share the same permissions in terms of
- // `PermissionsContainer` - otherwise granting/revoking permissions in one
- // file would have impact on other files, which is undesirable.
- let permissions =
- Permissions::from_options(&cli_options.permissions_options())?;
- let graph_kind = cli_options.type_check_mode().as_graph_kind();
- let log_level = cli_options.log_level();
-
- let resolver = |changed: Option<Vec<PathBuf>>| {
- let paths_to_watch = test_options.files.include.clone();
- let paths_to_watch_clone = paths_to_watch.clone();
- let files_changed = changed.is_some();
- let test_options = &test_options;
- let cli_options = cli_options.clone();
- let module_graph_builder = module_graph_builder.clone();
-
- async move {
- let test_modules = if test_options.doc {
- collect_specifiers(&test_options.files, is_supported_test_ext)
- } else {
- collect_specifiers(&test_options.files, is_supported_test_path)
- }?;
-
- let mut paths_to_watch = paths_to_watch_clone;
- let mut modules_to_reload = if files_changed {
- Vec::new()
- } else {
- test_modules.clone()
- };
- let graph = module_graph_builder
- .create_graph(graph_kind, test_modules.clone())
- .await?;
- graph_valid_with_cli_options(&graph, &test_modules, &cli_options)?;
-
- // TODO(@kitsonk) - This should be totally derivable from the graph.
- for specifier in test_modules {
- fn get_dependencies<'a>(
- graph: &'a deno_graph::ModuleGraph,
- maybe_module: Option<&'a deno_graph::Module>,
- // This needs to be accessible to skip getting dependencies if they're already there,
- // otherwise this will cause a stack overflow with circular dependencies
- output: &mut HashSet<&'a ModuleSpecifier>,
- ) {
- if let Some(module) = maybe_module.and_then(|m| m.esm()) {
- for dep in module.dependencies.values() {
- if let Some(specifier) = &dep.get_code() {
- if !output.contains(specifier) {
- output.insert(specifier);
- get_dependencies(graph, graph.get(specifier), output);
- }
- }
- if let Some(specifier) = &dep.get_type() {
- if !output.contains(specifier) {
- output.insert(specifier);
- get_dependencies(graph, graph.get(specifier), output);
- }
- }
- }
- }
- }
-
- // This test module and all it's dependencies
- let mut modules = HashSet::new();
- modules.insert(&specifier);
- get_dependencies(&graph, graph.get(&specifier), &mut modules);
-
- paths_to_watch.extend(
- modules
- .iter()
- .filter_map(|specifier| specifier.to_file_path().ok()),
- );
-
- if let Some(changed) = &changed {
- for path in changed
- .iter()
- .filter_map(|path| ModuleSpecifier::from_file_path(path).ok())
- {
- if modules.contains(&path) {
- modules_to_reload.push(specifier);
- break;
- }
- }
- }
- }
-
- Ok((paths_to_watch, modules_to_reload))
- }
- .map(move |result| {
- if files_changed
- && matches!(result, Ok((_, ref modules)) if modules.is_empty())
- {
- ResolutionResult::Ignore
- } else {
- match result {
- Ok((paths_to_watch, modules_to_reload)) => {
- ResolutionResult::Restart {
- paths_to_watch,
- result: Ok(modules_to_reload),
- }
- }
- Err(e) => ResolutionResult::Restart {
- paths_to_watch,
- result: Err(e),
- },
- }
- }
- })
- };
-
- let create_cli_main_worker_factory =
- factory.create_cli_main_worker_factory_func().await?;
- let operation = |modules_to_reload: Vec<ModuleSpecifier>| {
- let permissions = &permissions;
- let test_options = &test_options;
- file_watcher.reset();
- let cli_options = cli_options.clone();
- let file_fetcher = file_fetcher.clone();
- let module_load_preparer = module_load_preparer.clone();
- let create_cli_main_worker_factory = create_cli_main_worker_factory.clone();
-
- async move {
- let worker_factory = Arc::new(create_cli_main_worker_factory());
- let specifiers_with_mode = fetch_specifiers_with_test_mode(
- &file_fetcher,
- &test_options.files,
- &test_options.doc,
- )
- .await?
- .into_iter()
- .filter(|(specifier, _)| modules_to_reload.contains(specifier))
- .collect::<Vec<(ModuleSpecifier, TestMode)>>();
-
- check_specifiers(
- &cli_options,
- &file_fetcher,
- &module_load_preparer,
- specifiers_with_mode.clone(),
- )
- .await?;
-
- if test_options.no_run {
- return Ok(());
- }
-
- test_specifiers(
- worker_factory,
- permissions,
- specifiers_with_mode
- .into_iter()
- .filter_map(|(s, m)| match m {
- TestMode::Documentation => None,
- _ => Some(s),
- })
- .collect(),
- TestSpecifiersOptions {
- concurrent_jobs: test_options.concurrent_jobs,
- fail_fast: test_options.fail_fast,
- log_level,
- specifier: TestSpecifierOptions {
- filter: TestFilter::from_flag(&test_options.filter),
- shuffle: test_options.shuffle,
- trace_ops: test_options.trace_ops,
- },
- },
- )
- .await?;
-
- Ok(())
- }
- };
-
// On top of the sigint handlers which are added and unbound for each test
// run, a process-scoped basic exit handler is required due to a tokio
// limitation where it doesn't unbind its own handler for the entire process
@@ -1901,14 +1726,118 @@ pub async fn run_tests_with_watch(
}
});
- let clear_screen = !cli_options.no_clear_screen();
+ let clear_screen = !flags.no_clear_screen;
file_watcher::watch_func(
- resolver,
- operation,
+ flags,
file_watcher::PrintConfig {
job_name: "Test".to_string(),
clear_screen,
},
+ move |flags, sender, changed_paths| {
+ let test_flags = test_flags.clone();
+ Ok(async move {
+ let factory = CliFactoryBuilder::new()
+ .with_watcher(sender.clone())
+ .build_from_flags(flags)
+ .await?;
+ let cli_options = factory.cli_options();
+ let test_options = cli_options.resolve_test_options(test_flags)?;
+
+ if let Some(watch_paths) = cli_options.watch_paths() {
+ let _ = sender.send(watch_paths);
+ }
+ let _ = sender.send(test_options.files.include.clone());
+
+ let graph_kind = cli_options.type_check_mode().as_graph_kind();
+ let log_level = cli_options.log_level();
+ let cli_options = cli_options.clone();
+ let module_graph_builder = factory.module_graph_builder().await?;
+ let file_fetcher = factory.file_fetcher()?;
+ let test_modules = if test_options.doc {
+ collect_specifiers(&test_options.files, is_supported_test_ext)
+ } else {
+ collect_specifiers(&test_options.files, is_supported_test_path)
+ }?;
+ let permissions =
+ Permissions::from_options(&cli_options.permissions_options())?;
+
+ let graph = module_graph_builder
+ .create_graph(graph_kind, test_modules.clone())
+ .await?;
+ graph_valid_with_cli_options(&graph, &test_modules, &cli_options)?;
+
+ let test_modules_to_reload = if let Some(changed_paths) = changed_paths
+ {
+ let changed_specifiers = changed_paths
+ .into_iter()
+ .filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
+ .collect::<HashSet<_>>();
+ let mut result = Vec::new();
+ for test_module_specifier in test_modules {
+ if has_graph_root_local_dependent_changed(
+ &graph,
+ &test_module_specifier,
+ &changed_specifiers,
+ ) {
+ result.push(test_module_specifier.clone());
+ }
+ }
+ result
+ } else {
+ test_modules.clone()
+ };
+
+ let worker_factory =
+ Arc::new(factory.create_cli_main_worker_factory().await?);
+ let module_load_preparer = factory.module_load_preparer().await?;
+ let specifiers_with_mode = fetch_specifiers_with_test_mode(
+ file_fetcher,
+ &test_options.files,
+ &test_options.doc,
+ )
+ .await?
+ .into_iter()
+ .filter(|(specifier, _)| test_modules_to_reload.contains(specifier))
+ .collect::<Vec<(ModuleSpecifier, TestMode)>>();
+
+ check_specifiers(
+ &cli_options,
+ file_fetcher,
+ module_load_preparer,
+ specifiers_with_mode.clone(),
+ )
+ .await?;
+
+ if test_options.no_run {
+ return Ok(());
+ }
+
+ test_specifiers(
+ worker_factory,
+ &permissions,
+ specifiers_with_mode
+ .into_iter()
+ .filter_map(|(s, m)| match m {
+ TestMode::Documentation => None,
+ _ => Some(s),
+ })
+ .collect(),
+ TestSpecifiersOptions {
+ concurrent_jobs: test_options.concurrent_jobs,
+ fail_fast: test_options.fail_fast,
+ log_level,
+ specifier: TestSpecifierOptions {
+ filter: TestFilter::from_flag(&test_options.filter),
+ shuffle: test_options.shuffle,
+ trace_ops: test_options.trace_ops,
+ },
+ },
+ )
+ .await?;
+
+ Ok(())
+ })
+ },
)
.await?;