-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lintr >= 3.0.0 support #180
base: main
Are you sure you want to change the base?
Changes from all commits
a8eae7c
aa0f502
5e597ab
c51f3a8
d159e39
c027273
6541e39
10f1d7b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
.idea | ||
.Rproj.user | ||
inst/doc | ||
docs |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
Package: lifecycle | ||
Title: Manage the Life Cycle of your Package Functions | ||
Version: 1.0.4 | ||
Version: 1.0.4.9000 | ||
Authors@R: c( | ||
person("Lionel", "Henry", , "[email protected]", role = c("aut", "cre")), | ||
person("Hadley", "Wickham", , "[email protected]", role = "aut", | ||
|
@@ -23,18 +23,19 @@ Suggests: | |
covr, | ||
crayon, | ||
knitr, | ||
lintr, | ||
lintr (>= 3.1.0), | ||
rmarkdown, | ||
testthat (>= 3.0.1), | ||
tibble, | ||
tidyverse, | ||
tools, | ||
vctrs, | ||
withr | ||
withr, | ||
xml2 | ||
VignetteBuilder: | ||
knitr | ||
Config/Needs/website: tidyverse/tidytemplate, usethis | ||
Config/testthat/edition: 3 | ||
Encoding: UTF-8 | ||
Roxygen: list(markdown = TRUE) | ||
RoxygenNote: 7.2.1 | ||
RoxygenNote: 7.2.3 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,7 @@ db_function <- function(db) { | |
#' Include `NA` if you want to include functions without a specified lifecycle | ||
#' status in the results. | ||
#' @export | ||
#' @rdname lint_lifecycle | ||
#' @rdname lifecycle_linter | ||
pkg_lifecycle_statuses <- function(package, which = c("superseded", "deprecated", "questioning", "defunct", "experimental", "soft-deprecated", "retired")) { | ||
check_installed("vctrs") | ||
which <- match.arg(which, several.ok = TRUE) | ||
|
@@ -82,67 +82,107 @@ get_usage_function_names <- function(x) { | |
} | ||
} | ||
|
||
#' @rdname lifecycle_linter | ||
#' @param path The directory path to the files you want to search. | ||
#' @param pattern Any files matching this pattern will be searched. The default | ||
#' searches any files ending in `.R` or `.Rmd`. | ||
#' @export | ||
lint_lifecycle <- function( | ||
packages, | ||
path = ".", | ||
pattern = "(?i)[.](r|rmd|qmd|rnw|rhtml|rrst|rtex|rtxt)$", | ||
which = c("superseded", "deprecated", "questioning", "defunct", "experimental", "soft-deprecated", "retired"), | ||
symbol_is_undesirable = FALSE | ||
) { | ||
which <- match.arg(which, several.ok = TRUE) | ||
|
||
check_installed(c("lintr", "vctrs", "xml2")) | ||
|
||
lintr::lint_dir( | ||
path = path, | ||
pattern = pattern, | ||
linters = lifecycle_linter(packages = packages, which = which, symbol_is_undesirable = symbol_is_undesirable) | ||
) | ||
} | ||
|
||
#' @rdname lifecycle_linter | ||
#' @export | ||
lint_tidyverse_lifecycle <- function( | ||
path = ".", | ||
pattern = "(?i)[.](r|rmd|qmd|rnw|rhtml|rrst|rtex|rtxt)$", | ||
which = c("superseded", "deprecated", "questioning", "defunct", "experimental", "soft-deprecated", "retired"), | ||
symbol_is_undesirable = FALSE | ||
) { | ||
which <- match.arg(which, several.ok = TRUE) | ||
|
||
check_installed(c("lintr", "vctrs", "xml2", "tidyverse")) | ||
|
||
lint_lifecycle( | ||
packages = tidyverse::tidyverse_packages(), | ||
pattern = pattern, | ||
path = path, | ||
which = which, | ||
symbol_is_undesirable = symbol_is_undesirable | ||
) | ||
} | ||
|
||
#' Lint usages of functions that have a non-stable life cycle. | ||
#' | ||
#' - `lint_lifecycle` dynamically queries the package documentation for packages | ||
#' - `lifecycle_linter()` creates a linter for lifecycle annotations which can be | ||
#' included in a `.lintr` configuration if `lintr` is used directly. | ||
#' - `lint_lifecycle()` dynamically queries the package documentation for packages | ||
#' in `packages` for lifecycle annotations and then searches the directory in | ||
#' `path` for usages of those functions. | ||
#' - `lint_tidyverse_lifecycle` is a convenience function to call `lint_lifecycle` | ||
#' - `lint_tidyverse_lifecycle()` is a convenience function to call `lint_lifecycle()` | ||
#' for all the packages in the tidyverse. | ||
#' - `pkg_lifecycle_statuses` returns a data frame of functions with lifecycle | ||
#' - `pkg_lifecycle_statuses()` returns a data frame of functions with lifecycle | ||
#' annotations for an installed package. | ||
#' | ||
#' @param packages One or more installed packages to query for lifecycle statuses. | ||
#' @param path The directory path to the files you want to search. | ||
#' @param pattern Any files matching this pattern will be searched. The default | ||
#' searches any files ending in `.R` or `.Rmd`. | ||
#' @param which Vector of lifecycle statuses to lint. | ||
#' @param symbol_is_undesirable Also lint symbol usages, e.g. `lapply(x, is_na)`? | ||
#' | ||
#' @examples | ||
#' | ||
#' lintr::lint(text = "is_na(x)", linters = lifecycle_linter(packages = "rlang")) | ||
#' lintr::lint(text = "lapply(x, is_na)", linters = lifecycle_linter(packages = "rlang", symbol_is_undesirable = TRUE)) | ||
#' | ||
#' @export | ||
lint_lifecycle <- function(packages, path = ".", pattern = "[.][Rr](md)?", which = c("superseded", "deprecated", "questioning", "defunct", "experimental", "soft-deprecated", "retired")) { | ||
which <- match.arg(which, several.ok = TRUE) | ||
|
||
check_installed(c("lintr", "vctrs")) | ||
lifecycle_linter <- function( | ||
packages = tidyverse::tidyverse_packages(), | ||
which = c("superseded", "deprecated", "questioning", "defunct", "experimental", "soft-deprecated", "retired"), | ||
symbol_is_undesirable = FALSE | ||
) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Idea for future expansion: |
||
check_installed(c("lintr", "vctrs", "xml2")) | ||
|
||
life_cycles <- vctrs::vec_rbind(!!!lapply(packages, pkg_lifecycle_statuses, which = which)) | ||
bad_usages <- sprintf("`%s::%s` is %s", life_cycles$package, life_cycles$fun, life_cycles$lifecycle) | ||
names(bad_usages) <- life_cycles$fun | ||
|
||
msgs <- sprintf("`%s::%s` is %s", life_cycles$package, life_cycles$fun, life_cycles$lifecycle) | ||
|
||
lifecycle_linter <- function(source_file) { | ||
lapply( | ||
lintr::ids_with_token(source_file, "SYMBOL_FUNCTION_CALL", fun = `%in%`), | ||
function(id) { | ||
token <- lintr::with_id(source_file, id) | ||
fun_name <- token[["text"]] | ||
has_lifecycle_fun <- fun_name == life_cycles$fun | ||
if (any(has_lifecycle_fun)) { | ||
line_num <- token[["line1"]] | ||
start_col_num <- token[["col1"]] | ||
end_col_num <- token[["col2"]] | ||
|
||
# In case more than one lifecycle function matches, we only take the first one. | ||
msg <- msgs[has_lifecycle_fun][[1]] | ||
lintr::Lint( | ||
filename = source_file[["filename"]], | ||
line_number = line_num, | ||
column_number = start_col_num, | ||
type = "warning", | ||
message = msg, | ||
line = source_file[["lines"]][[as.character(line_num)]], | ||
ranges = list(c(start_col_num, end_col_num)) | ||
) | ||
} | ||
} | ||
if (symbol_is_undesirable) { | ||
xpath <- sprintf( | ||
"//SYMBOL_FUNCTION_CALL[%1$s] | //SYMBOL[%1$s]", | ||
paste0("text() = '", names(bad_usages), "'", collapse = " or ") | ||
) | ||
} else { | ||
xpath <- sprintf( | ||
"//SYMBOL_FUNCTION_CALL[%s]", | ||
paste0("text() = '", names(bad_usages), "'", collapse = " or ") | ||
) | ||
} | ||
|
||
lintr::lint_dir(path = path, pattern = pattern, linters = lifecycle_linter) | ||
} | ||
|
||
#' @rdname lint_lifecycle | ||
#' @export | ||
lint_tidyverse_lifecycle <- function(path = ".", pattern = "[.][Rr](md)?", which = c("superseded", "deprecated", "questioning", "defunct", "experimental", "soft-deprecated", "retired")) { | ||
which <- match.arg(which, several.ok = TRUE) | ||
lintr::Linter(function(source_expression) { | ||
if (!lintr::is_lint_level(source_expression, "expression")) { | ||
return(list()) | ||
} | ||
|
||
check_installed(c("lintr", "vctrs", "tidyverse")) | ||
matched_nodes <- xml2::xml_find_all(source_expression$xml_parsed_content, xpath) | ||
fun_names <- lintr::get_r_string(matched_nodes) | ||
|
||
lint_lifecycle(packages = tidyverse::tidyverse_packages(), path = path, which = which) | ||
lintr::xml_nodes_to_lints( | ||
matched_nodes, | ||
source_expression = source_expression, | ||
lint_message = unname(bad_usages[fun_names]) | ||
) | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
linter,tags | ||
lifecycle_linter,robustness best_practices configurable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NB this is for PyCharm