|
3 | 3 | #' Check that the source contains no TODO comments (case-insensitive). |
4 | 4 | #' |
5 | 5 | #' @param todo Vector of case-insensitive strings that identify TODO comments. |
| 6 | +#' @param except_regex Vector of case-sensitive regular expressions that identify |
| 7 | +#' _valid_ TODO comments. |
6 | 8 | #' |
7 | 9 | #' @examples |
8 | 10 | #' # will produce lints |
9 | 11 | #' lint( |
10 | | -#' text = "x + y # TODO", |
11 | | -#' linters = todo_comment_linter() |
| 12 | +#' text = "x + y # TOODOO", |
| 13 | +#' linters = todo_comment_linter(todo = "toodoo") |
12 | 14 | #' ) |
13 | 15 | #' |
14 | 16 | #' lint( |
15 | | -#' text = "pi <- 1.0 # FIXME", |
16 | | -#' linters = todo_comment_linter() |
| 17 | +#' text = "pi <- 1.0 # FIIXMEE", |
| 18 | +#' linters = todo_comment_linter(todo = "fiixmee") |
17 | 19 | #' ) |
18 | 20 | #' |
19 | 21 | #' lint( |
20 | | -#' text = "x <- TRUE # hack", |
21 | | -#' linters = todo_comment_linter(todo = c("todo", "fixme", "hack")) |
| 22 | +#' text = "x <- TRUE # TOODOO(#1234): Fix this hack.", |
| 23 | +#' linters = todo_comment_linter() |
22 | 24 | #' ) |
23 | 25 | #' |
24 | 26 | #' # okay |
|
37 | 39 | #' linters = todo_comment_linter() |
38 | 40 | #' ) |
39 | 41 | #' |
| 42 | +#' lint( |
| 43 | +#' text = "x <- TRUE # TODO(#1234): Fix this hack.", |
| 44 | +#' linters = todo_comment_linter(except_regex = "TODO\\(#[0-9]+\\):") |
| 45 | +#' ) |
| 46 | +#' |
40 | 47 | #' @evalRd rd_tags("todo_comment_linter") |
41 | 48 | #' @seealso [linters] for a complete list of linters available in lintr. |
42 | 49 | #' @export |
43 | | -todo_comment_linter <- function(todo = c("todo", "fixme")) { |
| 50 | +todo_comment_linter <- function(todo = c("todo", "fixme"), except_regex = NULL) { |
44 | 51 | todo_comment_regex <- rex(one_or_more("#"), any_spaces, or(todo)) |
| 52 | + valid_todo_regex <- |
| 53 | + if (!is.null(except_regex)) paste0("#+", rex::shortcuts$any_spaces, "(?:", paste(except_regex, collapse = "|"), ")") |
45 | 54 |
|
46 | 55 | Linter(linter_level = "expression", function(source_expression) { |
47 | 56 | xml <- source_expression$xml_parsed_content |
48 | 57 |
|
49 | 58 | comment_expr <- xml_find_all(xml, "//COMMENT") |
50 | | - are_todo <- re_matches(xml_text(comment_expr), todo_comment_regex, ignore.case = TRUE) |
| 59 | + comment_text <- xml_text(comment_expr) |
| 60 | + invalid_todo <- re_matches(comment_text, todo_comment_regex, ignore.case = TRUE) |
| 61 | + if (!is.null(valid_todo_regex)) { |
| 62 | + invalid_todo <- invalid_todo & !re_matches(comment_text, valid_todo_regex) |
| 63 | + } |
51 | 64 |
|
52 | 65 | xml_nodes_to_lints( |
53 | | - comment_expr[are_todo], |
| 66 | + comment_expr[invalid_todo], |
54 | 67 | source_expression = source_expression, |
55 | 68 | lint_message = "Remove TODO comments.", |
56 | 69 | type = "style" |
|
0 commit comments