Skip to content

Commit 4d76e82

Browse files
schloerkeclaude
andauthored
chore: 2026 upkeep (#182)
* chore: 2026 upkeep (#180) Addresses the 2026 upkeep checklist from usethis::use_tidy_upkeep_issue(). * Add tidy GitHub labels * Add Code of Conduct (use_tidy_coc) * Add lifecycle infrastructure; deprecate export(verbose=) with lifecycle * Add rlang standalone types-check; replace stop() with cli::cli_abort() * Delegate assert_nzchar_string() to rlang::check_string() * Replace hand-rolled check in assets_remove() with check_character() * Add Air formatter config (air.toml) and format-r-code: true in GHA routine job * Fix broken URL in README.md (shinylive Python docs link) * Add class= to unclassed expect_error() calls in tests * Add assertion unit tests (27 tests) * Fix R CMD check NOTEs: missing rlang imports, spelling wordlist, .Rbuildignore * Run use_tidy_description() * Update .Rbuildignore for .context and .git (worktree support) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: Remove standalone types-check, simplify assertion helpers Remove heavy rlang standalone files (import-standalone-types-check.R, import-standalone-obj-type.R) and replace with simple inline checks. Remove unused rlang imports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * `air format` (GitHub Actions) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: schloerke <schloerke@users.noreply.github.com>
1 parent 90bada2 commit 4d76e82

23 files changed

+477
-49
lines changed

.Rbuildignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@
2020
^node_modules$
2121
^[.]?air[.]toml$
2222
^\.vscode$
23+
^\.context$
24+
^\.git$

.github/CODE_OF_CONDUCT.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
We as members, contributors, and leaders pledge to make participation in our
6+
community a harassment-free experience for everyone, regardless of age, body
7+
size, visible or invisible disability, ethnicity, sex characteristics, gender
8+
identity and expression, level of experience, education, socio-economic status,
9+
nationality, personal appearance, race, caste, color, religion, or sexual
10+
identity and orientation.
11+
12+
We pledge to act and interact in ways that contribute to an open, welcoming,
13+
diverse, inclusive, and healthy community.
14+
15+
## Our Standards
16+
17+
Examples of behavior that contributes to a positive environment for our
18+
community include:
19+
20+
* Demonstrating empathy and kindness toward other people
21+
* Being respectful of differing opinions, viewpoints, and experiences
22+
* Giving and gracefully accepting constructive feedback
23+
* Accepting responsibility and apologizing to those affected by our mistakes,
24+
and learning from the experience
25+
* Focusing on what is best not just for us as individuals, but for the overall
26+
community
27+
28+
Examples of unacceptable behavior include:
29+
30+
* The use of sexualized language or imagery, and sexual attention or advances of
31+
any kind
32+
* Trolling, insulting or derogatory comments, and personal or political attacks
33+
* Public or private harassment
34+
* Publishing others' private information, such as a physical or email address,
35+
without their explicit permission
36+
* Other conduct which could reasonably be considered inappropriate in a
37+
professional setting
38+
39+
## Enforcement Responsibilities
40+
41+
Community leaders are responsible for clarifying and enforcing our standards of
42+
acceptable behavior and will take appropriate and fair corrective action in
43+
response to any behavior that they deem inappropriate, threatening, offensive,
44+
or harmful.
45+
46+
Community leaders have the right and responsibility to remove, edit, or reject
47+
comments, commits, code, wiki edits, issues, and other contributions that are
48+
not aligned to this Code of Conduct, and will communicate reasons for moderation
49+
decisions when appropriate.
50+
51+
## Scope
52+
53+
This Code of Conduct applies within all community spaces, and also applies when
54+
an individual is officially representing the community in public spaces.
55+
Examples of representing our community include using an official e-mail address,
56+
posting via an official social media account, or acting as an appointed
57+
representative at an online or offline event.
58+
59+
## Enforcement
60+
61+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
62+
reported to the community leaders responsible for enforcement at codeofconduct@posit.co.
63+
All complaints will be reviewed and investigated promptly and fairly.
64+
65+
All community leaders are obligated to respect the privacy and security of the
66+
reporter of any incident.
67+
68+
## Enforcement Guidelines
69+
70+
Community leaders will follow these Community Impact Guidelines in determining
71+
the consequences for any action they deem in violation of this Code of Conduct:
72+
73+
### 1. Correction
74+
75+
**Community Impact**: Use of inappropriate language or other behavior deemed
76+
unprofessional or unwelcome in the community.
77+
78+
**Consequence**: A private, written warning from community leaders, providing
79+
clarity around the nature of the violation and an explanation of why the
80+
behavior was inappropriate. A public apology may be requested.
81+
82+
### 2. Warning
83+
84+
**Community Impact**: A violation through a single incident or series of
85+
actions.
86+
87+
**Consequence**: A warning with consequences for continued behavior. No
88+
interaction with the people involved, including unsolicited interaction with
89+
those enforcing the Code of Conduct, for a specified period of time. This
90+
includes avoiding interactions in community spaces as well as external channels
91+
like social media. Violating these terms may lead to a temporary or permanent
92+
ban.
93+
94+
### 3. Temporary Ban
95+
96+
**Community Impact**: A serious violation of community standards, including
97+
sustained inappropriate behavior.
98+
99+
**Consequence**: A temporary ban from any sort of interaction or public
100+
communication with the community for a specified period of time. No public or
101+
private interaction with the people involved, including unsolicited interaction
102+
with those enforcing the Code of Conduct, is allowed during this period.
103+
Violating these terms may lead to a permanent ban.
104+
105+
### 4. Permanent Ban
106+
107+
**Community Impact**: Demonstrating a pattern of violation of community
108+
standards, including sustained inappropriate behavior, harassment of an
109+
individual, or aggression toward or disparagement of classes of individuals.
110+
111+
**Consequence**: A permanent ban from any sort of public interaction within the
112+
community.
113+
114+
## Attribution
115+
116+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
117+
version 2.1, available at
118+
<https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
119+
120+
Community Impact Guidelines were inspired by
121+
[Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion].
122+
123+
For answers to common questions about this code of conduct, see the FAQ at
124+
<https://www.contributor-covenant.org/faq>. Translations are available at <https://www.contributor-covenant.org/translations>.
125+
126+
[homepage]: https://www.contributor-covenant.org

.github/workflows/R-CMD-check.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ jobs:
1717
uses: rstudio/shiny-workflows/.github/workflows/website.yaml@v1
1818
routine:
1919
uses: rstudio/shiny-workflows/.github/workflows/routine.yaml@v1
20+
with:
21+
format-r-code: true
2022
R-CMD-check:
2123
uses: rstudio/shiny-workflows/.github/workflows/R-CMD-check.yaml@v1
2224

DESCRIPTION

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ Imports:
3434
glue,
3535
httr2 (>= 1.0.0),
3636
jsonlite,
37+
lifecycle,
3738
pkgdepends,
3839
rappdirs,
3940
renv,
40-
rlang,
41+
rlang (>= 1.1.0),
4142
tools,
4243
whisker,
4344
withr
@@ -48,6 +49,7 @@ Suggests:
4849
testthat (>= 3.0.0)
4950
Config/Needs/website: tidyverse/tidytemplate
5051
Config/testthat/edition: 3
52+
Config/usethis/last-upkeep: 2026-03-30
5153
Encoding: UTF-8
5254
Language: en-US
5355
Roxygen: list(markdown = TRUE)

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export(assets_install_link)
99
export(assets_remove)
1010
export(assets_version)
1111
export(export)
12+
importFrom(lifecycle,deprecated)
1213
importFrom(rlang,"%||%")
1314
importFrom(rlang,is_interactive)

R/app_json.R

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ file_content_obj <- function(name, content, type = c("text", "binary")) {
1313

1414
APP_INFO_CLASS <- "shinylive_app_info"
1515
app_info_obj <- function(appdir, subdir, files) {
16-
stopifnot(inherits(files, "list"))
17-
lapply(files, function(file) {
18-
stopifnot(inherits(file, FILE_CONTENT_CLASS))
19-
})
16+
assert_list(files, arg = "files")
17+
assert_list_items(files, FILE_CONTENT_CLASS, arg = "files")
2018
structure(
2119
list(
2220
appdir = appdir,
@@ -66,7 +64,11 @@ read_app_files <- function(
6664
}
6765

6866
inspect_dir <- function(curdur) {
69-
stopifnot(fs::is_dir(curdur))
67+
if (!fs::is_dir(curdur)) {
68+
cli::cli_abort(
69+
"{.arg curdur} must be an existing directory: {.path {curdur}}"
70+
)
71+
}
7072

7173
# Check for excluded dirs
7274
curdur_basename <- basename(curdur)
@@ -161,9 +163,15 @@ write_app_json <- function(
161163
) {
162164
local_quiet(quiet)
163165

164-
stopifnot(inherits(app_info, APP_INFO_CLASS))
166+
if (!inherits(app_info, APP_INFO_CLASS)) {
167+
cli::cli_abort("{.arg app_info} must be a {.cls {APP_INFO_CLASS}} object.")
168+
}
165169
# stopifnot(fs::dir_exists(destdir))
166-
stopifnot(fs::dir_exists(template_dir))
170+
if (!fs::dir_exists(template_dir)) {
171+
cli::cli_abort(
172+
"{.arg template_dir} must be an existing directory: {.path {template_dir}}"
173+
)
174+
}
167175

168176
app_destdir <- fs::path(destdir, app_info$subdir)
169177

R/assets.R

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ assets_dir_impl <- function(
9696
dir = assets_cache_dir(),
9797
version = assets_version()
9898
) {
99-
stopifnot(length(list(...)) == 0)
99+
rlang::check_dots_empty()
100100
fs::path(dir, paste0(shinylive_prefix, version))
101101
}
102102

@@ -108,8 +108,12 @@ install_local_helper <- function(
108108
dir = assets_cache_dir(),
109109
version = package_json_version(assets_repo_dir)
110110
) {
111-
stopifnot(length(list(...)) == 0)
112-
stopifnot(fs::dir_exists(assets_repo_dir))
111+
rlang::check_dots_empty()
112+
if (!fs::dir_exists(assets_repo_dir)) {
113+
cli::cli_abort(
114+
"Assets repo directory does not exist: {.path {assets_repo_dir}}"
115+
)
116+
}
113117
repo_build_dir <- fs::path(assets_repo_dir, "build")
114118
if (!fs::dir_exists(repo_build_dir)) {
115119
cli::cli_abort(c(
@@ -208,7 +212,7 @@ assets_ensure <- function(
208212
dir = assets_cache_dir(),
209213
url = assets_bundle_url(version)
210214
) {
211-
stopifnot(length(list(...)) == 0)
215+
rlang::check_dots_empty()
212216
if (!fs::dir_exists(dir)) {
213217
cli_alert_info("Creating assets cache directory ", dir)
214218
fs::dir_create(dir)
@@ -241,7 +245,7 @@ assets_cleanup <- function(
241245
...,
242246
dir = assets_cache_dir()
243247
) {
244-
stopifnot(length(list(...)) == 0)
248+
rlang::check_dots_empty()
245249
versions <- vapply(
246250
assets_dirs(dir = dir),
247251
function(ver_path) {
@@ -283,8 +287,10 @@ assets_remove <- function(
283287
...,
284288
dir = assets_cache_dir()
285289
) {
286-
stopifnot(length(list(...)) == 0)
287-
stopifnot(length(versions) > 0 && is.character(versions))
290+
rlang::check_dots_empty()
291+
if (!is.character(versions) || length(versions) == 0) {
292+
cli::cli_abort("{.arg versions} must be a non-empty character vector.")
293+
}
288294

289295
lapply(versions, function(version) {
290296
target_dir <- assets_dir_impl(dir = dir, version = version)
@@ -304,7 +310,7 @@ assets_dirs <- function(
304310
...,
305311
dir = assets_cache_dir()
306312
) {
307-
stopifnot(length(list(...)) == 0)
313+
rlang::check_dots_empty()
308314
if (!fs::dir_exists(dir)) {
309315
return(character(0))
310316
}

R/deps.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ html_dep_obj <- function(
55
path,
66
attribs = NULL
77
) {
8-
stopifnot(length(list(...)) == 0)
8+
rlang::check_dots_empty()
99
assert_nzchar_string(name)
1010
assert_nzchar_string(path)
1111
is.null(attribs) || assert_list(attribs)
@@ -28,7 +28,7 @@ html_dep_serviceworker_obj <- function(
2828
source,
2929
destination
3030
) {
31-
stopifnot(length(list(...)) == 0)
31+
rlang::check_dots_empty()
3232
assert_nzchar_string(source)
3333
assert_nzchar_string(destination)
3434
structure(
@@ -52,7 +52,7 @@ quarto_html_dependency_obj <- function(
5252
head = NULL,
5353
serviceworkers = NULL
5454
) {
55-
stopifnot(length(list(...)) == 0)
55+
rlang::check_dots_empty()
5656
assert_nzchar_string(name)
5757
is.null(version) || assert_nzchar_string(version)
5858
is.null(scripts) || assert_list_items(scripts, HTML_DEP_ITEM_CLASS)

R/export.R

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#' @param quiet Suppress console output during export. Follows the global
1010
#' `shinylive.quiet` option or defaults to `FALSE` in interactive sessions if
1111
#' not set.
12-
#' @param verbose Deprecated, please use `quiet` instead.
12+
#' @param verbose `r lifecycle::badge('deprecated')` Use `quiet` instead.
1313
#' @param wasm_packages Download and include binary WebAssembly packages as part
1414
#' of the output app's static assets. Logical, defaults to `TRUE`. The default
1515
#' value can be changed by setting the environment variable
@@ -70,12 +70,10 @@ export <- function(
7070
assets_version = NULL,
7171
template_dir = NULL,
7272
template_params = list(),
73-
verbose = NULL
73+
verbose = deprecated()
7474
) {
75-
if (!is.null(verbose)) {
76-
rlang::warn(
77-
"The {.var verbose} argument is deprecated. Use {.var quiet} instead."
78-
)
75+
if (!missing(verbose)) {
76+
lifecycle::deprecate_warn("0.2.0", "export(verbose)", "export(quiet)")
7977
if (missing(quiet)) {
8078
quiet <- !verbose
8179
}

R/quarto_ext.R

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,11 @@ quarto_ext <- function(
115115
pretty = is_interactive(),
116116
con = "stdin"
117117
) {
118-
stopifnot(length(list(...)) == 0)
118+
rlang::check_dots_empty()
119119
# This method should not print anything to stdout. Instead, it should return a JSON string that will be printed by the extension.
120-
stopifnot(length(args) >= 1)
120+
if (length(args) < 1) {
121+
cli::cli_abort("{.arg args} must have at least one element.")
122+
}
121123

122124
followup_statement <- function() {
123125
c(
@@ -180,7 +182,6 @@ quarto_ext <- function(
180182
followup_statement()
181183
))
182184
}
183-
stopifnot(length(args) >= 2)
184185

185186
ret <- switch(
186187
args[2],
@@ -197,11 +198,11 @@ quarto_ext <- function(
197198
sw_dir_pos <- which(args == "--sw-dir")
198199
if (length(sw_dir_pos) == 1) {
199200
if (sw_dir_pos == length(args)) {
200-
stop("expected `--sw-dir` argument value")
201+
cli::cli_abort("Expected {.arg --sw-dir} argument value.")
201202
}
202203
sw_dir <- args[sw_dir_pos + 1]
203204
} else {
204-
stop("expected `--sw-dir` argument")
205+
cli::cli_abort("Expected {.arg --sw-dir} argument.")
205206
}
206207
# Language agnostic files
207208
shinylive_base_deps_htmldep(sw_dir)
@@ -215,7 +216,7 @@ quarto_ext <- function(
215216
build_app_resources(app_json)
216217
},
217218
{
218-
stop("Not implemented `extension` type: ", args[2])
219+
cli::cli_abort("Not implemented {.arg extension} type: {.val {args[2]}}.")
219220
}
220221
)
221222
ret_null_free <- drop_nulls_rec(ret)

0 commit comments

Comments
 (0)