From de3f0828ba3118ad32b3dea46890b5afe858b1a6 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Thu, 11 Jan 2024 17:02:56 +0800 Subject: [PATCH 01/15] package housekeeping --- DESCRIPTION | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index f399da4f..8cad97d1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: rhino Title: A Framework for Enterprise Shiny Applications -Version: 1.7.0.9000 +Version: 1.7.0.9003 Authors@R: c( person("Kamil", "Żyła", role = c("aut", "cre"), email = "opensource+kamil@appsilon.com"), @@ -44,9 +44,11 @@ Suggests: knitr, mockery, rcmdcheck, + rex, rmarkdown, shiny.react, - spelling + spelling, + xml2 LazyData: true Config/testthat/edition: 3 Config/testthat/parallel: true From caced920eacd3d23bda57c01e7bf10977d6282d6 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Thu, 11 Jan 2024 17:03:30 +0800 Subject: [PATCH 02/15] box function import count linter --- R/linter_box_function_import_count_linter.R | 66 ++++++++++++++++++ ...-linter_box_function_import_count_linter.R | 67 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 R/linter_box_function_import_count_linter.R create mode 100644 tests/testthat/test-linter_box_function_import_count_linter.R diff --git a/R/linter_box_function_import_count_linter.R b/R/linter_box_function_import_count_linter.R new file mode 100644 index 00000000..ec82ea68 --- /dev/null +++ b/R/linter_box_function_import_count_linter.R @@ -0,0 +1,66 @@ +#' Box library function import count linter +#' +#' Checks that function imports do not exceed the defined `max`. Defaults to 5. +#' +#' @param max Maximum function imports allowed between `[` and `]`. Defaults to 5. +#' +#' @examples +#' # will produce lints +#' lintr::lint( +#' text = "box::use(package[one, two, three, four, five, six, ])", +#' linters = box_func_import_count_linter() +#' ) +#' +#' lintr::lint( +#' text = "box::use(package[one, two, three, four, ])", +#' linters = box_func_import_count_linter(3) +#' ) +#' +#' # okay +#' lintr::lint( +#' text = "box::use(package[one, two, three, four, five, ])", +#' linters = box_func_import_count_linter() +#' ) +#' +#' lintr::lint( +#' text = "box::use(package[one, two, three, ])", +#' linters = box_func_import_count_linter(3) +#' ) +#' +#' @export +box_func_import_count_linter <- function(max = 5L) { + xpath <- glue::glue("//SYMBOL_PACKAGE[ + (text() = 'box' and + following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use']) + ] +/parent::expr +/parent::expr +/descendant::OP-LEFT-BRACKET[ + count( + following-sibling::expr[ + count(. | ..//OP-RIGHT-BRACKET/preceding-sibling::expr) = + count(../OP-RIGHT-BRACKET/preceding-sibling::expr) + ] + ) > {max} +] +/parent::expr") + + lint_message <- glue::glue("Limit the function imports to a max of {max}.") + + lintr::Linter(function(source_expression) { + if (!lintr::is_lint_level(source_expression, "file")) { + return(list()) + } + + xml <- source_expression$full_xml_parsed_content + + bad_expr <- xml2::xml_find_all(xml, xpath) + + lintr::xml_nodes_to_lints( + bad_expr, + source_expression = source_expression, + lint_message = lint_message, + type = "style" + ) + }) +} diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R new file mode 100644 index 00000000..0a5bd1af --- /dev/null +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -0,0 +1,67 @@ +five_function_imports <- "box::use( + dplyr[ + arrange, + select, + mutate, + distinct, + filter, + ], +)" + +five_function_imports_inline <- "box::use( + dplyr[arrange, select, mutate, distinct, filter, ], +)" + +six_function_imports <- "box::use( + dplyr[ + arrange, + select, + mutate, + distinct, + filter, + slice, + ], +)" + +six_function_imports_inline <- "box::use( + dplyr[arrange, select, mutate, distinct, filter, slice, ], +)" + +three_function_imports <- "box::use( + dplyr[ + arrange, + select, + mutate, + ], +)" + +three_function_imports_inline <- "box::use( + dplyr[arrange, select, mutate, ], +)" + +lint_message <- function(max = 5L) { + rex::rex(glue::glue("Limit the function imports to a max of {max}.")) +} + +test_that("box_func_import_count_linter skips allowed function count.", { + linter <- box_func_import_count_linter() + + lintr::expect_lint(five_function_imports, NULL, ) + lintr::expect_lint(five_function_imports_inline, NULL, linter) +}) + +test_that("box_func_import_count_linter skips allowed function count supplied max", { + linter <- box_func_import_count_linter(max = 3) + + lintr::expect_lint(three_function_imports, NULL, ) + lintr::expect_lint(three_function_imports_inline, NULL, linter) +}) + +test_that("box_func_import_count_linter blocks function imports more than max", { + max <- 5 + linter <- box_func_import_count_linter(max = max) + lint_msg <- lint_message(max) + + lintr::expect_lint(six_function_imports, list(message = lint_msg), linter) + lintr::expect_lint(six_function_imports_inline, list(message = lint_msg), linter) +}) From fa7d53f6bb17156ce69494ae5d3d2097fe2af579 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Thu, 11 Jan 2024 17:03:59 +0800 Subject: [PATCH 03/15] update .lintr template --- inst/templates/app_structure/dot.lintr | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/templates/app_structure/dot.lintr b/inst/templates/app_structure/dot.lintr index 63fade9a..418d0c59 100644 --- a/inst/templates/app_structure/dot.lintr +++ b/inst/templates/app_structure/dot.lintr @@ -1,5 +1,6 @@ linters: linters_with_defaults( line_length_linter = line_length_linter(100), + box_func_import_count_linter = rhino::box_func_import_count_linter(), object_usage_linter = NULL # Does not work with `box::use()`. ) From a7222ef2ea3bc1855769a68eba30677214d5e83a Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Thu, 11 Jan 2024 17:04:17 +0800 Subject: [PATCH 04/15] documentation --- NAMESPACE | 1 + man/box_func_import_count_linter.Rd | 38 +++++++++++++++++++++++++++++ pkgdown/_pkgdown.yml | 4 +++ 3 files changed, 43 insertions(+) create mode 100644 man/box_func_import_count_linter.Rd diff --git a/NAMESPACE b/NAMESPACE index 2b25b2d5..99d592db 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(app) +export(box_func_import_count_linter) export(build_js) export(build_sass) export(diagnostics) diff --git a/man/box_func_import_count_linter.Rd b/man/box_func_import_count_linter.Rd new file mode 100644 index 00000000..1edf45b9 --- /dev/null +++ b/man/box_func_import_count_linter.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/linter_box_function_import_count_linter.R +\name{box_func_import_count_linter} +\alias{box_func_import_count_linter} +\title{Box library function import count linter} +\usage{ +box_func_import_count_linter(max = 5L) +} +\arguments{ +\item{max}{Maximum function imports allowed between \code{[} and \verb{]}. Defaults to 5.} +} +\description{ +Checks that function imports do not exceed the defined \code{max}. Defaults to 5. +} +\examples{ +# will produce lints +lintr::lint( + text = "box::use(package[one, two, three, four, five, six, ])", + linters = box_func_import_count_linter() +) + +lintr::lint( + text = "box::use(package[one, two, three, four, ])", + linters = box_func_import_count_linter(3) +) + +# okay +lintr::lint( + text = "box::use(package[one, two, three, four, five, ])", + linters = box_func_import_count_linter() +) + +lintr::lint( + text = "box::use(package[one, two, three, ])", + linters = box_func_import_count_linter(3) +) + +} diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 759c93d4..a69c5e4f 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -143,6 +143,10 @@ reference: - diagnostics - test_e2e +- title: Linters + contents: + - box_func_import_count_linter + - title: Data contents: - rhinos From d64a8072913169c4362b90506465af18fd770d08 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Thu, 11 Jan 2024 17:12:38 +0800 Subject: [PATCH 05/15] remove lint --- R/linter_box_function_import_count_linter.R | 18 +++++++++--------- ...t-linter_box_function_import_count_linter.R | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/R/linter_box_function_import_count_linter.R b/R/linter_box_function_import_count_linter.R index ec82ea68..86c1256a 100644 --- a/R/linter_box_function_import_count_linter.R +++ b/R/linter_box_function_import_count_linter.R @@ -10,23 +10,23 @@ #' text = "box::use(package[one, two, three, four, five, six, ])", #' linters = box_func_import_count_linter() #' ) -#' +#' #' lintr::lint( #' text = "box::use(package[one, two, three, four, ])", #' linters = box_func_import_count_linter(3) #' ) -#' +#' #' # okay #' lintr::lint( #' text = "box::use(package[one, two, three, four, five, ])", #' linters = box_func_import_count_linter() #' ) -#' +#' #' lintr::lint( #' text = "box::use(package[one, two, three, ])", #' linters = box_func_import_count_linter(3) #' ) -#' +#' #' @export box_func_import_count_linter <- function(max = 5L) { xpath <- glue::glue("//SYMBOL_PACKAGE[ @@ -44,18 +44,18 @@ box_func_import_count_linter <- function(max = 5L) { ) > {max} ] /parent::expr") - + lint_message <- glue::glue("Limit the function imports to a max of {max}.") - + lintr::Linter(function(source_expression) { if (!lintr::is_lint_level(source_expression, "file")) { return(list()) } - + xml <- source_expression$full_xml_parsed_content - + bad_expr <- xml2::xml_find_all(xml, xpath) - + lintr::xml_nodes_to_lints( bad_expr, source_expression = source_expression, diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R index 0a5bd1af..fdf3c941 100644 --- a/tests/testthat/test-linter_box_function_import_count_linter.R +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -45,14 +45,14 @@ lint_message <- function(max = 5L) { test_that("box_func_import_count_linter skips allowed function count.", { linter <- box_func_import_count_linter() - + lintr::expect_lint(five_function_imports, NULL, ) lintr::expect_lint(five_function_imports_inline, NULL, linter) }) test_that("box_func_import_count_linter skips allowed function count supplied max", { linter <- box_func_import_count_linter(max = 3) - + lintr::expect_lint(three_function_imports, NULL, ) lintr::expect_lint(three_function_imports_inline, NULL, linter) }) @@ -61,7 +61,7 @@ test_that("box_func_import_count_linter blocks function imports more than max", max <- 5 linter <- box_func_import_count_linter(max = max) lint_msg <- lint_message(max) - + lintr::expect_lint(six_function_imports, list(message = lint_msg), linter) lintr::expect_lint(six_function_imports_inline, list(message = lint_msg), linter) }) From ec641ee12bca33d3eee4132161e1d6e538ac5360 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 12 Jan 2024 16:12:12 +0800 Subject: [PATCH 06/15] change default max to 8 --- R/linter_box_function_import_count_linter.R | 6 +++--- man/box_func_import_count_linter.Rd | 6 +++--- .../testthat/test-linter_box_function_import_count_linter.R | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/linter_box_function_import_count_linter.R b/R/linter_box_function_import_count_linter.R index 86c1256a..4f600258 100644 --- a/R/linter_box_function_import_count_linter.R +++ b/R/linter_box_function_import_count_linter.R @@ -1,8 +1,8 @@ #' Box library function import count linter #' -#' Checks that function imports do not exceed the defined `max`. Defaults to 5. +#' Checks that function imports do not exceed the defined `max`. #' -#' @param max Maximum function imports allowed between `[` and `]`. Defaults to 5. +#' @param max Maximum function imports allowed between `[` and `]`. Defaults to 8. #' #' @examples #' # will produce lints @@ -28,7 +28,7 @@ #' ) #' #' @export -box_func_import_count_linter <- function(max = 5L) { +box_func_import_count_linter <- function(max = 8L) { xpath <- glue::glue("//SYMBOL_PACKAGE[ (text() = 'box' and following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use']) diff --git a/man/box_func_import_count_linter.Rd b/man/box_func_import_count_linter.Rd index 1edf45b9..c9695654 100644 --- a/man/box_func_import_count_linter.Rd +++ b/man/box_func_import_count_linter.Rd @@ -4,13 +4,13 @@ \alias{box_func_import_count_linter} \title{Box library function import count linter} \usage{ -box_func_import_count_linter(max = 5L) +box_func_import_count_linter(max = 8L) } \arguments{ -\item{max}{Maximum function imports allowed between \code{[} and \verb{]}. Defaults to 5.} +\item{max}{Maximum function imports allowed between \code{[} and \verb{]}. Defaults to 8.} } \description{ -Checks that function imports do not exceed the defined \code{max}. Defaults to 5. +Checks that function imports do not exceed the defined \code{max}. } \examples{ # will produce lints diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R index fdf3c941..d6dc7f42 100644 --- a/tests/testthat/test-linter_box_function_import_count_linter.R +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -44,7 +44,7 @@ lint_message <- function(max = 5L) { } test_that("box_func_import_count_linter skips allowed function count.", { - linter <- box_func_import_count_linter() + linter <- box_func_import_count_linter(max = 5) lintr::expect_lint(five_function_imports, NULL, ) lintr::expect_lint(five_function_imports_inline, NULL, linter) From 7f45a9c030d5599e9894e82366c57c41137afee3 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 12 Jan 2024 16:14:22 +0800 Subject: [PATCH 07/15] skip lint for shiny[] call --- tests/e2e/app-files/hello.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/app-files/hello.R b/tests/e2e/app-files/hello.R index 19023488..efc9f199 100644 --- a/tests/e2e/app-files/hello.R +++ b/tests/e2e/app-files/hello.R @@ -11,7 +11,7 @@ box::use( tags, textInput, textOutput - ], + ], # nolint ) box::use(app/logic/say_hello[say_hello]) From 4f92a336a2f3532ea407aa8bf72b253655d75cbc Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 12 Jan 2024 16:24:10 +0800 Subject: [PATCH 08/15] nolint flag --- tests/e2e/app-files/hello.R | 4 ++-- ...-linter_box_function_import_count_linter.R | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/e2e/app-files/hello.R b/tests/e2e/app-files/hello.R index efc9f199..9567a26c 100644 --- a/tests/e2e/app-files/hello.R +++ b/tests/e2e/app-files/hello.R @@ -1,5 +1,5 @@ box::use( - shiny[ + shiny[ # nolint actionButton, bootstrapPage, isolate, @@ -11,7 +11,7 @@ box::use( tags, textInput, textOutput - ], # nolint + ], ) box::use(app/logic/say_hello[say_hello]) diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R index d6dc7f42..3290aca1 100644 --- a/tests/testthat/test-linter_box_function_import_count_linter.R +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -39,6 +39,19 @@ three_function_imports_inline <- "box::use( dplyr[arrange, select, mutate, ], )" +no_lint <- "box::use( + dplyr[ # nolint + arrange, + select, + mutate, + distinct + ], +)" + +no_lint_inline <- "box::use( + dplyr[arrange, select, mutate, distinct], # nolint +)" + lint_message <- function(max = 5L) { rex::rex(glue::glue("Limit the function imports to a max of {max}.")) } @@ -65,3 +78,12 @@ test_that("box_func_import_count_linter blocks function imports more than max", lintr::expect_lint(six_function_imports, list(message = lint_msg), linter) lintr::expect_lint(six_function_imports_inline, list(message = lint_msg), linter) }) + +test_that("box_func_import_count_linter resepect # nolint", { + max <- 3 + linter <- box_func_import_count_linter(max = max) + lint_msg <- lint_message(max) + + lintr::expect_lint(no_lint, NULL, linter) + lintr::expect_lint(no_lint_inline, NULL, linter) +}) \ No newline at end of file From 9b72efe830b2334d51ae8e7ca2bb42ed6842a22c Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 12 Jan 2024 16:28:39 +0800 Subject: [PATCH 09/15] remove lint --- tests/testthat/test-linter_box_function_import_count_linter.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R index 3290aca1..4330e30b 100644 --- a/tests/testthat/test-linter_box_function_import_count_linter.R +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -83,7 +83,7 @@ test_that("box_func_import_count_linter resepect # nolint", { max <- 3 linter <- box_func_import_count_linter(max = max) lint_msg <- lint_message(max) - + lintr::expect_lint(no_lint, NULL, linter) lintr::expect_lint(no_lint_inline, NULL, linter) -}) \ No newline at end of file +}) From 4523b4d2c59a0e5c6bee78b6bde7b31d07fe74d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 12 Jan 2024 17:23:07 +0800 Subject: [PATCH 10/15] somehow forgot to call the linter --- tests/testthat/test-linter_box_function_import_count_linter.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R index 4330e30b..3e7d0e9c 100644 --- a/tests/testthat/test-linter_box_function_import_count_linter.R +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -59,14 +59,14 @@ lint_message <- function(max = 5L) { test_that("box_func_import_count_linter skips allowed function count.", { linter <- box_func_import_count_linter(max = 5) - lintr::expect_lint(five_function_imports, NULL, ) + lintr::expect_lint(five_function_imports, NULL, linter) lintr::expect_lint(five_function_imports_inline, NULL, linter) }) test_that("box_func_import_count_linter skips allowed function count supplied max", { linter <- box_func_import_count_linter(max = 3) - lintr::expect_lint(three_function_imports, NULL, ) + lintr::expect_lint(three_function_imports, NULL, linter) lintr::expect_lint(three_function_imports_inline, NULL, linter) }) From 071cce3a8a3d01cf09190f4aee3c2827c80df3a9 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 26 Jan 2024 12:55:13 +0800 Subject: [PATCH 11/15] address comments/suggestions in PR --- DESCRIPTION | 3 +- R/linter_box_function_import_count_linter.R | 4 +- man/box_func_import_count_linter.Rd | 5 +- ...-linter_box_function_import_count_linter.R | 112 +++++++++--------- 4 files changed, 63 insertions(+), 61 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 64597df4..850c025d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -48,8 +48,7 @@ Suggests: rex, rmarkdown, shiny.react, - spelling, - xml2 + spelling LazyData: true Config/testthat/edition: 3 Config/testthat/parallel: true diff --git a/R/linter_box_function_import_count_linter.R b/R/linter_box_function_import_count_linter.R index 4f600258..13c5b7c4 100644 --- a/R/linter_box_function_import_count_linter.R +++ b/R/linter_box_function_import_count_linter.R @@ -4,8 +4,10 @@ #' #' @param max Maximum function imports allowed between `[` and `]`. Defaults to 8. #' +#' @return A custom linter function for use with `r-lib/lintr`. +#' #' @examples -#' # will produce lints +#' will produce lints #' lintr::lint( #' text = "box::use(package[one, two, three, four, five, six, ])", #' linters = box_func_import_count_linter() diff --git a/man/box_func_import_count_linter.Rd b/man/box_func_import_count_linter.Rd index c9695654..42a6ec06 100644 --- a/man/box_func_import_count_linter.Rd +++ b/man/box_func_import_count_linter.Rd @@ -9,11 +9,14 @@ box_func_import_count_linter(max = 8L) \arguments{ \item{max}{Maximum function imports allowed between \code{[} and \verb{]}. Defaults to 8.} } +\value{ +A custom linter function for use with \code{r-lib/lintr}. +} \description{ Checks that function imports do not exceed the defined \code{max}. } \examples{ -# will produce lints +will produce lints lintr::lint( text = "box::use(package[one, two, three, four, five, six, ])", linters = box_func_import_count_linter() diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_function_import_count_linter.R index 3e7d0e9c..6d080c91 100644 --- a/tests/testthat/test-linter_box_function_import_count_linter.R +++ b/tests/testthat/test-linter_box_function_import_count_linter.R @@ -1,57 +1,3 @@ -five_function_imports <- "box::use( - dplyr[ - arrange, - select, - mutate, - distinct, - filter, - ], -)" - -five_function_imports_inline <- "box::use( - dplyr[arrange, select, mutate, distinct, filter, ], -)" - -six_function_imports <- "box::use( - dplyr[ - arrange, - select, - mutate, - distinct, - filter, - slice, - ], -)" - -six_function_imports_inline <- "box::use( - dplyr[arrange, select, mutate, distinct, filter, slice, ], -)" - -three_function_imports <- "box::use( - dplyr[ - arrange, - select, - mutate, - ], -)" - -three_function_imports_inline <- "box::use( - dplyr[arrange, select, mutate, ], -)" - -no_lint <- "box::use( - dplyr[ # nolint - arrange, - select, - mutate, - distinct - ], -)" - -no_lint_inline <- "box::use( - dplyr[arrange, select, mutate, distinct], # nolint -)" - lint_message <- function(max = 5L) { rex::rex(glue::glue("Limit the function imports to a max of {max}.")) } @@ -59,6 +5,20 @@ lint_message <- function(max = 5L) { test_that("box_func_import_count_linter skips allowed function count.", { linter <- box_func_import_count_linter(max = 5) + five_function_imports <- "box::use( + dplyr[ + arrange, + select, + mutate, + distinct, + filter, + ], + )" + + five_function_imports_inline <- "box::use( + dplyr[arrange, select, mutate, distinct, filter, ], + )" + lintr::expect_lint(five_function_imports, NULL, linter) lintr::expect_lint(five_function_imports_inline, NULL, linter) }) @@ -66,6 +26,18 @@ test_that("box_func_import_count_linter skips allowed function count.", { test_that("box_func_import_count_linter skips allowed function count supplied max", { linter <- box_func_import_count_linter(max = 3) + three_function_imports <- "box::use( + dplyr[ + arrange, + select, + mutate, + ], + )" + + three_function_imports_inline <- "box::use( + dplyr[arrange, select, mutate, ], + )" + lintr::expect_lint(three_function_imports, NULL, linter) lintr::expect_lint(three_function_imports_inline, NULL, linter) }) @@ -75,14 +47,40 @@ test_that("box_func_import_count_linter blocks function imports more than max", linter <- box_func_import_count_linter(max = max) lint_msg <- lint_message(max) + six_function_imports <- "box::use( + dplyr[ + arrange, + select, + mutate, + distinct, + filter, + slice, + ], + )" + + six_function_imports_inline <- "box::use( + dplyr[arrange, select, mutate, distinct, filter, slice, ], + )" + lintr::expect_lint(six_function_imports, list(message = lint_msg), linter) lintr::expect_lint(six_function_imports_inline, list(message = lint_msg), linter) }) test_that("box_func_import_count_linter resepect # nolint", { - max <- 3 - linter <- box_func_import_count_linter(max = max) - lint_msg <- lint_message(max) + linter <- box_func_import_count_linter() + + no_lint <- "box::use( + dplyr[ # nolint + arrange, + select, + mutate, + distinct + ], + )" + + no_lint_inline <- "box::use( + dplyr[arrange, select, mutate, distinct], # nolint + )" lintr::expect_lint(no_lint, NULL, linter) lintr::expect_lint(no_lint_inline, NULL, linter) From f1937dea67f3d4929cdda56feb695bc99742e88a Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 26 Jan 2024 12:58:05 +0800 Subject: [PATCH 12/15] address a roxygen doc mistake --- R/box_linters.R | 69 +++++++++++++++++++++ R/linter_box_function_import_count_linter.R | 68 -------------------- man/box_func_import_count_linter.Rd | 4 +- 3 files changed, 71 insertions(+), 70 deletions(-) delete mode 100644 R/linter_box_function_import_count_linter.R diff --git a/R/box_linters.R b/R/box_linters.R index f0ba769c..3ea3d225 100644 --- a/R/box_linters.R +++ b/R/box_linters.R @@ -1,3 +1,72 @@ +#' Box library function import count linter +#' +#' Checks that function imports do not exceed the defined `max`. +#' +#' @param max Maximum function imports allowed between `[` and `]`. Defaults to 8. +#' +#' @return A custom linter function for use with `r-lib/lintr`. +#' +#' @examples +#' # will produce lints +#' lintr::lint( +#' text = "box::use(package[one, two, three, four, five, six, ])", +#' linters = box_func_import_count_linter() +#' ) +#' +#' lintr::lint( +#' text = "box::use(package[one, two, three, four, ])", +#' linters = box_func_import_count_linter(3) +#' ) +#' +#' # okay +#' lintr::lint( +#' text = "box::use(package[one, two, three, four, five, ])", +#' linters = box_func_import_count_linter() +#' ) +#' +#' lintr::lint( +#' text = "box::use(package[one, two, three, ])", +#' linters = box_func_import_count_linter(3) +#' ) +#' +#' @export +box_func_import_count_linter <- function(max = 8L) { + xpath <- glue::glue("//SYMBOL_PACKAGE[ + (text() = 'box' and + following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use']) + ] +/parent::expr +/parent::expr +/descendant::OP-LEFT-BRACKET[ + count( + following-sibling::expr[ + count(. | ..//OP-RIGHT-BRACKET/preceding-sibling::expr) = + count(../OP-RIGHT-BRACKET/preceding-sibling::expr) + ] + ) > {max} +] +/parent::expr") + + lint_message <- glue::glue("Limit the function imports to a max of {max}.") + + lintr::Linter(function(source_expression) { + if (!lintr::is_lint_level(source_expression, "file")) { + return(list()) + } + + xml <- source_expression$full_xml_parsed_content + + bad_expr <- xml2::xml_find_all(xml, xpath) + + lintr::xml_nodes_to_lints( + bad_expr, + source_expression = source_expression, + lint_message = lint_message, + type = "style" + ) + }) +} + #' Box library universal import linter #' #' Checks that all function imports are explicit. `package[...]` is not used. diff --git a/R/linter_box_function_import_count_linter.R b/R/linter_box_function_import_count_linter.R deleted file mode 100644 index 13c5b7c4..00000000 --- a/R/linter_box_function_import_count_linter.R +++ /dev/null @@ -1,68 +0,0 @@ -#' Box library function import count linter -#' -#' Checks that function imports do not exceed the defined `max`. -#' -#' @param max Maximum function imports allowed between `[` and `]`. Defaults to 8. -#' -#' @return A custom linter function for use with `r-lib/lintr`. -#' -#' @examples -#' will produce lints -#' lintr::lint( -#' text = "box::use(package[one, two, three, four, five, six, ])", -#' linters = box_func_import_count_linter() -#' ) -#' -#' lintr::lint( -#' text = "box::use(package[one, two, three, four, ])", -#' linters = box_func_import_count_linter(3) -#' ) -#' -#' # okay -#' lintr::lint( -#' text = "box::use(package[one, two, three, four, five, ])", -#' linters = box_func_import_count_linter() -#' ) -#' -#' lintr::lint( -#' text = "box::use(package[one, two, three, ])", -#' linters = box_func_import_count_linter(3) -#' ) -#' -#' @export -box_func_import_count_linter <- function(max = 8L) { - xpath <- glue::glue("//SYMBOL_PACKAGE[ - (text() = 'box' and - following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use']) - ] -/parent::expr -/parent::expr -/descendant::OP-LEFT-BRACKET[ - count( - following-sibling::expr[ - count(. | ..//OP-RIGHT-BRACKET/preceding-sibling::expr) = - count(../OP-RIGHT-BRACKET/preceding-sibling::expr) - ] - ) > {max} -] -/parent::expr") - - lint_message <- glue::glue("Limit the function imports to a max of {max}.") - - lintr::Linter(function(source_expression) { - if (!lintr::is_lint_level(source_expression, "file")) { - return(list()) - } - - xml <- source_expression$full_xml_parsed_content - - bad_expr <- xml2::xml_find_all(xml, xpath) - - lintr::xml_nodes_to_lints( - bad_expr, - source_expression = source_expression, - lint_message = lint_message, - type = "style" - ) - }) -} diff --git a/man/box_func_import_count_linter.Rd b/man/box_func_import_count_linter.Rd index 42a6ec06..d0300d79 100644 --- a/man/box_func_import_count_linter.Rd +++ b/man/box_func_import_count_linter.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/linter_box_function_import_count_linter.R +% Please edit documentation in R/box_linters.R \name{box_func_import_count_linter} \alias{box_func_import_count_linter} \title{Box library function import count linter} @@ -16,7 +16,7 @@ A custom linter function for use with \code{r-lib/lintr}. Checks that function imports do not exceed the defined \code{max}. } \examples{ -will produce lints +# will produce lints lintr::lint( text = "box::use(package[one, two, three, four, five, six, ])", linters = box_func_import_count_linter() From 2e56e2072219504a875cb29b7135e7ee0a46d7e4 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Fri, 26 Jan 2024 13:03:36 +0800 Subject: [PATCH 13/15] rename test file to reflect function name --- ..._count_linter.R => test-linter_box_func_import_count_linter.R} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{test-linter_box_function_import_count_linter.R => test-linter_box_func_import_count_linter.R} (100%) diff --git a/tests/testthat/test-linter_box_function_import_count_linter.R b/tests/testthat/test-linter_box_func_import_count_linter.R similarity index 100% rename from tests/testthat/test-linter_box_function_import_count_linter.R rename to tests/testthat/test-linter_box_func_import_count_linter.R From df30abd7d92a78e94eef0ac9f08484ff7986c787 Mon Sep 17 00:00:00 2001 From: Rodrigo Basa Date: Thu, 8 Feb 2024 11:43:23 +0800 Subject: [PATCH 14/15] ironic de-linting commit --- R/box_linters.R | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/R/box_linters.R b/R/box_linters.R index fa09bbc7..90721c10 100644 --- a/R/box_linters.R +++ b/R/box_linters.R @@ -46,18 +46,18 @@ box_func_import_count_linter <- function(max = 8L) { ) > {max} ] /parent::expr") - + lint_message <- glue::glue("Limit the function imports to a max of {max}.") - + lintr::Linter(function(source_expression) { if (!lintr::is_lint_level(source_expression, "file")) { return(list()) } - + xml <- source_expression$full_xml_parsed_content - + bad_expr <- xml2::xml_find_all(xml, xpath) - + lintr::xml_nodes_to_lints( bad_expr, source_expression = source_expression, @@ -115,7 +115,7 @@ box_trailing_commas_linter <- function(check_functions = FALSE) { ] /parent::expr " - + right_paren_xpath <- paste( base_xpath, "/following-sibling::OP-RIGHT-PAREN[ @@ -123,7 +123,7 @@ box_trailing_commas_linter <- function(check_functions = FALSE) { ] " ) - + right_bracket_xpath <- paste( base_xpath, "/parent::expr @@ -137,27 +137,27 @@ box_trailing_commas_linter <- function(check_functions = FALSE) { ] " ) - + lintr::Linter(function(source_expression) { if (!lintr::is_lint_level(source_expression, "file")) { return(list()) } - + xml <- source_expression$full_xml_parsed_content - + bad_right_paren_expr <- xml2::xml_find_all(xml, right_paren_xpath) - + paren_lints <- lintr::xml_nodes_to_lints( bad_right_paren_expr, source_expression = source_expression, lint_message = "Always have a trailing comma at the end of imports, before a `)`.", type = "style" ) - + bracket_lints <- NULL if (check_functions) { bad_right_bracket_expr <- xml2::xml_find_all(xml, right_bracket_xpath) - + bracket_lints <- lintr::xml_nodes_to_lints( bad_right_bracket_expr, source_expression = source_expression, @@ -165,7 +165,7 @@ box_trailing_commas_linter <- function(check_functions = FALSE) { type = "style" ) } - + c(paren_lints, bracket_lints) }) } @@ -202,23 +202,23 @@ box_trailing_commas_linter <- function(check_functions = FALSE) { #' @export box_universal_import_linter <- function() { 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() = '...'] " - + lintr::Linter(function(source_expression) { if (!lintr::is_lint_level(source_expression, "file")) { return(list()) } - + xml <- source_expression$full_xml_parsed_content - + bad_expr <- xml2::xml_find_all(xml, xpath) - + lintr::xml_nodes_to_lints( bad_expr, source_expression = source_expression, From 96683d769a8cb3a14481f70e6834ae44d2b6f5e5 Mon Sep 17 00:00:00 2001 From: Jakub Nowicki Date: Tue, 20 Feb 2024 12:27:03 +0100 Subject: [PATCH 15/15] docs: Minor documentation changes. --- NEWS.md | 1 + R/box_linters.R | 32 ++++++++++++++--------------- man/box_func_import_count_linter.Rd | 10 ++++----- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/NEWS.md b/NEWS.md index 239e44e4..777196d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ 1. Introduce linters for `box::use` statements: * `box_universal_import_linter` checks if all imports are explicit. * `box_trailing_commas_linter` checks if statements include trailing commas. + * `box_func_import_count_linter` checks if the number of function imports does not exceed the limit. 2. Major refactor of `rhino::app()`: * The `request` parameter is now correctly forwarded to the UI function when using a `legacy_entrypoint` ([#395](https://github.com/Appsilon/rhino/issues/395)). diff --git a/R/box_linters.R b/R/box_linters.R index 90721c10..8338160d 100644 --- a/R/box_linters.R +++ b/R/box_linters.R @@ -1,4 +1,4 @@ -#' Box library function import count linter +#' `box` library function import count linter #' #' Checks that function imports do not exceed the defined `max`. #' @@ -9,23 +9,23 @@ #' @examples #' # will produce lints #' lintr::lint( -#' text = "box::use(package[one, two, three, four, five, six, ])", +#' text = "box::use(package[one, two, three, four, five, six, seven, eight, nine])", #' linters = box_func_import_count_linter() #' ) #' #' lintr::lint( -#' text = "box::use(package[one, two, three, four, ])", +#' text = "box::use(package[one, two, three, four])", #' linters = box_func_import_count_linter(3) #' ) #' #' # okay #' lintr::lint( -#' text = "box::use(package[one, two, three, four, five, ])", +#' text = "box::use(package[one, two, three, four, five])", #' linters = box_func_import_count_linter() #' ) #' #' lintr::lint( -#' text = "box::use(package[one, two, three, ])", +#' text = "box::use(package[one, two, three])", #' linters = box_func_import_count_linter(3) #' ) #' @@ -35,17 +35,17 @@ box_func_import_count_linter <- function(max = 8L) { (text() = 'box' and following-sibling::SYMBOL_FUNCTION_CALL[text() = 'use']) ] -/parent::expr -/parent::expr -/descendant::OP-LEFT-BRACKET[ - count( - following-sibling::expr[ - count(. | ..//OP-RIGHT-BRACKET/preceding-sibling::expr) = - count(../OP-RIGHT-BRACKET/preceding-sibling::expr) - ] - ) > {max} -] -/parent::expr") + /parent::expr + /parent::expr + /descendant::OP-LEFT-BRACKET[ + count( + following-sibling::expr[ + count(. | ..//OP-RIGHT-BRACKET/preceding-sibling::expr) = + count(../OP-RIGHT-BRACKET/preceding-sibling::expr) + ] + ) > {max} + ] + /parent::expr") lint_message <- glue::glue("Limit the function imports to a max of {max}.") diff --git a/man/box_func_import_count_linter.Rd b/man/box_func_import_count_linter.Rd index d0300d79..1960ce5a 100644 --- a/man/box_func_import_count_linter.Rd +++ b/man/box_func_import_count_linter.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/box_linters.R \name{box_func_import_count_linter} \alias{box_func_import_count_linter} -\title{Box library function import count linter} +\title{\code{box} library function import count linter} \usage{ box_func_import_count_linter(max = 8L) } @@ -18,23 +18,23 @@ Checks that function imports do not exceed the defined \code{max}. \examples{ # will produce lints lintr::lint( - text = "box::use(package[one, two, three, four, five, six, ])", + text = "box::use(package[one, two, three, four, five, six, seven, eight, nine])", linters = box_func_import_count_linter() ) lintr::lint( - text = "box::use(package[one, two, three, four, ])", + text = "box::use(package[one, two, three, four])", linters = box_func_import_count_linter(3) ) # okay lintr::lint( - text = "box::use(package[one, two, three, four, five, ])", + text = "box::use(package[one, two, three, four, five])", linters = box_func_import_count_linter() ) lintr::lint( - text = "box::use(package[one, two, three, ])", + text = "box::use(package[one, two, three])", linters = box_func_import_count_linter(3) )