|
3 | 3 | #' Nesting pipes harms readability; extract sub-steps to separate variables, |
4 | 4 | #' append further pipeline steps, or otherwise refactor such usage away. |
5 | 5 | #' |
6 | | -#' When [try()] or [tryCatch()] are the "outer" call, no lint is thrown, |
7 | | -#' since the "unnested" version of such usage may not work as intended |
8 | | -#' due to how evaluation happens in such cases. |
9 | | -#' |
10 | 6 | #' @param allow_inline Logical, default `TRUE`, in which case only "inner" |
11 | 7 | #' pipelines which span more than one line are linted. If `FALSE`, even |
12 | 8 | #' "inner" pipelines that fit in one line are linted. |
| 9 | +#' @param allow_outer_calls Character vector dictating which "outer" |
| 10 | +#' calls to exempt from the requirement to unnest (see examples). Defaults |
| 11 | +#' to [try()], [tryCatch()], and [withCallingHandlers()]. |
13 | 12 | #' |
14 | 13 | #' @examples |
15 | 14 | #' # will produce lints |
|
25 | 24 | #' linters = nested_pipe_linter(allow_inline = FALSE) |
26 | 25 | #' ) |
27 | 26 | #' |
| 27 | +#' lint( |
| 28 | +#' text = "tryCatch(x %>% filter(grp == 'a'), error = identity)", |
| 29 | +#' linters = nested_pipe_linter(allow_outer_calls = character()) |
| 30 | +#' ) |
| 31 | +#' |
28 | 32 | #' # okay |
29 | 33 | #' lint( |
30 | 34 | #' text = "df1 %>% inner_join(df2 %>% select(a, b))", |
31 | 35 | #' linters = nested_pipe_linter() |
32 | 36 | #' ) |
33 | 37 | #' |
| 38 | +#' code <- "df1 %>%\n inner_join(df2 %>%\n select(a, b)\n )" |
| 39 | +#' writeLines(code) |
| 40 | +#' lint( |
| 41 | +#' text = code, |
| 42 | +#' linters = nested_pipe_linter(allow_outer_calls = "inner_join") |
| 43 | +#' ) |
| 44 | +#' |
34 | 45 | #' lint( |
35 | 46 | #' text = "tryCatch(x %>% filter(grp == 'a'), error = identity)", |
36 | 47 | #' linters = nested_pipe_linter() |
|
39 | 50 | #' @evalRd rd_tags("nested_pipe_linter") |
40 | 51 | #' @seealso [linters] for a complete list of linters available in lintr. |
41 | 52 | #' @export |
42 | | -nested_pipe_linter <- function(allow_inline = TRUE) { |
| 53 | +nested_pipe_linter <- function( |
| 54 | + allow_inline = TRUE, |
| 55 | + allow_outer_calls = c("try", "tryCatch", "withCallingHandlers")) { |
43 | 56 | multiline_and <- if (allow_inline) "@line1 != @line2 and" else "" |
44 | 57 | xpath <- glue(" |
45 | 58 | (//PIPE | //SPECIAL[{ xp_text_in_table(magrittr_pipes) }]) |
46 | 59 | /parent::expr[{multiline_and} preceding-sibling::expr/SYMBOL_FUNCTION_CALL[ |
47 | | - not(text() = 'try' or text() = 'tryCatch') |
| 60 | + not({ xp_text_in_table(allow_outer_calls) }) |
48 | 61 | and ( |
49 | 62 | text() != 'switch' |
50 | 63 | or parent::expr |
|
0 commit comments