diff --git a/R/linter_box_universal_import_linter.R b/R/linter_box_universal_import_linter.R index e0c04555..e776eff7 100644 --- a/R/linter_box_universal_import_linter.R +++ b/R/linter_box_universal_import_linter.R @@ -2,6 +2,8 @@ #' #' Checks that all function imports are explicit. `package[...]` is not used. #' +#' @param exclude Exclude package names. Defaults are `shiny` and `testthat`. +#' #' @examples #' # will produce lints #' lintr::lint( @@ -26,15 +28,34 @@ #' ) #' #' @export -box_universal_import_linter <- function() { +box_universal_import_linter <- function(exclude = c("shiny", "testthat")) { lint_message <- "Explicitly declare imports rather than universally import with `...`." - xpath <- " - //SYMBOL_PACKAGE[(text() = 'box' and following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use'])] - /parent::expr - /parent::expr - //SYMBOL[text() = '...'] - " + xpath_exclude_packages <- NULL + + if (!is.null(exclude)) { + exclude_packages <- glue::glue_collapse( + glue::glue("text() != '{exclude}'"), + sep = " and " + ) + + xpath_exclude_packages <- glue::glue("parent::expr + /preceding-sibling::expr[SYMBOL[{exclude_packages}]]") + } + + xpath_symbol_selector <- glue::glue_collapse( + c("text() = '...'", + xpath_exclude_packages), + sep = " and " + ) + + xpath <- glue::glue(" + //SYMBOL_PACKAGE[(text() = 'box' and + following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use'])] + /parent::expr + /parent::expr + //SYMBOL[{xpath_symbol_selector}] + ") lintr::Linter(function(source_expression) { if (!lintr::is_lint_level(source_expression, "file")) { diff --git a/tests/testthat/test-linter_box_universal_import_linter.R b/tests/testthat/test-linter_box_universal_import_linter.R index 06b30f4d..e47e7cd4 100644 --- a/tests/testthat/test-linter_box_universal_import_linter.R +++ b/tests/testthat/test-linter_box_universal_import_linter.R @@ -1,6 +1,8 @@ good_package_imports <- "box::use( dplyr[select, mutate, ], + shiny[...], stringr[str_sub, str_match, ], + testthat[...], ) " @@ -28,7 +30,7 @@ function_with_three_dots <- "some_function <- function(...) { " no_lint <- "box::use( - shiny[...], # nolint + dplyr[...], # nolint ) " @@ -69,3 +71,26 @@ test_that("box_universal_count_linter respects #nolint", { lintr::expect_lint(no_lint, NULL, linter) }) + +test_that("box_universal_count_linter excludes can be modified", { + linter <- box_universal_import_linter(exclude = c("dplyr")) + + lintr::expect_lint(bad_package_imports, NULL, linter) + lintr::expect_lint(good_package_imports, + list( + list(message = lint_msg), + list(message = lint_msg) + ), + linter) +}) + +test_that("box_universal_count_linter excludes can be NULL", { + linter <- box_universal_import_linter(exclude = NULL) + + lintr::expect_lint(good_package_imports, + list( + list(message = lint_msg), + list(message = lint_msg) + ), + linter) +})