From ad25fe98a444713040608a933560aea91df78e9e Mon Sep 17 00:00:00 2001
From: eitsupi <ts1s1andn@gmail.com>
Date: Tue, 8 Oct 2024 13:12:11 +0000
Subject: [PATCH] Support `suggests` field of standalone file

---
 R/use_standalone.R                      | 36 ++++++++++++++-------
 tests/testthat/_snaps/use_standalone.md | 33 ++++++++++++++-----
 tests/testthat/test-use_standalone.R    | 42 ++++++++++++++++++-------
 3 files changed, 81 insertions(+), 30 deletions(-)

diff --git a/R/use_standalone.R b/R/use_standalone.R
index 11ca47e12..cb2ef0cce 100644
--- a/R/use_standalone.R
+++ b/R/use_standalone.R
@@ -38,6 +38,9 @@
 #'    [use_package()] to ensure they are included in the `Imports:`
 #'    field of the `DESCRIPTION` file.
 #'
+#' - `suggests`: Similar to `imports`, but the packages are added to the
+#'   `Suggests:` field of the `DESCRIPTION` file.
+#'
 #' Note that lists are specified with standard YAML syntax, using
 #' square brackets, for example: `imports: [rlang (>= 1.0.0), purrr]`.
 #'
@@ -84,20 +87,27 @@ use_standalone <- function(repo_spec, file = NULL, ref = NULL, host = NULL) {
   }
 
   imports <- dependencies$imports
-
-  for (i in seq_len(nrow(imports))) {
-    import <- imports[i, , drop = FALSE]
-
-    if (is.na(import$ver)) {
-      ver <- NULL
-    } else {
-      ver <- import$ver
+  suggests <- dependencies$suggests
+
+  add_fields <- function(x, type = c("Imports", "Suggests")) {
+    type <- arg_match(type)
+
+    for (i in seq_len(nrow(x))) {
+      pkgs <- x[i, , drop = FALSE]
+      if (is.na(pkgs$ver)) {
+        ver <- NULL
+      } else {
+        ver <- pkgs$ver
+      }
+      ui_silence(
+        use_package(pkgs$pkg, min_version = ver, type = type)
+      )
     }
-    ui_silence(
-      use_package(import$pkg, min_version = ver)
-    )
   }
 
+  add_fields(imports, "Imports")
+  add_fields(suggests, "Suggests")
+
   invisible()
 }
 
@@ -206,6 +216,8 @@ standalone_dependencies <- function(lines, path, error_call = caller_env()) {
   deps <- as_chr_field(yaml$dependencies)
   imports <- as_chr_field(yaml$imports)
   imports <- as_version_info(imports, error_call = error_call)
+  suggests <- as_chr_field(yaml$suggests)
+  suggests <- as_version_info(suggests, error_call = error_call)
 
   if (any(stats::na.omit(imports$cmp) != ">=")) {
     cli::cli_abort(
@@ -214,7 +226,7 @@ standalone_dependencies <- function(lines, path, error_call = caller_env()) {
     )
   }
 
-  list(deps = deps, imports = imports)
+  list(deps = deps, imports = imports, suggests = suggests)
 }
 
 as_version_info <- function(fields, error_call = caller_env()) {
diff --git a/tests/testthat/_snaps/use_standalone.md b/tests/testthat/_snaps/use_standalone.md
index 1b1a447b6..3e08e7ab8 100644
--- a/tests/testthat/_snaps/use_standalone.md
+++ b/tests/testthat/_snaps/use_standalone.md
@@ -78,23 +78,42 @@
       ! `file` is absent, but must be supplied.
       i Possible options are cli, downstream-deps, lazyeval, lifecycle, linked-version, obj-type, purrr, rlang, s3-register, sizes, types-check, vctrs, or zeallot.
 
-# can extract imports
+# can extract imports/suggests
 
     Code
-      extract_imports("# imports: rlang (== 1.0.0)")
+      extract_pkgs("# imports: rlang (== 1.0.0)", "imports")
     Condition
-      Error in `extract_imports()`:
+      Error in `extract_pkgs()`:
       ! Version specification must use `>=`.
     Code
-      extract_imports("# imports: rlang (>= 1.0.0), purrr")
+      extract_pkgs("# suggests: rlang (== 1.0.0)", "suggests")
+    Output
+      # A data frame: 1 x 3
+        pkg   cmp   ver  
+        <chr> <chr> <chr>
+      1 rlang ==    1.0.0
+    Code
+      extract_pkgs("# imports: rlang (>= 1.0.0), purrr", "imports")
+    Condition
+      Error in `extract_pkgs()`:
+      ! Version field can't contain comma.
+      i Do you need to wrap in a list?
+    Code
+      extract_pkgs("# suggests: rlang (>= 1.0.0), purrr", "suggests")
     Condition
-      Error in `extract_imports()`:
+      Error in `extract_pkgs()`:
       ! Version field can't contain comma.
       i Do you need to wrap in a list?
     Code
-      extract_imports("# imports: foo (>=0.0.0)")
+      extract_pkgs("# imports: foo (>=0.0.0)", "imports")
+    Condition
+      Error in `extract_pkgs()`:
+      ! Can't parse version `foo (>=0.0.0)` in `imports:` field.
+      i Example of expected version format: `rlang (>= 1.0.0)`.
+    Code
+      extract_pkgs("# suggests: foo (>=0.0.0)", "suggests")
     Condition
-      Error in `extract_imports()`:
+      Error in `extract_pkgs()`:
       ! Can't parse version `foo (>=0.0.0)` in `imports:` field.
       i Example of expected version format: `rlang (>= 1.0.0)`.
 
diff --git a/tests/testthat/test-use_standalone.R b/tests/testthat/test-use_standalone.R
index 41d9337e7..09b958755 100644
--- a/tests/testthat/test-use_standalone.R
+++ b/tests/testthat/test-use_standalone.R
@@ -82,40 +82,60 @@ test_that("can extract dependencies", {
   expect_equal(extract_deps("# dependencies: [a, b]"), c("a", "b"))
 })
 
-test_that("can extract imports", {
-  extract_imports <- function(imports) {
+test_that("can extract imports/suggests", {
+  extract_pkgs <- function(pkgs, type = c("imports", "suggests")) {
+    type <- arg_match(type)
     out <- standalone_dependencies(
-      c("# ---", imports, "# ---"),
+      c("# ---", pkgs, "# ---"),
       "test.R",
       error_call = current_env()
     )
-    out$imports
+    out[[type]]
   }
 
   expect_equal(
-    extract_imports(NULL),
+    extract_pkgs(NULL, "imports"),
+    version_info_df()
+  )
+  expect_equal(
+    extract_pkgs(NULL, "suggests"),
     version_info_df()
   )
 
   expect_equal(
-    extract_imports("# imports: rlang"),
+    extract_pkgs("# imports: rlang", "imports"),
+    version_info_df("rlang", NA, NA)
+  )
+  expect_equal(
+    extract_pkgs("# suggests: rlang", "suggests"),
     version_info_df("rlang", NA, NA)
   )
 
   expect_equal(
-    extract_imports("# imports: rlang (>= 1.0.0)"),
+    extract_pkgs("# imports: rlang (>= 1.0.0)", "imports"),
+    version_info_df("rlang", ">=", "1.0.0")
+  )
+  expect_equal(
+    extract_pkgs("# suggests: rlang (>= 1.0.0)", "suggests"),
     version_info_df("rlang", ">=", "1.0.0")
   )
 
   expect_equal(
-    extract_imports("# imports: [rlang (>= 1.0.0), purrr]"),
+    extract_pkgs("# imports: [rlang (>= 1.0.0), purrr]", "imports"),
+    version_info_df(c("rlang", "purrr"), c(">=", NA), c("1.0.0", NA))
+  )
+  expect_equal(
+    extract_pkgs("# suggests: [rlang (>= 1.0.0), purrr]", "suggests"),
     version_info_df(c("rlang", "purrr"), c(">=", NA), c("1.0.0", NA))
   )
 
   expect_snapshot(error = TRUE, {
-    extract_imports("# imports: rlang (== 1.0.0)")
-    extract_imports("# imports: rlang (>= 1.0.0), purrr")
-    extract_imports("# imports: foo (>=0.0.0)")
+    extract_pkgs("# imports: rlang (== 1.0.0)", "imports")
+    extract_pkgs("# suggests: rlang (== 1.0.0)", "suggests")
+    extract_pkgs("# imports: rlang (>= 1.0.0), purrr", "imports")
+    extract_pkgs("# suggests: rlang (>= 1.0.0), purrr", "suggests")
+    extract_pkgs("# imports: foo (>=0.0.0)", "imports")
+    extract_pkgs("# suggests: foo (>=0.0.0)", "suggests")
   })
 })