summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/args/flags.rs68
-rw-r--r--cli/factory.rs2
-rw-r--r--cli/main.rs3
-rw-r--r--cli/tools/registry/mod.rs1
-rw-r--r--cli/tools/registry/pm.rs85
-rw-r--r--tests/specs/add/dist_tag/__test__.jsonc2
-rw-r--r--tests/specs/add/dist_tag/add.out15
-rw-r--r--tests/specs/remove/basic/__test__.jsonc16
-rw-r--r--tests/specs/remove/basic/add.out12
-rw-r--r--tests/specs/remove/basic/add_lock.out24
-rw-r--r--tests/specs/remove/basic/remove_lock.out4
-rw-r--r--tests/specs/remove/basic/rm.out2
12 files changed, 229 insertions, 5 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index c6bb90430..b9908f413 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -84,6 +84,11 @@ pub struct AddFlags {
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
+pub struct RemoveFlags {
+ pub packages: Vec<String>,
+}
+
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct BenchFlags {
pub files: FileFlags,
pub filter: Option<String>,
@@ -428,6 +433,7 @@ pub struct HelpFlags {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DenoSubcommand {
Add(AddFlags),
+ Remove(RemoveFlags),
Bench(BenchFlags),
Bundle(BundleFlags),
Cache(CacheFlags),
@@ -1216,6 +1222,7 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
if let Some((subcommand, mut m)) = matches.remove_subcommand() {
match subcommand.as_str() {
"add" => add_parse(&mut flags, &mut m),
+ "remove" => remove_parse(&mut flags, &mut m),
"bench" => bench_parse(&mut flags, &mut m),
"bundle" => bundle_parse(&mut flags, &mut m),
"cache" => cache_parse(&mut flags, &mut m),
@@ -1442,6 +1449,7 @@ pub fn clap_root() -> Command {
.defer(|cmd| {
let cmd = cmd
.subcommand(add_subcommand())
+ .subcommand(remove_subcommand())
.subcommand(bench_subcommand())
.subcommand(bundle_subcommand())
.subcommand(cache_subcommand())
@@ -1515,6 +1523,31 @@ You can add multiple dependencies at once:
})
}
+fn remove_subcommand() -> Command {
+ Command::new("remove")
+ .alias("rm")
+ .about("Remove dependencies")
+ .long_about(
+ "Remove dependencies from the configuration file.
+
+ deno remove @std/path
+
+You can remove multiple dependencies at once:
+
+ deno remove @std/path @std/assert
+",
+ )
+ .defer(|cmd| {
+ cmd.arg(
+ Arg::new("packages")
+ .help("List of packages to remove")
+ .required(true)
+ .num_args(1..)
+ .action(ArgAction::Append),
+ )
+ })
+}
+
fn bench_subcommand() -> Command {
Command::new("bench")
.about(
@@ -3726,6 +3759,12 @@ fn add_parse_inner(
AddFlags { packages }
}
+fn remove_parse(flags: &mut Flags, matches: &mut ArgMatches) {
+ flags.subcommand = DenoSubcommand::Remove(RemoveFlags {
+ packages: matches.remove_many::<String>("packages").unwrap().collect(),
+ });
+}
+
fn bench_parse(flags: &mut Flags, matches: &mut ArgMatches) {
flags.type_check_mode = TypeCheckMode::Local;
@@ -10248,6 +10287,35 @@ mod tests {
}
#[test]
+ fn remove_subcommand() {
+ let r = flags_from_vec(svec!["deno", "remove"]);
+ r.unwrap_err();
+
+ let r = flags_from_vec(svec!["deno", "remove", "@david/which"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Remove(RemoveFlags {
+ packages: svec!["@david/which"],
+ }),
+ ..Flags::default()
+ }
+ );
+
+ let r =
+ flags_from_vec(svec!["deno", "remove", "@david/which", "@luca/hello"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Remove(RemoveFlags {
+ packages: svec!["@david/which", "@luca/hello"],
+ }),
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
fn run_with_frozen_lockfile() {
let cases = [
(Some("--frozen"), true),
diff --git a/cli/factory.rs b/cli/factory.rs
index ed288b22f..942aefd25 100644
--- a/cli/factory.rs
+++ b/cli/factory.rs
@@ -355,7 +355,7 @@ impl CliFactory {
let fs = self.fs();
let cli_options = self.cli_options()?;
// For `deno install` we want to force the managed resolver so it can set up `node_modules/` directory.
- create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Add(_)) {
+ create_cli_npm_resolver(if cli_options.use_byonm() && !matches!(cli_options.sub_command(), DenoSubcommand::Install(_) | DenoSubcommand::Add(_) | DenoSubcommand::Remove(_)) {
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
fs: fs.clone(),
root_node_modules_dir: Some(match cli_options.node_modules_dir_path() {
diff --git a/cli/main.rs b/cli/main.rs
index 4955b79d0..1b2640758 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -100,6 +100,9 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
tools::registry::add(flags, add_flags, tools::registry::AddCommandName::Add).await
}),
+ DenoSubcommand::Remove(remove_flags) => spawn_subcommand(async {
+ tools::registry::remove(flags, remove_flags).await
+ }),
DenoSubcommand::Bench(bench_flags) => spawn_subcommand(async {
if bench_flags.watch.is_some() {
tools::bench::run_benchmarks_with_watch(flags, bench_flags).await
diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs
index b3bed7721..34e803c73 100644
--- a/cli/tools/registry/mod.rs
+++ b/cli/tools/registry/mod.rs
@@ -64,6 +64,7 @@ mod unfurl;
use auth::get_auth_method;
use auth::AuthMethod;
pub use pm::add;
+pub use pm::remove;
pub use pm::AddCommandName;
use publish_order::PublishOrderGraph;
use unfurl::SpecifierUnfurler;
diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs
index 86596df9d..90238b890 100644
--- a/cli/tools/registry/pm.rs
+++ b/cli/tools/registry/pm.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::borrow::Cow;
+use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
@@ -23,6 +24,7 @@ use jsonc_parser::ast::Value;
use crate::args::AddFlags;
use crate::args::CacheSetting;
use crate::args::Flags;
+use crate::args::RemoveFlags;
use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher;
use crate::jsr::JsrFetchResolver;
@@ -337,9 +339,7 @@ pub async fn add(
// make a new CliFactory to pick up the updated config file
let cli_factory = CliFactory::from_flags(flags);
// cache deps
- if cli_factory.cli_options()?.enable_future_features() {
- crate::module_loader::load_top_level_deps(&cli_factory).await?;
- }
+ crate::module_loader::load_top_level_deps(&cli_factory).await?;
Ok(())
}
@@ -513,6 +513,85 @@ fn generate_imports(packages_to_version: Vec<(String, String)>) -> String {
contents.join("\n")
}
+fn remove_from_config(
+ config_path: &Path,
+ keys: &[&'static str],
+ packages_to_remove: &[String],
+ removed_packages: &mut Vec<String>,
+ fmt_options: &FmtOptionsConfig,
+) -> Result<(), AnyError> {
+ let mut json: serde_json::Value =
+ serde_json::from_slice(&std::fs::read(config_path)?)?;
+ for key in keys {
+ let Some(obj) = json.get_mut(*key).and_then(|v| v.as_object_mut()) else {
+ continue;
+ };
+ for package in packages_to_remove {
+ if obj.shift_remove(package).is_some() {
+ removed_packages.push(package.clone());
+ }
+ }
+ }
+
+ let config = serde_json::to_string_pretty(&json)?;
+ let config =
+ crate::tools::fmt::format_json(config_path, &config, fmt_options)
+ .ok()
+ .flatten()
+ .unwrap_or(config);
+
+ std::fs::write(config_path, config)
+ .context("Failed to update configuration file")?;
+
+ Ok(())
+}
+
+pub async fn remove(
+ flags: Arc<Flags>,
+ remove_flags: RemoveFlags,
+) -> Result<(), AnyError> {
+ let (config_file, factory) = DenoOrPackageJson::from_flags(flags.clone())?;
+ let options = factory.cli_options()?;
+ let start_dir = &options.start_dir;
+ let fmt_config_options = config_file.fmt_options();
+
+ let mut removed_packages = Vec::new();
+
+ if let Some(deno_json) = start_dir.maybe_deno_json() {
+ remove_from_config(
+ &deno_json.specifier.to_file_path().unwrap(),
+ &["imports"],
+ &remove_flags.packages,
+ &mut removed_packages,
+ &fmt_config_options,
+ )?;
+ }
+
+ if let Some(pkg_json) = start_dir.maybe_pkg_json() {
+ remove_from_config(
+ &pkg_json.path,
+ &["dependencies", "devDependencies"],
+ &remove_flags.packages,
+ &mut removed_packages,
+ &fmt_config_options,
+ )?;
+ }
+
+ if removed_packages.is_empty() {
+ log::info!("No packages were removed");
+ } else {
+ for package in &removed_packages {
+ log::info!("Removed {}", crate::colors::green(package));
+ }
+ // Update deno.lock
+ node_resolver::PackageJsonThreadLocalCache::clear();
+ let cli_factory = CliFactory::from_flags(flags);
+ crate::module_loader::load_top_level_deps(&cli_factory).await?;
+ }
+
+ Ok(())
+}
+
fn update_config_file_content(
obj: jsonc_parser::ast::Object,
config_file_contents: &str,
diff --git a/tests/specs/add/dist_tag/__test__.jsonc b/tests/specs/add/dist_tag/__test__.jsonc
index ac8a65654..93104966d 100644
--- a/tests/specs/add/dist_tag/__test__.jsonc
+++ b/tests/specs/add/dist_tag/__test__.jsonc
@@ -3,7 +3,7 @@
"steps": [
{
"args": "add npm:ajv@latest",
- "output": "Add npm:ajv@8.11.0\n"
+ "output": "add.out"
}
]
}
diff --git a/tests/specs/add/dist_tag/add.out b/tests/specs/add/dist_tag/add.out
new file mode 100644
index 000000000..928eb6d6c
--- /dev/null
+++ b/tests/specs/add/dist_tag/add.out
@@ -0,0 +1,15 @@
+Add npm:ajv@8.11.0
+[UNORDERED_START]
+Download http://localhost:4260/ajv
+Download http://localhost:4260/fast-deep-equal
+Download http://localhost:4260/json-schema-traverse
+Download http://localhost:4260/require-from-string
+Download http://localhost:4260/uri-js
+Download http://localhost:4260/punycode
+Download http://localhost:4260/ajv/ajv-8.11.0.tgz
+Download http://localhost:4260/require-from-string/require-from-string-2.0.2.tgz
+Download http://localhost:4260/uri-js/uri-js-4.4.1.tgz
+Download http://localhost:4260/fast-deep-equal/fast-deep-equal-3.1.3.tgz
+Download http://localhost:4260/json-schema-traverse/json-schema-traverse-1.0.0.tgz
+Download http://localhost:4260/punycode/punycode-2.1.1.tgz
+[UNORDERED_END]
diff --git a/tests/specs/remove/basic/__test__.jsonc b/tests/specs/remove/basic/__test__.jsonc
new file mode 100644
index 000000000..2f4d82c88
--- /dev/null
+++ b/tests/specs/remove/basic/__test__.jsonc
@@ -0,0 +1,16 @@
+{
+ "tempDir": true,
+ "steps": [{
+ "args": ["add", "@std/assert", "@std/http"],
+ "output": "add.out"
+ }, {
+ "args": ["eval", "console.log(Deno.readTextFileSync('deno.lock').trim())"],
+ "output": "add_lock.out"
+ }, {
+ "args": ["remove", "@std/assert", "@std/http"],
+ "output": "rm.out"
+ }, {
+ "args": ["eval", "console.log(Deno.readTextFileSync('deno.lock').trim())"],
+ "output": "remove_lock.out"
+ }]
+}
diff --git a/tests/specs/remove/basic/add.out b/tests/specs/remove/basic/add.out
new file mode 100644
index 000000000..a93b0ab52
--- /dev/null
+++ b/tests/specs/remove/basic/add.out
@@ -0,0 +1,12 @@
+Created deno.json configuration file.
+Add jsr:@std/assert@1.0.0
+Add jsr:@std/http@1.0.0
+[UNORDERED_START]
+Download http://127.0.0.1:4250/@std/http/1.0.0_meta.json
+Download http://127.0.0.1:4250/@std/assert/1.0.0_meta.json
+Download http://127.0.0.1:4250/@std/http/1.0.0/mod.ts
+Download http://127.0.0.1:4250/@std/assert/1.0.0/mod.ts
+Download http://127.0.0.1:4250/@std/assert/1.0.0/assert_equals.ts
+Download http://127.0.0.1:4250/@std/assert/1.0.0/assert.ts
+Download http://127.0.0.1:4250/@std/assert/1.0.0/fail.ts
+[UNORDERED_END]
diff --git a/tests/specs/remove/basic/add_lock.out b/tests/specs/remove/basic/add_lock.out
new file mode 100644
index 000000000..a5a45e854
--- /dev/null
+++ b/tests/specs/remove/basic/add_lock.out
@@ -0,0 +1,24 @@
+{
+ "version": "3",
+ "packages": {
+ "specifiers": {
+ "jsr:@std/assert@^1.0.0": "jsr:@std/assert@1.0.0",
+ "jsr:@std/http@^1.0.0": "jsr:@std/http@1.0.0"
+ },
+ "jsr": {
+ "@std/assert@1.0.0": {
+ "integrity": "7ae268c58de9693b4997fd93d9b303a47df336664e2008378ccb93c3458d092a"
+ },
+ "@std/http@1.0.0": {
+ "integrity": "d75bd303c21123a9b58f7249e38b4c0aa3a09f7d76b13f9d7e7842d89052091a"
+ }
+ }
+ },
+ "remote": {},
+ "workspace": {
+ "dependencies": [
+ "jsr:@std/assert@^1.0.0",
+ "jsr:@std/http@^1.0.0"
+ ]
+ }
+}
diff --git a/tests/specs/remove/basic/remove_lock.out b/tests/specs/remove/basic/remove_lock.out
new file mode 100644
index 000000000..37f10ce95
--- /dev/null
+++ b/tests/specs/remove/basic/remove_lock.out
@@ -0,0 +1,4 @@
+{
+ "version": "3",
+ "remote": {}
+}
diff --git a/tests/specs/remove/basic/rm.out b/tests/specs/remove/basic/rm.out
new file mode 100644
index 000000000..083ab8c05
--- /dev/null
+++ b/tests/specs/remove/basic/rm.out
@@ -0,0 +1,2 @@
+Removed @std/assert
+Removed @std/http