Skip to content

Commit 0fbe4d4

Browse files
committed
feat: detect missing NS
1 parent b3d62d2 commit 0fbe4d4

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export(browser_button)
3737
export(browser_dev)
3838
export(bundle_resources)
3939
export(cat_dev)
40+
export(check_namespace_sanity)
4041
export(create_golem)
4142
export(css_template)
4243
export(detach_all_attached)
@@ -121,6 +122,7 @@ importFrom(tools,file_ext)
121122
importFrom(utils,capture.output)
122123
importFrom(utils,file.edit)
123124
importFrom(utils,getFromNamespace)
125+
importFrom(utils,getParseData)
124126
importFrom(utils,menu)
125127
importFrom(utils,modifyList)
126128
importFrom(utils,person)

R/find_missing_ns.R

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#' @noRd
2+
stop_quietly <- function() {
3+
opt <- options(show.error.messages = FALSE)
4+
on.exit(options(opt))
5+
stop()
6+
}
7+
8+
#' @noRd
9+
is_shiny_input_output_funmodule <- function(
10+
text,
11+
extend_input_output_funmodule = NA_character_
12+
) {
13+
stopifnot(is.character(extend_input_output_funmodule))
14+
15+
input_output_knew <- c("Input|Output|actionButton|radioButtons")
16+
ui_funmodule_pattern <- c("mod_\\w+_ui")
17+
18+
patterns <- paste(
19+
input_output_knew,
20+
ui_funmodule_pattern,
21+
sep = "|"
22+
)
23+
24+
if (
25+
!is.null(extend_input_output_funmodule) ||
26+
!is.na(extend_input_output_funmodule) ||
27+
extend_input_output_funmodule == ""
28+
) {
29+
patterns <- paste(
30+
patterns,
31+
extend_input_output_funmodule,
32+
sep = "|"
33+
)
34+
}
35+
36+
grepl(
37+
pattern = patterns,
38+
x = text
39+
)
40+
}
41+
42+
#' @noRd
43+
#' @importFrom utils getParseData
44+
check_namespace_in_file <- function(
45+
path,
46+
extend_input_output_funmodule = NA_character_
47+
) {
48+
getParseData(
49+
parse(
50+
file = path,
51+
keep.source = TRUE
52+
)
53+
) |>
54+
dplyr::mutate(
55+
path = path
56+
) |>
57+
dplyr::filter(
58+
token == "SYMBOL_FUNCTION_CALL"
59+
) |>
60+
dplyr::mutate(
61+
is_input_output_funmodule = is_shiny_input_output_funmodule(
62+
text = text,
63+
extend_input_output_funmodule = extend_input_output_funmodule
64+
)
65+
) |>
66+
dplyr::mutate(
67+
is_followed_by = dplyr::lead(text),
68+
is_followed_by_ns = is_followed_by == "ns"
69+
) |>
70+
dplyr::filter(
71+
is_input_output_funmodule
72+
)
73+
}
74+
75+
#' @export
76+
check_namespace_sanity <- function(
77+
pkg = golem::get_golem_wd(),
78+
extend_input_output_funmodule = NA_character_,
79+
disable = FALSE
80+
) {
81+
if (disable) {
82+
return(invisible(FALSE))
83+
}
84+
85+
base_path <- normalizePath(
86+
path = pkg,
87+
mustWork = TRUE
88+
)
89+
90+
if (!requireNamespace("desc", quietly = TRUE)) {
91+
check_desc_installed()
92+
}
93+
94+
encoding <- desc::desc_get("Encoding", file = base_path)[[1]]
95+
96+
if (!identical(encoding, "UTF-8")) {
97+
warning("roxygen2 requires Encoding: UTF-8", call. = FALSE)
98+
}
99+
100+
blocks <- roxygen2::parse_package(
101+
path = ".",
102+
env = NULL
103+
)
104+
105+
shinymodule_blocks <- blocks |>
106+
purrr::map(
107+
.f = \(x) {
108+
return <- roxygen2::block_get_tag(x, tag = "shinyModule")
109+
if (is.null(return)) {
110+
NULL
111+
} else {
112+
return
113+
}
114+
}
115+
) |>
116+
purrr::compact()
117+
118+
if (length(shinymodule_blocks) == 0) {
119+
cli::cli_alert_info("ok")
120+
return(invisible(FALSE))
121+
}
122+
123+
shinymodule_links <- shinymodule_blocks |>
124+
purrr::map_chr(
125+
.f = ~ .x[["file"]]
126+
) |>
127+
unique()
128+
129+
data <- shinymodule_links |>
130+
purrr::map_df(
131+
.f = ~ check_namespace_in_file(
132+
path = .x,
133+
extend_input_output_funmodule = extend_input_output_funmodule
134+
)
135+
) |>
136+
dplyr::filter(
137+
!is_followed_by_ns
138+
) |>
139+
dplyr::select(
140+
path,
141+
text,
142+
line1,
143+
col1,
144+
is_followed_by,
145+
is_followed_by_ns
146+
) |>
147+
dplyr::mutate(
148+
message = sprintf("... see line %d in {.file %s:%d:%d}.", line1, path, line1, col1)
149+
)
150+
151+
missing_ns_detected <- nrow(data)
152+
153+
cli::cli_text(
154+
"It seems that ",
155+
cli::bg_br_yellow(
156+
"{missing_ns_detected} namespace{?s} (NS) {?is/are} missing..."
157+
)
158+
)
159+
160+
cli::cli_alert_info("Fix {?this/these} {missing_ns_detected} missing namespace{?s} before to continue...")
161+
162+
purrr::walk(data$message, cli::cli_alert_danger)
163+
164+
launch_app <- yesno::yesno("Is it fixed? Do you want to launch the app?")
165+
166+
if (isFALSE(launch_app)) {
167+
stop_quietly()
168+
}
169+
170+
return(TRUE)
171+
}

0 commit comments

Comments
 (0)