mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-11 07:58:11 -05:00
Compare commits
21 Commits
add-client
...
fix/bindin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42b6b8bdde | ||
|
|
4a01dde46b | ||
|
|
6c281f377c | ||
|
|
33d6686223 | ||
|
|
20b2669e76 | ||
|
|
db123a1508 | ||
|
|
0952f3e0a7 | ||
|
|
13ca8dfc57 | ||
|
|
79f42f5846 | ||
|
|
9a35b01e23 | ||
|
|
5bf0701939 | ||
|
|
e5083f4938 | ||
|
|
ce6a562a3c | ||
|
|
b6bcfc8683 | ||
|
|
d37beeece7 | ||
|
|
79ee25620f | ||
|
|
82c678a1eb | ||
|
|
458924569a | ||
|
|
501b012b2b | ||
|
|
ee1aac847a | ||
|
|
7785a76a67 |
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"arcanis.vscode-zipfs",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Package: shiny
|
||||
Type: Package
|
||||
Title: Web Application Framework for R
|
||||
Version: 1.9.1.9000
|
||||
Version: 1.10.0.9000
|
||||
Authors@R: c(
|
||||
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@posit.co", comment = c(ORCID = "0000-0002-1576-2126")),
|
||||
person("Joe", "Cheng", role = "aut", email = "joe@posit.co"),
|
||||
@@ -83,7 +83,7 @@ Imports:
|
||||
R6 (>= 2.0),
|
||||
sourcetools,
|
||||
later (>= 1.0.0),
|
||||
promises (>= 1.1.0),
|
||||
promises (>= 1.3.2),
|
||||
tools,
|
||||
crayon,
|
||||
rlang (>= 0.4.10),
|
||||
@@ -95,6 +95,7 @@ Imports:
|
||||
cachem (>= 1.1.0),
|
||||
lifecycle (>= 0.2.0)
|
||||
Suggests:
|
||||
coro (>= 1.1.0),
|
||||
datasets,
|
||||
DT,
|
||||
Cairo (>= 1.5-5),
|
||||
|
||||
36
NEWS.md
36
NEWS.md
@@ -1,10 +1,20 @@
|
||||
# shiny (development version)
|
||||
|
||||
## Bug fixes
|
||||
|
||||
* Fixed a bug with modals where calling `removeModal()` too quickly after `showModal()` would fail to remove the modal if the remove modal message was received while the modal was in the process of being revealed. (#4173)
|
||||
|
||||
# shiny 1.10.0
|
||||
|
||||
## New features and improvements
|
||||
|
||||
* Small improvements to the default pulse busy indicator to better blend with any background. It's also now slightly smaller by default. (#4122)
|
||||
* When busy indicators are enabled (i.e., `useBusyIndicators()` is in the UI), Shiny now:
|
||||
* Shows the pulse indicator when dynamic UI elements are recalculating and no other spinners are visible in the app. (#4137)
|
||||
* Makes the pulse indicator slightly smaller by default and improves its appearance to better blend with any background. (#4122)
|
||||
|
||||
* When spinners and the pulse busy indicators are enabled, Shiny now shows the pulse indicator when dynamic UI elements are recalculating if no other spinners are present in the app. (#4137)
|
||||
* Improve collection of deep stack traces (stack traces that are tracked across steps in an async promise chain) with `{coro}` async generators such as `{elmer}` chat streams. Previously, Shiny treated each iteration of an async generator as a distinct deep stack, leading to pathologically long stack traces; now, Shiny only keeps/prints unique deep stack trace, discarding duplicates. (#4156)
|
||||
|
||||
* Added an example to the `ExtendedTask` documentation. (@daattali #4087)
|
||||
|
||||
## Bug fixes
|
||||
|
||||
@@ -12,9 +22,17 @@
|
||||
|
||||
* Fixed a bug with `sliderInput()` when used as a range slider that made it impossible to change the slider value when both handles were at the maximum value. (#4131)
|
||||
|
||||
* `dateInput` and `dateRangeInput` no longer send immediate updates to the server when the user is typing a date input. Instead, it waits until the user presses Enter or clicks out of the field to send the update, avoiding spurious and incorrect date values. Note that an update is still sent immediately when the field is cleared. (#3664)
|
||||
* `dateInput()` and `dateRangeInput()` no longer send immediate updates to the server when the user is typing a date input. Instead, it waits until the user presses Enter or clicks out of the field to send the update, avoiding spurious and incorrect date values. Note that an update is still sent immediately when the field is cleared. (#3664)
|
||||
|
||||
* Fixed a bug in `onBookmark` hook that caused elements to not be excluded from URL bookmarking. (#3762)
|
||||
* Fixed a bug in `onBookmark()` hook that caused elements to not be excluded from URL bookmarking. (#3762)
|
||||
|
||||
* Fixed a bug with stack trace capturing that caused reactives with very long async promise chains (hundreds/thousands of steps) to become extremely slow. Chains this long are unlikely to be written by hand, but `{coro}` async generators and `{elmer}` async streaming were easily creating problematically long chains. (#4155)
|
||||
|
||||
* Duplicate input and output IDs -- e.g. using `"debug"` for two inputs or two outputs -- or shared IDs -- e.g. using `"debug"` as the `inputId` for an input and an output -- now result in a console warning message, but not an error. When `devmode()` is enabled, an informative message is shown in the Shiny Client Console. We recommend all Shiny devs enable `devmode()` when developing Shiny apps locally. (#4101)
|
||||
|
||||
* Updating the choices of a `selectizeInput()` via `updateSelectizeInput()` with `server = TRUE` no longer retains the selected choice as a deselected option if the current value is not part of the new choices. (@dvg-p4 #4142)
|
||||
|
||||
* Fixed a bug where stack traces from `observeEvent()` were being stripped of stack frames too aggressively. (#4163)
|
||||
|
||||
# shiny 1.9.1
|
||||
|
||||
@@ -1038,7 +1056,7 @@ Shiny can now display notifications on the client browser by using the `showNoti
|
||||
<img src="http://shiny.rstudio.com/images/notification.png" alt="notification" width="50%"/>
|
||||
</p>
|
||||
|
||||
[Here](https://shiny.rstudio.com/articles/notifications.html)'s our article about it, and the [reference documentation](https://shiny.rstudio.com/reference/shiny/latest/showNotification.html).
|
||||
[Here](https://shiny.rstudio.com/articles/notifications.html)'s our article about it, and the [reference documentation](https://shiny.posit.co/r/reference/shiny/latest/shownotification.html).
|
||||
|
||||
## Progress indicators
|
||||
|
||||
@@ -1047,7 +1065,7 @@ If your Shiny app contains computations that take a long time to complete, a pro
|
||||
**_Important note_:**
|
||||
> If you were already using progress bars and had customized them with your own CSS, you can add the `style = "old"` argument to your `withProgress()` call (or `Progress$new()`). This will result in the same appearance as before. You can also call `shinyOptions(progress.style = "old")` in your app's server function to make all progress indicators use the old styling.
|
||||
|
||||
To see new progress bars in action, see [this app](https://gallery.shinyapps.io/085-progress/) in the gallery. You can also learn more about this in [our article](https://shiny.rstudio.com/articles/progress.html) and in the reference documentation (either for the easier [`withProgress` functional API](https://shiny.rstudio.com/reference/shiny/latest/withProgress.html) or the more complicated, but more powerful, [`Progress` object-oriented API](https://shiny.rstudio.com/reference/shiny/latest/Progress.html).
|
||||
To see new progress bars in action, see [this app](https://gallery.shinyapps.io/085-progress/) in the gallery. You can also learn more about this in [our article](https://shiny.rstudio.com/articles/progress.html) and in the reference documentation (either for the easier [`withProgress` functional API](https://shiny.posit.co/r/reference/shiny/latest/withprogress.html) or the more complicated, but more powerful, [`Progress` object-oriented API](https://shiny.posit.co/r/reference/shiny/latest/progress.html).
|
||||
|
||||
## Reconnection
|
||||
|
||||
@@ -1061,7 +1079,7 @@ Shiny has now built-in support for displaying modal dialogs like the one below (
|
||||
<img src="http://shiny.rstudio.com/images/modal-dialog.png" alt="modal-dialog" width="50%"/>
|
||||
</p>
|
||||
|
||||
To learn more about this, read [our article](https://shiny.rstudio.com/articles/modal-dialogs.html) and the [reference documentation](https://shiny.rstudio.com/reference/shiny/latest/modalDialog.html).
|
||||
To learn more about this, read [our article](https://shiny.rstudio.com/articles/modal-dialogs.html) and the [reference documentation](https://shiny.posit.co/r/reference/shiny/latest/modaldialog.html).
|
||||
|
||||
## `insertUI` and `removeUI`
|
||||
|
||||
@@ -1069,7 +1087,7 @@ Sometimes in a Shiny app, arbitrary HTML UI may need to be created on-the-fly in
|
||||
|
||||
See [this simple demo app](https://gallery.shinyapps.io/111-insert-ui/) of how one could use `insertUI` and `removeUI` to insert and remove text elements using a queue. Also see [this other app](https://gallery.shinyapps.io/insertUI/) that demonstrates how to insert and remove a few common Shiny input objects. Finally, [this app](https://gallery.shinyapps.io/insertUI-modules/) shows how to dynamically insert modules using `insertUI`.
|
||||
|
||||
For more, read [our article](https://shiny.rstudio.com/articles/dynamic-ui.html) about dynamic UI generation and the reference documentation about [`insertUI`](https://shiny.rstudio.com/reference/shiny/latest/insertUI.html) and [`removeUI`](https://shiny.rstudio.com/reference/shiny/latest/insertUI.html).
|
||||
For more, read [our article](https://shiny.rstudio.com/articles/dynamic-ui.html) about dynamic UI generation and the reference documentation about [`insertUI`](https://shiny.posit.co/r/reference/shiny/latest/insertui.html) and [`removeUI`](https://shiny.posit.co/r/reference/shiny/latest/insertui.html).
|
||||
|
||||
## Documentation for connecting to an external database
|
||||
|
||||
@@ -1103,7 +1121,7 @@ There are many more minor features, small improvements, and bug fixes than we ca
|
||||
<img src="http://shiny.rstudio.com/images/render-table.png" alt="render-table" width="75%"/>
|
||||
</p>
|
||||
|
||||
For more, read our [short article](https://shiny.rstudio.com/articles/render-table.html) about this update, experiment with all the new features in this [demo app](https://gallery.shinyapps.io/109-render-table/), or check out the [reference documentation](https://shiny.rstudio.com/reference/shiny/latest/renderTable.html).
|
||||
For more, read our [short article](https://shiny.rstudio.com/articles/render-table.html) about this update, experiment with all the new features in this [demo app](https://gallery.shinyapps.io/109-render-table/), or check out the [reference documentation](https://shiny.posit.co/r/reference/shiny/latest/rendertable.html).
|
||||
|
||||
## Full changelog
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ utils::globalVariables(".GenericCallEnv", add = TRUE)
|
||||
#' cache by putting this at the top of your app.R, server.R, or global.R:
|
||||
#'
|
||||
#' ```
|
||||
#' shinyOptions(cache = cachem::cache_disk(file.path(dirname(tempdir()), "myapp-cache"))
|
||||
#' shinyOptions(cache = cachem::cache_disk(file.path(dirname(tempdir()), "myapp-cache")))
|
||||
#' ```
|
||||
#'
|
||||
#' This will create a subdirectory in your system temp directory named
|
||||
|
||||
239
R/conditions.R
239
R/conditions.R
@@ -130,6 +130,44 @@ captureStackTraces <- function(expr) {
|
||||
#' @include globals.R
|
||||
.globals$deepStack <- NULL
|
||||
|
||||
getCallStackDigest <- function(callStack, warn = FALSE) {
|
||||
dg <- attr(callStack, "shiny.stack.digest", exact = TRUE)
|
||||
if (!is.null(dg)) {
|
||||
return(dg)
|
||||
}
|
||||
|
||||
if (isTRUE(warn)) {
|
||||
rlang::warn(
|
||||
"Call stack doesn't have a cached digest; expensively computing one now",
|
||||
.frequency = "once",
|
||||
.frequency_id = "deepstack-uncached-digest-warning"
|
||||
)
|
||||
}
|
||||
|
||||
rlang::hash(getCallNames(callStack))
|
||||
}
|
||||
|
||||
saveCallStackDigest <- function(callStack) {
|
||||
attr(callStack, "shiny.stack.digest") <- getCallStackDigest(callStack, warn = FALSE)
|
||||
callStack
|
||||
}
|
||||
|
||||
# Appends a call stack to a list of call stacks, but only if it's not already
|
||||
# in the list. The list is deduplicated by digest; ideally the digests on the
|
||||
# list are cached before calling this function (you will get a warning if not).
|
||||
appendCallStackWithDedupe <- function(lst, x) {
|
||||
digests <- vapply(lst, getCallStackDigest, character(1), warn = TRUE)
|
||||
xdigest <- getCallStackDigest(x, warn = TRUE)
|
||||
stopifnot(all(nzchar(digests)))
|
||||
stopifnot(length(xdigest) == 1)
|
||||
stopifnot(nzchar(xdigest))
|
||||
if (xdigest %in% digests) {
|
||||
return(lst)
|
||||
} else {
|
||||
return(c(lst, list(x)))
|
||||
}
|
||||
}
|
||||
|
||||
createStackTracePromiseDomain <- function() {
|
||||
# These are actually stateless, we wouldn't have to create a new one each time
|
||||
# if we didn't want to. They're pretty cheap though.
|
||||
@@ -142,13 +180,14 @@ createStackTracePromiseDomain <- function() {
|
||||
currentStack <- sys.calls()
|
||||
currentParents <- sys.parents()
|
||||
attr(currentStack, "parents") <- currentParents
|
||||
currentStack <- saveCallStackDigest(currentStack)
|
||||
currentDeepStack <- .globals$deepStack
|
||||
}
|
||||
function(...) {
|
||||
# Fulfill time
|
||||
if (deepStacksEnabled()) {
|
||||
origDeepStack <- .globals$deepStack
|
||||
.globals$deepStack <- c(currentDeepStack, list(currentStack))
|
||||
.globals$deepStack <- appendCallStackWithDedupe(currentDeepStack, currentStack)
|
||||
on.exit(.globals$deepStack <- origDeepStack, add = TRUE)
|
||||
}
|
||||
|
||||
@@ -165,13 +204,14 @@ createStackTracePromiseDomain <- function() {
|
||||
currentStack <- sys.calls()
|
||||
currentParents <- sys.parents()
|
||||
attr(currentStack, "parents") <- currentParents
|
||||
currentStack <- saveCallStackDigest(currentStack)
|
||||
currentDeepStack <- .globals$deepStack
|
||||
}
|
||||
function(...) {
|
||||
# Fulfill time
|
||||
if (deepStacksEnabled()) {
|
||||
origDeepStack <- .globals$deepStack
|
||||
.globals$deepStack <- c(currentDeepStack, list(currentStack))
|
||||
.globals$deepStack <- appendCallStackWithDedupe(currentDeepStack, currentStack)
|
||||
on.exit(.globals$deepStack <- origDeepStack, add = TRUE)
|
||||
}
|
||||
|
||||
@@ -199,6 +239,7 @@ doCaptureStack <- function(e) {
|
||||
calls <- sys.calls()
|
||||
parents <- sys.parents()
|
||||
attr(calls, "parents") <- parents
|
||||
calls <- saveCallStackDigest(calls)
|
||||
attr(e, "stack.trace") <- calls
|
||||
}
|
||||
if (deepStacksEnabled()) {
|
||||
@@ -281,88 +322,115 @@ printStackTrace <- function(cond,
|
||||
full = get_devmode_option("shiny.fullstacktrace", FALSE),
|
||||
offset = getOption("shiny.stacktraceoffset", TRUE)) {
|
||||
|
||||
should_drop <- !full
|
||||
should_strip <- !full
|
||||
should_prune <- !full
|
||||
|
||||
stackTraceCalls <- c(
|
||||
stackTraces <- c(
|
||||
attr(cond, "deep.stack.trace", exact = TRUE),
|
||||
list(attr(cond, "stack.trace", exact = TRUE))
|
||||
)
|
||||
|
||||
stackTraceParents <- lapply(stackTraceCalls, attr, which = "parents", exact = TRUE)
|
||||
stackTraceCallNames <- lapply(stackTraceCalls, getCallNames)
|
||||
stackTraceCalls <- lapply(stackTraceCalls, offsetSrcrefs, offset = offset)
|
||||
|
||||
# Use dropTrivialFrames logic to remove trailing bits (.handleSimpleError, h)
|
||||
if (should_drop) {
|
||||
# toKeep is a list of logical vectors, of which elements (stack frames) to keep
|
||||
toKeep <- lapply(stackTraceCallNames, dropTrivialFrames)
|
||||
# We apply the list of logical vector indices to each data structure
|
||||
stackTraceCalls <- mapply(stackTraceCalls, FUN = `[`, toKeep, SIMPLIFY = FALSE)
|
||||
stackTraceCallNames <- mapply(stackTraceCallNames, FUN = `[`, toKeep, SIMPLIFY = FALSE)
|
||||
stackTraceParents <- mapply(stackTraceParents, FUN = `[`, toKeep, SIMPLIFY = FALSE)
|
||||
# Stripping of stack traces is the one step where the different stack traces
|
||||
# interact. So we need to do this in one go, instead of individually within
|
||||
# printOneStackTrace.
|
||||
if (!full) {
|
||||
stripResults <- stripStackTraces(lapply(stackTraces, getCallNames))
|
||||
} else {
|
||||
# If full is TRUE, we don't want to strip anything
|
||||
stripResults <- rep_len(list(TRUE), length(stackTraces))
|
||||
}
|
||||
|
||||
delayedAssign("all_true", {
|
||||
# List of logical vectors that are all TRUE, the same shape as
|
||||
# stackTraceCallNames. Delay the evaluation so we don't create it unless
|
||||
# we need it, but if we need it twice then we don't pay to create it twice.
|
||||
lapply(stackTraceCallNames, function(st) {
|
||||
rep_len(TRUE, length(st))
|
||||
})
|
||||
})
|
||||
|
||||
# stripStackTraces and lapply(stackTraceParents, pruneStackTrace) return lists
|
||||
# of logical vectors. Use mapply(FUN = `&`) to boolean-and each pair of the
|
||||
# logical vectors.
|
||||
toShow <- mapply(
|
||||
if (should_strip) stripStackTraces(stackTraceCallNames) else all_true,
|
||||
if (should_prune) lapply(stackTraceParents, pruneStackTrace) else all_true,
|
||||
FUN = `&`,
|
||||
mapply(
|
||||
seq_along(stackTraces),
|
||||
rev(stackTraces),
|
||||
rev(stripResults),
|
||||
FUN = function(i, trace, stripResult) {
|
||||
if (is.integer(trace)) {
|
||||
noun <- if (trace > 1L) "traces" else "trace"
|
||||
message("[ reached getOption(\"shiny.deepstacktrace\") -- omitted ", trace, " more stack ", noun, " ]")
|
||||
} else {
|
||||
if (i != 1) {
|
||||
message("From earlier call:")
|
||||
}
|
||||
printOneStackTrace(
|
||||
stackTrace = trace,
|
||||
stripResult = stripResult,
|
||||
full = full,
|
||||
offset = offset
|
||||
)
|
||||
}
|
||||
# No mapply return value--we're just printing
|
||||
NULL
|
||||
},
|
||||
SIMPLIFY = FALSE
|
||||
)
|
||||
|
||||
dfs <- mapply(seq_along(stackTraceCalls), rev(stackTraceCalls), rev(stackTraceCallNames), rev(toShow), FUN = function(i, calls, nms, index) {
|
||||
st <- data.frame(
|
||||
num = rev(which(index)),
|
||||
call = rev(nms[index]),
|
||||
loc = rev(getLocs(calls[index])),
|
||||
category = rev(getCallCategories(calls[index])),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
|
||||
if (i != 1) {
|
||||
message("From earlier call:")
|
||||
}
|
||||
|
||||
if (nrow(st) == 0) {
|
||||
message(" [No stack trace available]")
|
||||
} else {
|
||||
width <- floor(log10(max(st$num))) + 1
|
||||
formatted <- paste0(
|
||||
" ",
|
||||
formatC(st$num, width = width),
|
||||
": ",
|
||||
mapply(paste0(st$call, st$loc), st$category, FUN = function(name, category) {
|
||||
if (category == "pkg")
|
||||
crayon::silver(name)
|
||||
else if (category == "user")
|
||||
crayon::blue$bold(name)
|
||||
else
|
||||
crayon::white(name)
|
||||
}),
|
||||
"\n"
|
||||
)
|
||||
cat(file = stderr(), formatted, sep = "")
|
||||
}
|
||||
|
||||
st
|
||||
}, SIMPLIFY = FALSE)
|
||||
|
||||
invisible()
|
||||
}
|
||||
|
||||
printOneStackTrace <- function(stackTrace, stripResult, full, offset) {
|
||||
calls <- offsetSrcrefs(stackTrace, offset = offset)
|
||||
callNames <- getCallNames(stackTrace)
|
||||
parents <- attr(stackTrace, "parents", exact = TRUE)
|
||||
|
||||
should_drop <- !full
|
||||
should_strip <- !full
|
||||
should_prune <- !full
|
||||
|
||||
if (should_drop) {
|
||||
toKeep <- dropTrivialFrames(callNames)
|
||||
calls <- calls[toKeep]
|
||||
callNames <- callNames[toKeep]
|
||||
parents <- parents[toKeep]
|
||||
stripResult <- stripResult[toKeep]
|
||||
}
|
||||
|
||||
toShow <- rep(TRUE, length(callNames))
|
||||
if (should_prune) {
|
||||
toShow <- toShow & pruneStackTrace(parents)
|
||||
}
|
||||
if (should_strip) {
|
||||
toShow <- toShow & stripResult
|
||||
}
|
||||
|
||||
# If we're running in testthat, hide the parts of the stack trace that can
|
||||
# vary based on how testthat was launched. It's critical that this is not
|
||||
# happen at the same time as dropTrivialFrames, which happens before
|
||||
# pruneStackTrace; because dropTrivialTestFrames removes calls from the top
|
||||
# (or bottom? whichever is the oldest?) of the stack, it breaks `parents`
|
||||
# which is based on absolute indices of calls. dropTrivialFrames gets away
|
||||
# with this because it only removes calls from the opposite side of the stack.
|
||||
toShow <- toShow & dropTrivialTestFrames(callNames)
|
||||
|
||||
st <- data.frame(
|
||||
num = rev(which(toShow)),
|
||||
call = rev(callNames[toShow]),
|
||||
loc = rev(getLocs(calls[toShow])),
|
||||
category = rev(getCallCategories(calls[toShow])),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
|
||||
if (nrow(st) == 0) {
|
||||
message(" [No stack trace available]")
|
||||
} else {
|
||||
width <- floor(log10(max(st$num))) + 1
|
||||
formatted <- paste0(
|
||||
" ",
|
||||
formatC(st$num, width = width),
|
||||
": ",
|
||||
mapply(paste0(st$call, st$loc), st$category, FUN = function(name, category) {
|
||||
if (category == "pkg")
|
||||
crayon::silver(name)
|
||||
else if (category == "user")
|
||||
crayon::blue$bold(name)
|
||||
else
|
||||
crayon::white(name)
|
||||
}),
|
||||
"\n"
|
||||
)
|
||||
cat(file = stderr(), formatted, sep = "")
|
||||
}
|
||||
|
||||
invisible(st)
|
||||
}
|
||||
|
||||
stripStackTraces <- function(stackTraces, values = FALSE) {
|
||||
score <- 1L # >=1: show, <=0: hide
|
||||
lapply(seq_along(stackTraces), function(i) {
|
||||
@@ -458,6 +526,33 @@ dropTrivialFrames <- function(callnames) {
|
||||
)
|
||||
}
|
||||
|
||||
dropTrivialTestFrames <- function(callnames) {
|
||||
if (!identical(Sys.getenv("TESTTHAT_IS_SNAPSHOT"), "true")) {
|
||||
return(rep_len(TRUE, length(callnames)))
|
||||
}
|
||||
|
||||
hideable <- callnames %in% c(
|
||||
"test",
|
||||
"devtools::test",
|
||||
"test_check",
|
||||
"testthat::test_check",
|
||||
"test_dir",
|
||||
"testthat::test_dir",
|
||||
"test_file",
|
||||
"testthat::test_file",
|
||||
"test_local",
|
||||
"testthat::test_local"
|
||||
)
|
||||
|
||||
firstGoodCall <- min(which(!hideable))
|
||||
toRemove <- firstGoodCall - 1L
|
||||
|
||||
c(
|
||||
rep_len(FALSE, toRemove),
|
||||
rep_len(TRUE, length(callnames) - toRemove)
|
||||
)
|
||||
}
|
||||
|
||||
offsetSrcrefs <- function(calls, offset = TRUE) {
|
||||
if (offset) {
|
||||
srcrefs <- getSrcRefs(calls)
|
||||
|
||||
@@ -41,6 +41,54 @@
|
||||
#' is, a function that quickly returns a promise) and allows even that very
|
||||
#' session to immediately unblock and carry on with other user interactions.
|
||||
#'
|
||||
#' @examplesIf rlang::is_interactive() && rlang::is_installed("future")
|
||||
#'
|
||||
#' library(shiny)
|
||||
#' library(bslib)
|
||||
#' library(future)
|
||||
#' plan(multisession)
|
||||
#'
|
||||
#' ui <- page_fluid(
|
||||
#' titlePanel("Extended Task Demo"),
|
||||
#' p(
|
||||
#' 'Click the button below to perform a "calculation"',
|
||||
#' "that takes a while to perform."
|
||||
#' ),
|
||||
#' input_task_button("recalculate", "Recalculate"),
|
||||
#' p(textOutput("result"))
|
||||
#' )
|
||||
#'
|
||||
#' server <- function(input, output) {
|
||||
#' rand_task <- ExtendedTask$new(function() {
|
||||
#' future(
|
||||
#' {
|
||||
#' # Slow operation goes here
|
||||
#' Sys.sleep(2)
|
||||
#' sample(1:100, 1)
|
||||
#' },
|
||||
#' seed = TRUE
|
||||
#' )
|
||||
#' })
|
||||
#'
|
||||
#' # Make button state reflect task.
|
||||
#' # If using R >=4.1, you can do this instead:
|
||||
#' # rand_task <- ExtendedTask$new(...) |> bind_task_button("recalculate")
|
||||
#' bind_task_button(rand_task, "recalculate")
|
||||
#'
|
||||
#' observeEvent(input$recalculate, {
|
||||
#' # Invoke the extended in an observer
|
||||
#' rand_task$invoke()
|
||||
#' })
|
||||
#'
|
||||
#' output$result <- renderText({
|
||||
#' # React to updated results when the task completes
|
||||
#' number <- rand_task$result()
|
||||
#' paste0("Your number is ", number, ".")
|
||||
#' })
|
||||
#' }
|
||||
#'
|
||||
#' shinyApp(ui, server)
|
||||
#'
|
||||
#' @export
|
||||
ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
|
||||
public = list(
|
||||
|
||||
14
R/react.R
14
R/react.R
@@ -53,10 +53,12 @@ Context <- R6Class(
|
||||
|
||||
promises::with_promise_domain(reactivePromiseDomain(), {
|
||||
withReactiveDomain(.domain, {
|
||||
env <- .getReactiveEnvironment()
|
||||
rLog$enter(.reactId, id, .reactType, .domain)
|
||||
on.exit(rLog$exit(.reactId, id, .reactType, .domain), add = TRUE)
|
||||
env$runWith(self, func)
|
||||
captureStackTraces({
|
||||
env <- .getReactiveEnvironment()
|
||||
rLog$enter(.reactId, id, .reactType, .domain)
|
||||
on.exit(rLog$exit(.reactId, id, .reactType, .domain), add = TRUE)
|
||||
env$runWith(self, func)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -223,9 +225,7 @@ wrapForContext <- function(func, ctx) {
|
||||
|
||||
function(...) {
|
||||
.getReactiveEnvironment()$runWith(ctx, function() {
|
||||
captureStackTraces(
|
||||
func(...)
|
||||
)
|
||||
func(...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2304,7 +2304,7 @@ observeEvent <- function(eventExpr, handlerExpr,
|
||||
priority = priority,
|
||||
domain = domain,
|
||||
autoDestroy = TRUE,
|
||||
..stacktraceon = FALSE # TODO: Does this go in the bindEvent?
|
||||
..stacktraceon = TRUE
|
||||
))
|
||||
|
||||
o <- inject(bindEvent(
|
||||
|
||||
@@ -445,7 +445,9 @@ stopApp <- function(returnValue = invisible()) {
|
||||
#' @param host The IPv4 address that the application should listen on. Defaults
|
||||
#' to the `shiny.host` option, if set, or `"127.0.0.1"` if not.
|
||||
#' @param display.mode The mode in which to display the example. Defaults to
|
||||
#' `showcase`, but may be set to `normal` to see the example without
|
||||
#' `"auto"`, which uses the value of `DisplayMode` in the example's
|
||||
#' `DESCRIPTION` file. Set to `"showcase"` to show the app code and
|
||||
#' description with the running app, or `"normal"` to see the example without
|
||||
#' code or commentary.
|
||||
#' @param package The package in which to find the example (defaults to
|
||||
#' `"shiny"`).
|
||||
|
||||
@@ -2024,7 +2024,7 @@ ShinySession <- R6Class(
|
||||
tmpdata <- tempfile(fileext = ext)
|
||||
return(Context$new(getDefaultReactiveDomain(), '[download]')$run(function() {
|
||||
promises::with_promise_domain(reactivePromiseDomain(), {
|
||||
promises::with_promise_domain(createStackTracePromiseDomain(), {
|
||||
captureStackTraces({
|
||||
self$incrementBusyCount()
|
||||
hybrid_chain(
|
||||
# ..stacktraceon matches with the top-level ..stacktraceoff..
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
## revdepcheck results
|
||||
|
||||
We checked 1278 reverse dependencies (1277 from CRAN + 1 from Bioconductor), comparing R CMD check results across CRAN and dev versions of shiny.
|
||||
|
||||
* We saw 2 new problems (NOTEs only)
|
||||
* We failed to check 19 packages due to installation issues
|
||||
|
||||
Issues with CRAN packages are summarised below.
|
||||
|
||||
### New problems
|
||||
|
||||
R CMD check displayed NOTEs for two packages, unrelated to changes in shiny.
|
||||
|
||||
* HH
|
||||
checking installed package size ... NOTE
|
||||
|
||||
* PopED
|
||||
checking installed package size ... NOTE
|
||||
|
||||
### Failed to check
|
||||
|
||||
* animalEKF
|
||||
* AovBay
|
||||
* Certara.VPCResults
|
||||
* chipPCR
|
||||
* ctsem
|
||||
* dartR.sim
|
||||
* diveR
|
||||
* gap
|
||||
* jsmodule
|
||||
* loon.shiny
|
||||
* robmedExtra
|
||||
* rstanarm
|
||||
* SensMap
|
||||
* Seurat
|
||||
* shinyTempSignal
|
||||
* Signac
|
||||
* statsr
|
||||
* TestAnaAPP
|
||||
* tidyvpc
|
||||
@@ -1,2 +1,2 @@
|
||||
/*! shiny 1.9.1.9000 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
:where([data-shiny-busy-spinners] .recalculating){position:relative}[data-shiny-busy-spinners] .recalculating:after{position:absolute;content:"";--_shiny-spinner-url: var(--shiny-spinner-url, url(spinners/ring.svg));--_shiny-spinner-color: var(--shiny-spinner-color, var(--bs-primary, #007bc2));--_shiny-spinner-size: var(--shiny-spinner-size, 32px);--_shiny-spinner-delay: var(--shiny-spinner-delay, 1s);background:var(--_shiny-spinner-color);width:var(--_shiny-spinner-size);height:var(--_shiny-spinner-size);inset:calc(50% - var(--_shiny-spinner-size) / 2);mask-image:var(--_shiny-spinner-url);-webkit-mask-image:var(--_shiny-spinner-url);opacity:0;animation-delay:var(--_shiny-spinner-delay);animation-name:fade-in;animation-duration:.25s;animation-fill-mode:forwards}[data-shiny-busy-spinners] .recalculating:has(>*),[data-shiny-busy-spinners] .recalculating:empty{opacity:1}[data-shiny-busy-spinners] .recalculating>*:not(.recalculating){opacity:var(--_shiny-fade-opacity);transition:opacity .25s ease var(--shiny-spinner-delay, 1s)}[data-shiny-busy-spinners] .recalculating.shiny-html-output:after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating:not(.shiny-html-output)):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(#shiny-disconnected-overlay):after{display:none}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:has(#shiny-disconnected-overlay):after{display:none}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes busy-page-pulse{0%{left:-14%;right:97%}45%{left:0%;right:14%}55%{left:14%;right:0%}to{left:97%;right:-14%}}.shiny-spinner-output-container{--shiny-spinner-size: 0px}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
/*! shiny 1.9.1.9000 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
#showcase-well{border-radius:0}.shiny-code{background-color:#fff;margin-bottom:0}.shiny-code code{font-family:Menlo,Consolas,Courier New,monospace}.shiny-code-container{margin-top:20px;clear:both}.shiny-code-container h3{display:inline;margin-right:15px}.showcase-header{font-size:16px;font-weight:400}.showcase-code-link{text-align:right;padding:15px}#showcase-app-container{vertical-align:top}#showcase-code-tabs{margin-right:15px}#showcase-code-tabs pre{border:none;line-height:1em}#showcase-code-tabs .nav,#showcase-code-tabs ul{margin-bottom:0}#showcase-code-tabs .tab-content{border-style:solid;border-color:#e5e5e5;border-width:0px 1px 1px 1px;overflow:auto;border-bottom-right-radius:4px;border-bottom-left-radius:4px}#showcase-app-code{width:100%}#showcase-code-position-toggle{float:right}#showcase-sxs-code{padding-top:20px;vertical-align:top}.showcase-code-license{display:block;text-align:right}#showcase-code-content pre{background-color:#fff}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
||||
/*! shiny 1.9.1.9000 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
"use strict";(function(){var a=eval;window.addEventListener("message",function(i){var e=i.data;e.code&&a(e.code)});})();
|
||||
//# sourceMappingURL=shiny-testmode.js.map
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*! shiny 1.9.1.9000 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.10.0.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
"use strict";
|
||||
(function() {
|
||||
var __create = Object.create;
|
||||
@@ -4551,18 +4551,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/internals/define-built-ins.js
|
||||
var require_define_built_ins = __commonJS({
|
||||
"node_modules/core-js/internals/define-built-ins.js": function(exports, module) {
|
||||
var defineBuiltIn6 = require_define_built_in();
|
||||
module.exports = function(target, src, options) {
|
||||
for (var key in src)
|
||||
defineBuiltIn6(target, key, src[key], options);
|
||||
return target;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/internals/collection.js
|
||||
var require_collection = __commonJS({
|
||||
"node_modules/core-js/internals/collection.js": function(exports, module) {
|
||||
@@ -4666,6 +4654,221 @@
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/internals/define-built-ins.js
|
||||
var require_define_built_ins = __commonJS({
|
||||
"node_modules/core-js/internals/define-built-ins.js": function(exports, module) {
|
||||
var defineBuiltIn6 = require_define_built_in();
|
||||
module.exports = function(target, src, options) {
|
||||
for (var key in src)
|
||||
defineBuiltIn6(target, key, src[key], options);
|
||||
return target;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/internals/collection-strong.js
|
||||
var require_collection_strong = __commonJS({
|
||||
"node_modules/core-js/internals/collection-strong.js": function(exports, module) {
|
||||
"use strict";
|
||||
var create3 = require_object_create();
|
||||
var defineBuiltInAccessor4 = require_define_built_in_accessor();
|
||||
var defineBuiltIns = require_define_built_ins();
|
||||
var bind2 = require_function_bind_context();
|
||||
var anInstance = require_an_instance();
|
||||
var isNullOrUndefined5 = require_is_null_or_undefined();
|
||||
var iterate2 = require_iterate();
|
||||
var defineIterator2 = require_iterator_define();
|
||||
var createIterResultObject2 = require_create_iter_result_object();
|
||||
var setSpecies3 = require_set_species();
|
||||
var DESCRIPTORS10 = require_descriptors();
|
||||
var fastKey = require_internal_metadata().fastKey;
|
||||
var InternalStateModule2 = require_internal_state();
|
||||
var setInternalState2 = InternalStateModule2.set;
|
||||
var internalStateGetterFor = InternalStateModule2.getterFor;
|
||||
module.exports = {
|
||||
getConstructor: function(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
|
||||
var Constructor = wrapper(function(that, iterable) {
|
||||
anInstance(that, Prototype);
|
||||
setInternalState2(that, {
|
||||
type: CONSTRUCTOR_NAME,
|
||||
index: create3(null),
|
||||
first: void 0,
|
||||
last: void 0,
|
||||
size: 0
|
||||
});
|
||||
if (!DESCRIPTORS10)
|
||||
that.size = 0;
|
||||
if (!isNullOrUndefined5(iterable))
|
||||
iterate2(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
|
||||
});
|
||||
var Prototype = Constructor.prototype;
|
||||
var getInternalState3 = internalStateGetterFor(CONSTRUCTOR_NAME);
|
||||
var define = function(that, key, value) {
|
||||
var state = getInternalState3(that);
|
||||
var entry = getEntry(that, key);
|
||||
var previous, index;
|
||||
if (entry) {
|
||||
entry.value = value;
|
||||
} else {
|
||||
state.last = entry = {
|
||||
index: index = fastKey(key, true),
|
||||
key: key,
|
||||
value: value,
|
||||
previous: previous = state.last,
|
||||
next: void 0,
|
||||
removed: false
|
||||
};
|
||||
if (!state.first)
|
||||
state.first = entry;
|
||||
if (previous)
|
||||
previous.next = entry;
|
||||
if (DESCRIPTORS10)
|
||||
state.size++;
|
||||
else
|
||||
that.size++;
|
||||
if (index !== "F")
|
||||
state.index[index] = entry;
|
||||
}
|
||||
return that;
|
||||
};
|
||||
var getEntry = function(that, key) {
|
||||
var state = getInternalState3(that);
|
||||
var index = fastKey(key);
|
||||
var entry;
|
||||
if (index !== "F")
|
||||
return state.index[index];
|
||||
for (entry = state.first; entry; entry = entry.next) {
|
||||
if (entry.key == key)
|
||||
return entry;
|
||||
}
|
||||
};
|
||||
defineBuiltIns(Prototype, {
|
||||
clear: function clear() {
|
||||
var that = this;
|
||||
var state = getInternalState3(that);
|
||||
var data = state.index;
|
||||
var entry = state.first;
|
||||
while (entry) {
|
||||
entry.removed = true;
|
||||
if (entry.previous)
|
||||
entry.previous = entry.previous.next = void 0;
|
||||
delete data[entry.index];
|
||||
entry = entry.next;
|
||||
}
|
||||
state.first = state.last = void 0;
|
||||
if (DESCRIPTORS10)
|
||||
state.size = 0;
|
||||
else
|
||||
that.size = 0;
|
||||
},
|
||||
"delete": function(key) {
|
||||
var that = this;
|
||||
var state = getInternalState3(that);
|
||||
var entry = getEntry(that, key);
|
||||
if (entry) {
|
||||
var next2 = entry.next;
|
||||
var prev = entry.previous;
|
||||
delete state.index[entry.index];
|
||||
entry.removed = true;
|
||||
if (prev)
|
||||
prev.next = next2;
|
||||
if (next2)
|
||||
next2.previous = prev;
|
||||
if (state.first == entry)
|
||||
state.first = next2;
|
||||
if (state.last == entry)
|
||||
state.last = prev;
|
||||
if (DESCRIPTORS10)
|
||||
state.size--;
|
||||
else
|
||||
that.size--;
|
||||
}
|
||||
return !!entry;
|
||||
},
|
||||
forEach: function forEach3(callbackfn) {
|
||||
var state = getInternalState3(this);
|
||||
var boundFunction = bind2(callbackfn, arguments.length > 1 ? arguments[1] : void 0);
|
||||
var entry;
|
||||
while (entry = entry ? entry.next : state.first) {
|
||||
boundFunction(entry.value, entry.key, this);
|
||||
while (entry && entry.removed)
|
||||
entry = entry.previous;
|
||||
}
|
||||
},
|
||||
has: function has(key) {
|
||||
return !!getEntry(this, key);
|
||||
}
|
||||
});
|
||||
defineBuiltIns(Prototype, IS_MAP ? {
|
||||
get: function get3(key) {
|
||||
var entry = getEntry(this, key);
|
||||
return entry && entry.value;
|
||||
},
|
||||
set: function set(key, value) {
|
||||
return define(this, key === 0 ? 0 : key, value);
|
||||
}
|
||||
} : {
|
||||
add: function add(value) {
|
||||
return define(this, value = value === 0 ? 0 : value, value);
|
||||
}
|
||||
});
|
||||
if (DESCRIPTORS10)
|
||||
defineBuiltInAccessor4(Prototype, "size", {
|
||||
configurable: true,
|
||||
get: function() {
|
||||
return getInternalState3(this).size;
|
||||
}
|
||||
});
|
||||
return Constructor;
|
||||
},
|
||||
setStrong: function(Constructor, CONSTRUCTOR_NAME, IS_MAP) {
|
||||
var ITERATOR_NAME = CONSTRUCTOR_NAME + " Iterator";
|
||||
var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
|
||||
var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
|
||||
defineIterator2(Constructor, CONSTRUCTOR_NAME, function(iterated, kind) {
|
||||
setInternalState2(this, {
|
||||
type: ITERATOR_NAME,
|
||||
target: iterated,
|
||||
state: getInternalCollectionState(iterated),
|
||||
kind: kind,
|
||||
last: void 0
|
||||
});
|
||||
}, function() {
|
||||
var state = getInternalIteratorState(this);
|
||||
var kind = state.kind;
|
||||
var entry = state.last;
|
||||
while (entry && entry.removed)
|
||||
entry = entry.previous;
|
||||
if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
|
||||
state.target = void 0;
|
||||
return createIterResultObject2(void 0, true);
|
||||
}
|
||||
if (kind == "keys")
|
||||
return createIterResultObject2(entry.key, false);
|
||||
if (kind == "values")
|
||||
return createIterResultObject2(entry.value, false);
|
||||
return createIterResultObject2([entry.key, entry.value], false);
|
||||
}, IS_MAP ? "entries" : "values", !IS_MAP, true);
|
||||
setSpecies3(CONSTRUCTOR_NAME);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/modules/es.map.constructor.js
|
||||
var require_es_map_constructor = __commonJS({
|
||||
"node_modules/core-js/modules/es.map.constructor.js": function() {
|
||||
"use strict";
|
||||
var collection = require_collection();
|
||||
var collectionStrong = require_collection_strong();
|
||||
collection("Map", function(init2) {
|
||||
return function Map2() {
|
||||
return init2(this, arguments.length ? arguments[0] : void 0);
|
||||
};
|
||||
}, collectionStrong);
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/internals/collection-weak.js
|
||||
var require_collection_weak = __commonJS({
|
||||
"node_modules/core-js/internals/collection-weak.js": function(exports, module) {
|
||||
@@ -4903,209 +5106,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/internals/collection-strong.js
|
||||
var require_collection_strong = __commonJS({
|
||||
"node_modules/core-js/internals/collection-strong.js": function(exports, module) {
|
||||
"use strict";
|
||||
var create3 = require_object_create();
|
||||
var defineBuiltInAccessor4 = require_define_built_in_accessor();
|
||||
var defineBuiltIns = require_define_built_ins();
|
||||
var bind2 = require_function_bind_context();
|
||||
var anInstance = require_an_instance();
|
||||
var isNullOrUndefined5 = require_is_null_or_undefined();
|
||||
var iterate2 = require_iterate();
|
||||
var defineIterator2 = require_iterator_define();
|
||||
var createIterResultObject2 = require_create_iter_result_object();
|
||||
var setSpecies3 = require_set_species();
|
||||
var DESCRIPTORS10 = require_descriptors();
|
||||
var fastKey = require_internal_metadata().fastKey;
|
||||
var InternalStateModule2 = require_internal_state();
|
||||
var setInternalState2 = InternalStateModule2.set;
|
||||
var internalStateGetterFor = InternalStateModule2.getterFor;
|
||||
module.exports = {
|
||||
getConstructor: function(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
|
||||
var Constructor = wrapper(function(that, iterable) {
|
||||
anInstance(that, Prototype);
|
||||
setInternalState2(that, {
|
||||
type: CONSTRUCTOR_NAME,
|
||||
index: create3(null),
|
||||
first: void 0,
|
||||
last: void 0,
|
||||
size: 0
|
||||
});
|
||||
if (!DESCRIPTORS10)
|
||||
that.size = 0;
|
||||
if (!isNullOrUndefined5(iterable))
|
||||
iterate2(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
|
||||
});
|
||||
var Prototype = Constructor.prototype;
|
||||
var getInternalState3 = internalStateGetterFor(CONSTRUCTOR_NAME);
|
||||
var define = function(that, key, value) {
|
||||
var state = getInternalState3(that);
|
||||
var entry = getEntry(that, key);
|
||||
var previous, index;
|
||||
if (entry) {
|
||||
entry.value = value;
|
||||
} else {
|
||||
state.last = entry = {
|
||||
index: index = fastKey(key, true),
|
||||
key: key,
|
||||
value: value,
|
||||
previous: previous = state.last,
|
||||
next: void 0,
|
||||
removed: false
|
||||
};
|
||||
if (!state.first)
|
||||
state.first = entry;
|
||||
if (previous)
|
||||
previous.next = entry;
|
||||
if (DESCRIPTORS10)
|
||||
state.size++;
|
||||
else
|
||||
that.size++;
|
||||
if (index !== "F")
|
||||
state.index[index] = entry;
|
||||
}
|
||||
return that;
|
||||
};
|
||||
var getEntry = function(that, key) {
|
||||
var state = getInternalState3(that);
|
||||
var index = fastKey(key);
|
||||
var entry;
|
||||
if (index !== "F")
|
||||
return state.index[index];
|
||||
for (entry = state.first; entry; entry = entry.next) {
|
||||
if (entry.key == key)
|
||||
return entry;
|
||||
}
|
||||
};
|
||||
defineBuiltIns(Prototype, {
|
||||
clear: function clear() {
|
||||
var that = this;
|
||||
var state = getInternalState3(that);
|
||||
var data = state.index;
|
||||
var entry = state.first;
|
||||
while (entry) {
|
||||
entry.removed = true;
|
||||
if (entry.previous)
|
||||
entry.previous = entry.previous.next = void 0;
|
||||
delete data[entry.index];
|
||||
entry = entry.next;
|
||||
}
|
||||
state.first = state.last = void 0;
|
||||
if (DESCRIPTORS10)
|
||||
state.size = 0;
|
||||
else
|
||||
that.size = 0;
|
||||
},
|
||||
"delete": function(key) {
|
||||
var that = this;
|
||||
var state = getInternalState3(that);
|
||||
var entry = getEntry(that, key);
|
||||
if (entry) {
|
||||
var next2 = entry.next;
|
||||
var prev = entry.previous;
|
||||
delete state.index[entry.index];
|
||||
entry.removed = true;
|
||||
if (prev)
|
||||
prev.next = next2;
|
||||
if (next2)
|
||||
next2.previous = prev;
|
||||
if (state.first == entry)
|
||||
state.first = next2;
|
||||
if (state.last == entry)
|
||||
state.last = prev;
|
||||
if (DESCRIPTORS10)
|
||||
state.size--;
|
||||
else
|
||||
that.size--;
|
||||
}
|
||||
return !!entry;
|
||||
},
|
||||
forEach: function forEach3(callbackfn) {
|
||||
var state = getInternalState3(this);
|
||||
var boundFunction = bind2(callbackfn, arguments.length > 1 ? arguments[1] : void 0);
|
||||
var entry;
|
||||
while (entry = entry ? entry.next : state.first) {
|
||||
boundFunction(entry.value, entry.key, this);
|
||||
while (entry && entry.removed)
|
||||
entry = entry.previous;
|
||||
}
|
||||
},
|
||||
has: function has(key) {
|
||||
return !!getEntry(this, key);
|
||||
}
|
||||
});
|
||||
defineBuiltIns(Prototype, IS_MAP ? {
|
||||
get: function get3(key) {
|
||||
var entry = getEntry(this, key);
|
||||
return entry && entry.value;
|
||||
},
|
||||
set: function set(key, value) {
|
||||
return define(this, key === 0 ? 0 : key, value);
|
||||
}
|
||||
} : {
|
||||
add: function add(value) {
|
||||
return define(this, value = value === 0 ? 0 : value, value);
|
||||
}
|
||||
});
|
||||
if (DESCRIPTORS10)
|
||||
defineBuiltInAccessor4(Prototype, "size", {
|
||||
configurable: true,
|
||||
get: function() {
|
||||
return getInternalState3(this).size;
|
||||
}
|
||||
});
|
||||
return Constructor;
|
||||
},
|
||||
setStrong: function(Constructor, CONSTRUCTOR_NAME, IS_MAP) {
|
||||
var ITERATOR_NAME = CONSTRUCTOR_NAME + " Iterator";
|
||||
var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
|
||||
var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
|
||||
defineIterator2(Constructor, CONSTRUCTOR_NAME, function(iterated, kind) {
|
||||
setInternalState2(this, {
|
||||
type: ITERATOR_NAME,
|
||||
target: iterated,
|
||||
state: getInternalCollectionState(iterated),
|
||||
kind: kind,
|
||||
last: void 0
|
||||
});
|
||||
}, function() {
|
||||
var state = getInternalIteratorState(this);
|
||||
var kind = state.kind;
|
||||
var entry = state.last;
|
||||
while (entry && entry.removed)
|
||||
entry = entry.previous;
|
||||
if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
|
||||
state.target = void 0;
|
||||
return createIterResultObject2(void 0, true);
|
||||
}
|
||||
if (kind == "keys")
|
||||
return createIterResultObject2(entry.key, false);
|
||||
if (kind == "values")
|
||||
return createIterResultObject2(entry.value, false);
|
||||
return createIterResultObject2([entry.key, entry.value], false);
|
||||
}, IS_MAP ? "entries" : "values", !IS_MAP, true);
|
||||
setSpecies3(CONSTRUCTOR_NAME);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/modules/es.map.constructor.js
|
||||
var require_es_map_constructor = __commonJS({
|
||||
"node_modules/core-js/modules/es.map.constructor.js": function() {
|
||||
"use strict";
|
||||
var collection = require_collection();
|
||||
var collectionStrong = require_collection_strong();
|
||||
collection("Map", function(init2) {
|
||||
return function Map2() {
|
||||
return init2(this, arguments.length ? arguments[0] : void 0);
|
||||
};
|
||||
}, collectionStrong);
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/core-js/modules/es.set.constructor.js
|
||||
var require_es_set_constructor = __commonJS({
|
||||
"node_modules/core-js/modules/es.set.constructor.js": function() {
|
||||
@@ -6873,6 +6873,14 @@
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
function getBoundingClientSizeBeforeZoom(el) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
var zoom = el.currentCSSZoom || 1;
|
||||
return {
|
||||
width: rect.width / zoom,
|
||||
height: rect.height / zoom
|
||||
};
|
||||
}
|
||||
function scopeExprToFunc(expr) {
|
||||
var exprEscaped = expr.replace(/[\\"']/g, "\\$&").replace(/\u0000/g, "\\0").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/[\b]/g, "\\b");
|
||||
var func;
|
||||
@@ -10662,10 +10670,8 @@
|
||||
}
|
||||
if (hasDefinedProperty(data, "url")) {
|
||||
var _selectize2 = this._selectize(el);
|
||||
_selectize2.clear();
|
||||
_selectize2.clearOptions();
|
||||
if (hasDefinedProperty(data, "value")) {
|
||||
_selectize2.clear();
|
||||
}
|
||||
var loaded = false;
|
||||
_selectize2.settings.load = function(query, callback) {
|
||||
var settings = _selectize2.settings;
|
||||
@@ -15817,6 +15823,9 @@
|
||||
// srcts/src/components/errorConsole.ts
|
||||
var import_es_array_iterator36 = __toESM(require_es_array_iterator());
|
||||
|
||||
// node_modules/core-js/modules/es.map.js
|
||||
require_es_map_constructor();
|
||||
|
||||
// node_modules/@lit/reactive-element/reactive-element.js
|
||||
var import_es_regexp_exec10 = __toESM(require_es_regexp_exec(), 1);
|
||||
|
||||
@@ -15852,9 +15861,6 @@
|
||||
// node_modules/core-js/modules/es.weak-map.js
|
||||
require_es_weak_map_constructor();
|
||||
|
||||
// node_modules/core-js/modules/es.map.js
|
||||
require_es_map_constructor();
|
||||
|
||||
// node_modules/core-js/modules/es.set.js
|
||||
require_es_set_constructor();
|
||||
|
||||
@@ -16589,7 +16595,7 @@
|
||||
}
|
||||
function _wrapNativeSuper(Class) {
|
||||
var _cache = typeof Map === "function" ? /* @__PURE__ */ new Map() : void 0;
|
||||
_wrapNativeSuper = function _wrapNativeSuper3(Class2) {
|
||||
_wrapNativeSuper = function _wrapNativeSuper4(Class2) {
|
||||
if (Class2 === null || !_isNativeFunction(Class2))
|
||||
return Class2;
|
||||
if (typeof Class2 !== "function") {
|
||||
@@ -16612,7 +16618,7 @@
|
||||
if (_isNativeReflectConstruct21()) {
|
||||
_construct = Reflect.construct.bind();
|
||||
} else {
|
||||
_construct = function _construct3(Parent2, args2, Class2) {
|
||||
_construct = function _construct4(Parent2, args2, Class2) {
|
||||
var a3 = [null];
|
||||
a3.push.apply(a3, args2);
|
||||
var Constructor = Function.bind.apply(Parent2, a3);
|
||||
@@ -18335,7 +18341,7 @@
|
||||
}
|
||||
function _wrapNativeSuper2(Class) {
|
||||
var _cache = typeof Map === "function" ? /* @__PURE__ */ new Map() : void 0;
|
||||
_wrapNativeSuper2 = function _wrapNativeSuper3(Class2) {
|
||||
_wrapNativeSuper2 = function _wrapNativeSuper4(Class2) {
|
||||
if (Class2 === null || !_isNativeFunction2(Class2))
|
||||
return Class2;
|
||||
if (typeof Class2 !== "function") {
|
||||
@@ -18358,7 +18364,7 @@
|
||||
if (_isNativeReflectConstruct24()) {
|
||||
_construct2 = Reflect.construct.bind();
|
||||
} else {
|
||||
_construct2 = function _construct3(Parent2, args2, Class2) {
|
||||
_construct2 = function _construct4(Parent2, args2, Class2) {
|
||||
var a3 = [null];
|
||||
a3.push.apply(a3, args2);
|
||||
var Constructor = Function.bind.apply(Parent2, a3);
|
||||
@@ -18456,6 +18462,46 @@
|
||||
var _templateObject3;
|
||||
var _templateObject4;
|
||||
var _templateObject5;
|
||||
function _wrapNativeSuper3(Class) {
|
||||
var _cache = typeof Map === "function" ? /* @__PURE__ */ new Map() : void 0;
|
||||
_wrapNativeSuper3 = function _wrapNativeSuper4(Class2) {
|
||||
if (Class2 === null || !_isNativeFunction3(Class2))
|
||||
return Class2;
|
||||
if (typeof Class2 !== "function") {
|
||||
throw new TypeError("Super expression must either be null or a function");
|
||||
}
|
||||
if (typeof _cache !== "undefined") {
|
||||
if (_cache.has(Class2))
|
||||
return _cache.get(Class2);
|
||||
_cache.set(Class2, Wrapper);
|
||||
}
|
||||
function Wrapper() {
|
||||
return _construct3(Class2, arguments, _getPrototypeOf25(this).constructor);
|
||||
}
|
||||
Wrapper.prototype = Object.create(Class2.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } });
|
||||
return _setPrototypeOf25(Wrapper, Class2);
|
||||
};
|
||||
return _wrapNativeSuper3(Class);
|
||||
}
|
||||
function _construct3(Parent, args, Class) {
|
||||
if (_isNativeReflectConstruct25()) {
|
||||
_construct3 = Reflect.construct.bind();
|
||||
} else {
|
||||
_construct3 = function _construct4(Parent2, args2, Class2) {
|
||||
var a3 = [null];
|
||||
a3.push.apply(a3, args2);
|
||||
var Constructor = Function.bind.apply(Parent2, a3);
|
||||
var instance = new Constructor();
|
||||
if (Class2)
|
||||
_setPrototypeOf25(instance, Class2.prototype);
|
||||
return instance;
|
||||
};
|
||||
}
|
||||
return _construct3.apply(null, arguments);
|
||||
}
|
||||
function _isNativeFunction3(fn) {
|
||||
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
||||
}
|
||||
function _regeneratorRuntime6() {
|
||||
"use strict";
|
||||
_regeneratorRuntime6 = function _regeneratorRuntime15() {
|
||||
@@ -18958,12 +19004,36 @@
|
||||
headline: {},
|
||||
message: {}
|
||||
});
|
||||
_defineProperty11(ShinyErrorMessage, "styles", [i(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(['\n :host {\n color: var(--red-11);\n display: block;\n font-size: var(--font-md);\n\n position: relative;\n --icon-size: var(--font-lg)\n\n /* Reset box sizing */\n box-sizing: border-box;\n }\n\n .container {\n display: flex;\n gap: var(--space-2);\n }\n\n .contents {\n width: 40ch;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n padding-block-start: 0;\n padding-block-end: var(--space-3);\n overflow: auto;\n }\n\n :host(:last-of-type) .contents {\n\n padding-block-end: var(--space-1);\n }\n\n .contents > h3 {\n font-size: 1em;\n font-weight: 500;\n color: var(--red-12);\n }\n\n .contents > * {\n margin-block: 0;\n }\n\n .error-message {\n font-family: "Courier New", Courier, monospace;\n }\n\n .decoration-container {\n flex-shrink: 0;\n position: relative;\n\n --line-w: 2px;\n --dot-size: 11px;\n }\n\n :host(:hover) .decoration-container {\n --scale: 1.25;\n }\n\n .vertical-line {\n margin-inline: auto;\n width: var(--line-w);\n height: 100%;\n\n background-color: var(--red-10);\n }\n\n :host(:first-of-type) .vertical-line {\n height: calc(100% - var(--dot-size));\n margin-top: var(--dot-size);\n }\n\n .dot {\n position: absolute;\n width: var(--dot-size);\n height: var(--dot-size);\n top: calc(-1px + var(--dot-size) / 2);\n left: calc(50% - var(--dot-size) / 2);\n border-radius: 100%;\n transform: scale(var(--scale, 1));\n\n color: var(--red-6);\n background-color: var(--red-10);\n }\n\n .actions {\n transform: scaleX(0);\n transition: transform calc(var(--animation-speed) / 2) ease-in-out;\n display: flex;\n justify-content: center;\n flex-direction: column;\n }\n\n /* Delay transition on mouseout so the buttons don\'t jump away if the user\n overshoots them with their mouse */\n :host(:not(:hover)) .actions {\n transition-delay: 0.15s;\n }\n\n :host(:hover) .actions {\n transform: scaleX(1);\n }\n\n ', "\n\n .copy-button {\n padding: 0;\n width: var(--space-8);\n height: var(--space-8);\n position: relative;\n --pad: var(--space-2);\n }\n\n .copy-button-inner {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n transition: transform 0.5s;\n transform-style: preserve-3d;\n }\n\n /* Animate flipping to the other side when the .copy-success class is\n added to the host */\n :host(.copy-success) .copy-button-inner {\n transform: rotateY(180deg);\n }\n\n /* Position the front and back side */\n .copy-button .front,\n .copy-button .back {\n --side: calc(100% - 2 * var(--pad));\n position: absolute;\n inset: var(--pad);\n height: var(--side);\n width: var(--side);\n -webkit-backface-visibility: hidden; /* Safari */\n backface-visibility: hidden;\n }\n\n .copy-button:hover .copy-button-inner {\n background-color: var(--gray-2);\n }\n\n /* Style the back side */\n .copy-button .back {\n --pad: var(--space-1);\n color: var(--green-8);\n transform: rotateY(180deg);\n }\n "])), buttonStyles)]);
|
||||
_defineProperty11(ShinyErrorMessage, "styles", [i(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(['\n :host {\n color: var(--red-11);\n display: block;\n font-size: var(--font-md);\n\n position: relative;\n --icon-size: var(--font-lg)\n\n /* Reset box sizing */\n box-sizing: border-box;\n }\n\n .container {\n display: flex;\n gap: var(--space-2);\n }\n\n .contents {\n width: 40ch;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n padding-block-start: 0;\n padding-block-end: var(--space-3);\n overflow: auto;\n }\n\n :host(:last-of-type) .contents {\n\n padding-block-end: var(--space-1);\n }\n\n .contents > h3 {\n font-size: 1em;\n font-weight: 500;\n color: var(--red-12);\n }\n\n .contents > * {\n margin-block: 0;\n }\n\n .error-message {\n font-family: "Courier New", Courier, monospace;\n white-space: pre-wrap;\n }\n\n .decoration-container {\n flex-shrink: 0;\n position: relative;\n\n --line-w: 2px;\n --dot-size: 11px;\n }\n\n :host(:hover) .decoration-container {\n --scale: 1.25;\n }\n\n .vertical-line {\n margin-inline: auto;\n width: var(--line-w);\n height: 100%;\n\n background-color: var(--red-10);\n }\n\n :host(:first-of-type) .vertical-line {\n height: calc(100% - var(--dot-size));\n margin-top: var(--dot-size);\n }\n\n .dot {\n position: absolute;\n width: var(--dot-size);\n height: var(--dot-size);\n top: calc(-1px + var(--dot-size) / 2);\n left: calc(50% - var(--dot-size) / 2);\n border-radius: 100%;\n transform: scale(var(--scale, 1));\n\n color: var(--red-6);\n background-color: var(--red-10);\n }\n\n .actions {\n transform: scaleX(0);\n transition: transform calc(var(--animation-speed) / 2) ease-in-out;\n display: flex;\n justify-content: center;\n flex-direction: column;\n }\n\n /* Delay transition on mouseout so the buttons don\'t jump away if the user\n overshoots them with their mouse */\n :host(:not(:hover)) .actions {\n transition-delay: 0.15s;\n }\n\n :host(:hover) .actions {\n transform: scaleX(1);\n }\n\n ', "\n\n .copy-button {\n padding: 0;\n width: var(--space-8);\n height: var(--space-8);\n position: relative;\n --pad: var(--space-2);\n }\n\n .copy-button-inner {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n transition: transform 0.5s;\n transform-style: preserve-3d;\n }\n\n /* Animate flipping to the other side when the .copy-success class is\n added to the host */\n :host(.copy-success) .copy-button-inner {\n transform: rotateY(180deg);\n }\n\n /* Position the front and back side */\n .copy-button .front,\n .copy-button .back {\n --side: calc(100% - 2 * var(--pad));\n position: absolute;\n inset: var(--pad);\n height: var(--side);\n width: var(--side);\n -webkit-backface-visibility: hidden; /* Safari */\n backface-visibility: hidden;\n }\n\n .copy-button:hover .copy-button-inner {\n background-color: var(--gray-2);\n }\n\n /* Style the back side */\n .copy-button .back {\n --pad: var(--space-1);\n color: var(--green-8);\n transform: rotateY(180deg);\n }\n "])), buttonStyles)]);
|
||||
customElements.define("shiny-error-message", ShinyErrorMessage);
|
||||
function showErrorInClientConsole(e4) {
|
||||
function showShinyClientMessage(_ref) {
|
||||
var _ref$headline = _ref.headline, headline = _ref$headline === void 0 ? "" : _ref$headline, message = _ref.message, _ref$status = _ref.status, status = _ref$status === void 0 ? "warning" : _ref$status;
|
||||
var consoleMessage = "[shiny] ".concat(headline).concat(headline ? " - " : "").concat(message);
|
||||
switch (status) {
|
||||
case "error":
|
||||
console.error(consoleMessage);
|
||||
break;
|
||||
case "warning":
|
||||
console.warn(consoleMessage);
|
||||
break;
|
||||
default:
|
||||
console.log(consoleMessage);
|
||||
break;
|
||||
}
|
||||
if (!Shiny.inDevMode()) {
|
||||
return;
|
||||
}
|
||||
var errorConsoleContainer = document.querySelector("shiny-error-console");
|
||||
if (!errorConsoleContainer) {
|
||||
errorConsoleContainer = document.createElement("shiny-error-console");
|
||||
document.body.appendChild(errorConsoleContainer);
|
||||
}
|
||||
var errorConsole = document.createElement("shiny-error-message");
|
||||
errorConsole.setAttribute("headline", headline);
|
||||
errorConsole.setAttribute("message", message);
|
||||
errorConsoleContainer.appendChild(errorConsole);
|
||||
}
|
||||
function showErrorInClientConsole(e4) {
|
||||
var errorMsg = null;
|
||||
var headline = "Error on client while running Shiny app";
|
||||
if (typeof e4 === "string") {
|
||||
@@ -18976,16 +19046,39 @@
|
||||
} else {
|
||||
errorMsg = "Unknown error";
|
||||
}
|
||||
var errorConsoleContainer = document.querySelector("shiny-error-console");
|
||||
if (!errorConsoleContainer) {
|
||||
errorConsoleContainer = document.createElement("shiny-error-console");
|
||||
document.body.appendChild(errorConsoleContainer);
|
||||
}
|
||||
var errorConsole = document.createElement("shiny-error-message");
|
||||
errorConsole.setAttribute("headline", headline || "");
|
||||
errorConsole.setAttribute("message", errorMsg);
|
||||
errorConsoleContainer.appendChild(errorConsole);
|
||||
showShinyClientMessage({
|
||||
headline: headline,
|
||||
message: errorMsg,
|
||||
status: "error"
|
||||
});
|
||||
}
|
||||
var ShinyClientMessageEvent = /* @__PURE__ */ function(_CustomEvent) {
|
||||
_inherits25(ShinyClientMessageEvent2, _CustomEvent);
|
||||
var _super3 = _createSuper25(ShinyClientMessageEvent2);
|
||||
function ShinyClientMessageEvent2(detail) {
|
||||
_classCallCheck33(this, ShinyClientMessageEvent2);
|
||||
return _super3.call(this, "shiny:client-message", {
|
||||
detail: detail,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
}
|
||||
return _createClass33(ShinyClientMessageEvent2);
|
||||
}(/* @__PURE__ */ _wrapNativeSuper3(CustomEvent));
|
||||
window.addEventListener("shiny:client-message", function(ev) {
|
||||
if (!(ev instanceof CustomEvent)) {
|
||||
throw new Error("[shiny] shiny:client-message expected a CustomEvent");
|
||||
}
|
||||
var _ev$detail = ev.detail, headline = _ev$detail.headline, message = _ev$detail.message, status = _ev$detail.status;
|
||||
if (!message) {
|
||||
throw new Error("[shiny] shiny:client-message expected a `message` property in `event.detail`.");
|
||||
}
|
||||
showShinyClientMessage({
|
||||
headline: headline,
|
||||
message: message,
|
||||
status: status
|
||||
});
|
||||
});
|
||||
|
||||
// srcts/src/imageutils/resetBrush.ts
|
||||
function resetBrush(brushId) {
|
||||
@@ -20511,6 +20604,9 @@
|
||||
if (Array.isArray(arr))
|
||||
return arr;
|
||||
}
|
||||
function isJQuery(value) {
|
||||
return Object.prototype.hasOwnProperty.call(value, "jquery") && typeof value.jquery === "string";
|
||||
}
|
||||
function valueChangeCallback(inputs, binding, el, allowDeferred) {
|
||||
var id = binding.getId(el);
|
||||
if (id) {
|
||||
@@ -20528,8 +20624,12 @@
|
||||
}
|
||||
var bindingsRegistry = function() {
|
||||
var bindings = /* @__PURE__ */ new Map();
|
||||
function checkValidity() {
|
||||
function checkValidity(scope) {
|
||||
if (!isJQuery(scope) && !(scope instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
var duplicateIds = /* @__PURE__ */ new Map();
|
||||
var problems = /* @__PURE__ */ new Set();
|
||||
bindings.forEach(function(idTypes, id) {
|
||||
var counts = {
|
||||
input: 0,
|
||||
@@ -20538,17 +20638,22 @@
|
||||
idTypes.forEach(function(type) {
|
||||
return counts[type] += 1;
|
||||
});
|
||||
if (counts.input === 1 && counts.output === 1 && !Shiny.inDevMode()) {
|
||||
if (counts.input + counts.output < 2) {
|
||||
return;
|
||||
}
|
||||
if (counts.input + counts.output > 1) {
|
||||
duplicateIds.set(id, counts);
|
||||
duplicateIds.set(id, counts);
|
||||
if (counts.input > 1) {
|
||||
problems.add("input");
|
||||
}
|
||||
if (counts.output > 1) {
|
||||
problems.add("output");
|
||||
}
|
||||
if (counts.input >= 1 && counts.output >= 1) {
|
||||
problems.add("shared");
|
||||
}
|
||||
});
|
||||
if (duplicateIds.size === 0)
|
||||
return {
|
||||
status: "ok"
|
||||
};
|
||||
return;
|
||||
var duplicateIdMsg = Array.from(duplicateIds.entries()).map(function(_ref) {
|
||||
var _ref2 = _slicedToArray4(_ref, 2), id = _ref2[0], counts = _ref2[1];
|
||||
var messages = [pluralize(counts.input, "input"), pluralize(counts.output, "output")].filter(function(msg) {
|
||||
@@ -20556,13 +20661,25 @@
|
||||
}).join(" and ");
|
||||
return '- "'.concat(id, '": ').concat(messages);
|
||||
}).join("\n");
|
||||
return {
|
||||
status: "error",
|
||||
error: new ShinyClientError({
|
||||
headline: "Duplicate input/output IDs found",
|
||||
message: "The following ".concat(duplicateIds.size === 1 ? "ID was" : "IDs were", " repeated:\n").concat(duplicateIdMsg)
|
||||
})
|
||||
};
|
||||
var txtVerb = "Duplicate";
|
||||
var txtNoun = "input/output";
|
||||
if (problems.has("input") && problems.has("output")) {
|
||||
} else if (problems.has("input")) {
|
||||
txtNoun = "input";
|
||||
} else if (problems.has("output")) {
|
||||
txtNoun = "output";
|
||||
} else if (problems.has("shared")) {
|
||||
txtVerb = "Shared";
|
||||
}
|
||||
var txtIdsWere = duplicateIds.size == 1 ? "ID was" : "IDs were";
|
||||
var headline = "".concat(txtVerb, " ").concat(txtNoun, " ").concat(txtIdsWere, " found");
|
||||
var message = "The following ".concat(txtIdsWere, " used for more than one ").concat(problems.has("shared") ? "input/output" : txtNoun, ":\n").concat(duplicateIdMsg);
|
||||
var event = new ShinyClientMessageEvent({
|
||||
headline: headline,
|
||||
message: message
|
||||
});
|
||||
var scopeElement = isJQuery(scope) ? scope.get(0) : scope;
|
||||
(scopeElement || window).dispatchEvent(event);
|
||||
}
|
||||
function addBinding(id, bindingType) {
|
||||
var existingBinding = bindings.get(id);
|
||||
@@ -20795,7 +20912,7 @@
|
||||
}
|
||||
function _bindAll2() {
|
||||
_bindAll2 = _asyncToGenerator8(/* @__PURE__ */ _regeneratorRuntime8().mark(function _callee2(shinyCtx, scope) {
|
||||
var currentInputs, bindingValidity;
|
||||
var currentInputs;
|
||||
return _regeneratorRuntime8().wrap(function _callee2$(_context2) {
|
||||
while (1)
|
||||
switch (_context2.prev = _context2.next) {
|
||||
@@ -20804,21 +20921,9 @@
|
||||
return bindOutputs(shinyCtx, scope);
|
||||
case 2:
|
||||
currentInputs = bindInputs(shinyCtx, scope);
|
||||
bindingValidity = bindingsRegistry.checkValidity();
|
||||
if (!(bindingValidity.status === "error")) {
|
||||
_context2.next = 10;
|
||||
break;
|
||||
}
|
||||
if (!Shiny.inDevMode()) {
|
||||
_context2.next = 9;
|
||||
break;
|
||||
}
|
||||
throw bindingValidity.error;
|
||||
case 9:
|
||||
console.warn("[shiny] " + bindingValidity.error.message);
|
||||
case 10:
|
||||
bindingsRegistry.checkValidity(scope);
|
||||
return _context2.abrupt("return", currentInputs);
|
||||
case 11:
|
||||
case 5:
|
||||
case "end":
|
||||
return _context2.stop();
|
||||
}
|
||||
@@ -21216,8 +21321,12 @@
|
||||
function remove() {
|
||||
var $modal = (0, import_jquery35.default)("#shiny-modal-wrapper");
|
||||
$modal.off("keydown.shinymodal");
|
||||
if ($modal.find(".modal").length > 0) {
|
||||
$modal.find(".modal").modal("hide");
|
||||
var $bsModal = $modal.find(".modal");
|
||||
if ($bsModal.length > 0) {
|
||||
$bsModal.on("shown.bs.modal", function() {
|
||||
return $bsModal.modal("hide");
|
||||
});
|
||||
$bsModal.modal("hide");
|
||||
} else {
|
||||
shinyUnbindAll($modal);
|
||||
$modal.remove();
|
||||
@@ -24539,36 +24648,40 @@
|
||||
_iterator3.s();
|
||||
case 27:
|
||||
if ((_step3 = _iterator3.n()).done) {
|
||||
_context15.next = 34;
|
||||
_context15.next = 35;
|
||||
break;
|
||||
}
|
||||
el = _step3.value;
|
||||
$tabContent[0].appendChild(el);
|
||||
_context15.next = 32;
|
||||
if (!(el.nodeType === Node.ELEMENT_NODE)) {
|
||||
_context15.next = 33;
|
||||
break;
|
||||
}
|
||||
_context15.next = 33;
|
||||
return renderContentAsync(el, el.innerHTML || el.textContent);
|
||||
case 32:
|
||||
case 33:
|
||||
_context15.next = 27;
|
||||
break;
|
||||
case 34:
|
||||
_context15.next = 39;
|
||||
case 35:
|
||||
_context15.next = 40;
|
||||
break;
|
||||
case 36:
|
||||
_context15.prev = 36;
|
||||
case 37:
|
||||
_context15.prev = 37;
|
||||
_context15.t0 = _context15["catch"](25);
|
||||
_iterator3.e(_context15.t0);
|
||||
case 39:
|
||||
_context15.prev = 39;
|
||||
case 40:
|
||||
_context15.prev = 40;
|
||||
_iterator3.f();
|
||||
return _context15.finish(39);
|
||||
case 42:
|
||||
return _context15.finish(40);
|
||||
case 43:
|
||||
if (message.select) {
|
||||
$liTag.find("a").tab("show");
|
||||
}
|
||||
case 43:
|
||||
case 44:
|
||||
case "end":
|
||||
return _context15.stop();
|
||||
}
|
||||
}, _callee15, null, [[25, 36, 39, 42]]);
|
||||
}, _callee15, null, [[25, 37, 40, 43]]);
|
||||
}));
|
||||
return function(_x17) {
|
||||
return _ref10.apply(this, arguments);
|
||||
@@ -25066,7 +25179,7 @@
|
||||
_defineProperty23(this, "initializeInputs", void 0);
|
||||
_defineProperty23(this, "initializedPromise", void 0);
|
||||
_defineProperty23(this, "oncustommessage", void 0);
|
||||
this.version = "1.9.1.9000";
|
||||
this.version = "1.10.0.9000";
|
||||
var _initInputBindings = initInputBindings(), inputBindings = _initInputBindings.inputBindings, fileInputBinding2 = _initInputBindings.fileInputBinding;
|
||||
var _initOutputBindings = initOutputBindings(), outputBindings = _initOutputBindings.outputBindings;
|
||||
setFileInputBinding(fileInputBinding2);
|
||||
@@ -25191,7 +25304,7 @@
|
||||
};
|
||||
doSendImageSize = function _doSendImageSize() {
|
||||
(0, import_jquery39.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(function() {
|
||||
var id = getIdFromEl(this), rect = this.getBoundingClientRect();
|
||||
var id = getIdFromEl(this), rect = getBoundingClientSizeBeforeZoom(this);
|
||||
if (rect.width !== 0 || rect.height !== 0) {
|
||||
inputs.setInput(".clientdata_output_" + id + "_width", rect.width);
|
||||
inputs.setInput(".clientdata_output_" + id + "_height", rect.height);
|
||||
@@ -25373,7 +25486,7 @@
|
||||
};
|
||||
initialValues = (0, _context3.t0)(_context3.t1, _context3.t2);
|
||||
(0, import_jquery39.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(function() {
|
||||
var id = getIdFromEl(this), rect = this.getBoundingClientRect();
|
||||
var id = getIdFromEl(this), rect = getBoundingClientSizeBeforeZoom(this);
|
||||
if (rect.width !== 0 || rect.height !== 0) {
|
||||
initialValues[".clientdata_output_" + id + "_width"] = rect.width;
|
||||
initialValues[".clientdata_output_" + id + "_height"] = rect.height;
|
||||
|
||||
File diff suppressed because one or more lines are too long
2
inst/www/shared/shiny.min.css
vendored
2
inst/www/shared/shiny.min.css
vendored
File diff suppressed because one or more lines are too long
4
inst/www/shared/shiny.min.js
vendored
4
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -45,6 +45,56 @@ is, a function that quickly returns a promise) and allows even that very
|
||||
session to immediately unblock and carry on with other user interactions.
|
||||
}
|
||||
|
||||
\examples{
|
||||
\dontshow{if (rlang::is_interactive() && rlang::is_installed("future")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
|
||||
|
||||
library(shiny)
|
||||
library(bslib)
|
||||
library(future)
|
||||
plan(multisession)
|
||||
|
||||
ui <- page_fluid(
|
||||
titlePanel("Extended Task Demo"),
|
||||
p(
|
||||
'Click the button below to perform a "calculation"',
|
||||
"that takes a while to perform."
|
||||
),
|
||||
input_task_button("recalculate", "Recalculate"),
|
||||
p(textOutput("result"))
|
||||
)
|
||||
|
||||
server <- function(input, output) {
|
||||
rand_task <- ExtendedTask$new(function() {
|
||||
future(
|
||||
{
|
||||
# Slow operation goes here
|
||||
Sys.sleep(2)
|
||||
sample(1:100, 1)
|
||||
},
|
||||
seed = TRUE
|
||||
)
|
||||
})
|
||||
|
||||
# Make button state reflect task.
|
||||
# If using R >=4.1, you can do this instead:
|
||||
# rand_task <- ExtendedTask$new(...) |> bind_task_button("recalculate")
|
||||
bind_task_button(rand_task, "recalculate")
|
||||
|
||||
observeEvent(input$recalculate, {
|
||||
# Invoke the extended in an observer
|
||||
rand_task$invoke()
|
||||
})
|
||||
|
||||
output$result <- renderText({
|
||||
# React to updated results when the task completes
|
||||
number <- rand_task$result()
|
||||
paste0("Your number is ", number, ".")
|
||||
})
|
||||
}
|
||||
|
||||
shinyApp(ui, server)
|
||||
\dontshow{\}) # examplesIf}
|
||||
}
|
||||
\section{Methods}{
|
||||
\subsection{Public methods}{
|
||||
\itemize{
|
||||
|
||||
@@ -182,7 +182,7 @@ If you want to use a cache that is shared across multiple R processes, you
|
||||
can use a \code{\link[cachem:cache_disk]{cachem::cache_disk()}}. You can create a application-level shared
|
||||
cache by putting this at the top of your app.R, server.R, or global.R:
|
||||
|
||||
\if{html}{\out{<div class="sourceCode">}}\preformatted{shinyOptions(cache = cachem::cache_disk(file.path(dirname(tempdir()), "myapp-cache"))
|
||||
\if{html}{\out{<div class="sourceCode">}}\preformatted{shinyOptions(cache = cachem::cache_disk(file.path(dirname(tempdir()), "myapp-cache")))
|
||||
}\if{html}{\out{</div>}}
|
||||
|
||||
This will create a subdirectory in your system temp directory named
|
||||
|
||||
@@ -33,7 +33,9 @@ interactive sessions only.}
|
||||
to the \code{shiny.host} option, if set, or \code{"127.0.0.1"} if not.}
|
||||
|
||||
\item{display.mode}{The mode in which to display the example. Defaults to
|
||||
\code{showcase}, but may be set to \code{normal} to see the example without
|
||||
\code{"auto"}, which uses the value of \code{DisplayMode} in the example's
|
||||
\code{DESCRIPTION} file. Set to \code{"showcase"} to show the app code and
|
||||
description with the running app, or \code{"normal"} to see the example without
|
||||
code or commentary.}
|
||||
|
||||
\item{package}{The package in which to find the example (defaults to
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"homepage": "https://shiny.rstudio.com",
|
||||
"repository": "github:rstudio/shiny",
|
||||
"name": "@types/rstudio-shiny",
|
||||
"version": "1.9.1-alpha.9000",
|
||||
"version": "1.10.0-alpha.9000",
|
||||
"license": "GPL-3.0-only",
|
||||
"main": "",
|
||||
"browser": "",
|
||||
|
||||
@@ -1,43 +1,34 @@
|
||||
# Revdeps
|
||||
|
||||
## Failed to check (29)
|
||||
## Failed to check (20)
|
||||
|
||||
|package |version |error |warning |note |
|
||||
|:---------------|:-------|:-----|:-------|:----|
|
||||
|alevinQC |? | | | |
|
||||
|animalEKF |1.2 |1 | | |
|
||||
|animaltracker |? | | | |
|
||||
|antaresViz |? | | | |
|
||||
|AovBay |0.1.0 |1 | | |
|
||||
|bdclean |? | | | |
|
||||
|chipPCR |1.0-2 |1 | | |
|
||||
|ctsem |3.10.0 |1 | | |
|
||||
|diveR |? | | | |
|
||||
|DynNom |5.1 |1 | | |
|
||||
|hydflood |? | | | |
|
||||
|loon.shiny |? | | | |
|
||||
|modchart |? | | | |
|
||||
|MODIStsp |? | | | |
|
||||
|protGear |? | | | |
|
||||
|robmedExtra |0.1.0 |1 | | |
|
||||
|RQuantLib |0.4.23 |1 | | |
|
||||
|rstanarm |2.32.1 |1 | | |
|
||||
|scPipe |? | | | |
|
||||
|sen2r |? | | | |
|
||||
|SensMap |0.7 |1 | | |
|
||||
|Seurat |5.1.0 |1 | | |
|
||||
|shinyTempSignal |0.0.8 |1 | | |
|
||||
|Signac |1.13.0 |1 | | |
|
||||
|simplevis |? | | | |
|
||||
|statsr |0.3.0 |1 | | |
|
||||
|teachingApps |? | | | |
|
||||
|tidyvpc |1.5.1 |1 | | |
|
||||
|TVTB |? | | | |
|
||||
|package |version |error |warning |note |
|
||||
|:------------------|:-------|:-----|:-------|:----|
|
||||
|animalEKF |1.2 |1 | | |
|
||||
|AovBay |0.1.0 |1 | | |
|
||||
|Certara.VPCResults |3.0.2 |1 | | |
|
||||
|chipPCR |1.0-2 |1 | | |
|
||||
|ctsem |3.10.1 |1 | | |
|
||||
|dartR.sim |? | | | |
|
||||
|diveR |? | | | |
|
||||
|gap |? | | | |
|
||||
|jsmodule |? | | | |
|
||||
|loon.shiny |? | | | |
|
||||
|robmedExtra |0.1.1 |1 | | |
|
||||
|rstanarm |2.32.1 |1 | | |
|
||||
|SensMap |0.7 |1 | | |
|
||||
|Seurat |5.1.0 |1 | |1 |
|
||||
|shinyTempSignal |0.0.8 |1 | | |
|
||||
|Signac |1.14.0 |1 | | |
|
||||
|statsr |0.3.0 |1 | | |
|
||||
|TestAnaAPP |1.1.2 |1 | | |
|
||||
|tidyvpc |1.5.2 |1 | | |
|
||||
|visR |? | | | |
|
||||
|
||||
## New problems (2)
|
||||
|
||||
|package |version |error |warning |note |
|
||||
|:-------|:-------|:--------|:-------|:------|
|
||||
|[EgoCor](problems.md#egocor)|1.2.0 |1 __+1__ | |-1 |
|
||||
|[mxfda](problems.md#mxfda)|0.2.1 | | |__+1__ |
|
||||
|package |version |error |warning |note |
|
||||
|:-------|:-------|:-----|:-------|:------|
|
||||
|[HH](problems.md#hh)|3.1-52 | | |__+1__ |
|
||||
|[PopED](problems.md#poped)|0.7.0 | | |__+1__ |
|
||||
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
## revdepcheck results
|
||||
|
||||
We checked 1221 reverse dependencies (1208 from CRAN + 13 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
We checked 1278 reverse dependencies (1277 from CRAN + 1 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
|
||||
* We saw 2 new problems
|
||||
* We failed to check 16 packages
|
||||
* We failed to check 19 packages
|
||||
|
||||
Issues with CRAN packages are summarised below.
|
||||
|
||||
### New problems
|
||||
(This reports the first line of each new failure)
|
||||
|
||||
* EgoCor
|
||||
checking running R code from vignettes ... ERROR
|
||||
* HH
|
||||
checking installed package size ... NOTE
|
||||
|
||||
* mxfda
|
||||
* PopED
|
||||
checking installed package size ... NOTE
|
||||
|
||||
### Failed to check
|
||||
|
||||
* animalEKF (NA)
|
||||
* AovBay (NA)
|
||||
* chipPCR (NA)
|
||||
* ctsem (NA)
|
||||
* diveR (NA)
|
||||
* DynNom (NA)
|
||||
* loon.shiny (NA)
|
||||
* robmedExtra (NA)
|
||||
* RQuantLib (NA)
|
||||
* rstanarm (NA)
|
||||
* SensMap (NA)
|
||||
* Seurat (NA)
|
||||
* shinyTempSignal (NA)
|
||||
* Signac (NA)
|
||||
* statsr (NA)
|
||||
* tidyvpc (NA)
|
||||
* animalEKF (NA)
|
||||
* AovBay (NA)
|
||||
* Certara.VPCResults (NA)
|
||||
* chipPCR (NA)
|
||||
* ctsem (NA)
|
||||
* dartR.sim (NA)
|
||||
* diveR (NA)
|
||||
* gap (NA)
|
||||
* jsmodule (NA)
|
||||
* loon.shiny (NA)
|
||||
* robmedExtra (NA)
|
||||
* rstanarm (NA)
|
||||
* SensMap (NA)
|
||||
* Seurat (NA)
|
||||
* shinyTempSignal (NA)
|
||||
* Signac (NA)
|
||||
* statsr (NA)
|
||||
* TestAnaAPP (NA)
|
||||
* tidyvpc (NA)
|
||||
|
||||
@@ -1,84 +1,14 @@
|
||||
# EgoCor
|
||||
# HH
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 1.2.0
|
||||
* GitHub: https://github.com/julia-dyck/EgoCor
|
||||
* Source code: https://github.com/cran/EgoCor
|
||||
* Date/Publication: 2024-03-28 18:10:02 UTC
|
||||
* Number of recursive dependencies: 74
|
||||
* Version: 3.1-52
|
||||
* GitHub: NA
|
||||
* Source code: https://github.com/cran/HH
|
||||
* Date/Publication: 2024-02-11 00:00:02 UTC
|
||||
* Number of recursive dependencies: 165
|
||||
|
||||
Run `revdepcheck::cloud_details(, "EgoCor")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking running R code from vignettes ... ERROR
|
||||
```
|
||||
Errors in running code in vignettes:
|
||||
when running code in ‘Intro_to_EgoCor.Rmd’
|
||||
...
|
||||
Warning in gstat::fit.variogram(emp.sv, model = v, fit.sills = TRUE, fit.ranges = TRUE, :
|
||||
linear model has singular covariance matrix
|
||||
Warning in gstat::fit.variogram(emp.sv, model = v, fit.sills = TRUE, fit.ranges = TRUE, :
|
||||
linear model has singular covariance matrix
|
||||
Warning in gstat::fit.variogram(emp.sv, model = v, fit.sills = TRUE, fit.ranges = TRUE, :
|
||||
No convergence after 200 iterations: try different initial values?
|
||||
|
||||
When sourcing ‘Intro_to_EgoCor.R’:
|
||||
Error: missing value where TRUE/FALSE needed
|
||||
Execution halted
|
||||
|
||||
‘Intro_to_EgoCor.Rmd’ using ‘UTF-8’... failed
|
||||
```
|
||||
|
||||
## Newly fixed
|
||||
|
||||
* checking re-building of vignette outputs ... NOTE
|
||||
```
|
||||
Error(s) in re-building vignettes:
|
||||
--- re-building ‘Intro_to_EgoCor.Rmd’ using rmarkdown
|
||||
```
|
||||
|
||||
## In both
|
||||
|
||||
* checking examples ... ERROR
|
||||
```
|
||||
Running examples in ‘EgoCor-Ex.R’ failed
|
||||
The error most likely occurred in:
|
||||
|
||||
> ### Name: vario.reg.prep
|
||||
> ### Title: Adjustment for covariates before semi-variogram model fitting
|
||||
> ### Aliases: vario.reg.prep
|
||||
>
|
||||
> ### ** Examples
|
||||
>
|
||||
> ## Example 1
|
||||
...
|
||||
+ }
|
||||
Warning in check_dep_version() :
|
||||
ABI version mismatch:
|
||||
lme4 was built with Matrix ABI version 1
|
||||
Current Matrix ABI version is 0
|
||||
Please re-install lme4 from source or restore original ‘Matrix’ package
|
||||
Error in initializePtr() :
|
||||
function 'cholmod_factor_ldetA' not provided by package 'Matrix'
|
||||
Calls: <Anonymous> ... initialize -> <Anonymous> -> initializePtr -> .Call
|
||||
Execution halted
|
||||
```
|
||||
|
||||
# mxfda
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 0.2.1
|
||||
* GitHub: https://github.com/julia-wrobel/mxfda
|
||||
* Source code: https://github.com/cran/mxfda
|
||||
* Date/Publication: 2024-05-08 11:00:02 UTC
|
||||
* Number of recursive dependencies: 220
|
||||
|
||||
Run `revdepcheck::cloud_details(, "mxfda")` for more info
|
||||
Run `revdepcheck::cloud_details(, "HH")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
@@ -86,8 +16,34 @@ Run `revdepcheck::cloud_details(, "mxfda")` for more info
|
||||
|
||||
* checking installed package size ... NOTE
|
||||
```
|
||||
installed size is 5.6Mb
|
||||
installed size is 5.1Mb
|
||||
sub-directories of 1Mb or more:
|
||||
data 4.0Mb
|
||||
R 1.5Mb
|
||||
help 1.5Mb
|
||||
```
|
||||
|
||||
# PopED
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 0.7.0
|
||||
* GitHub: https://github.com/andrewhooker/PopED
|
||||
* Source code: https://github.com/cran/PopED
|
||||
* Date/Publication: 2024-10-07 19:30:02 UTC
|
||||
* Number of recursive dependencies: 140
|
||||
|
||||
Run `revdepcheck::cloud_details(, "PopED")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking installed package size ... NOTE
|
||||
```
|
||||
installed size is 5.5Mb
|
||||
sub-directories of 1Mb or more:
|
||||
R 1.5Mb
|
||||
doc 1.4Mb
|
||||
test 1.1Mb
|
||||
```
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import type {
|
||||
} from "esbuild";
|
||||
import { build as esbuildBuild } from "esbuild";
|
||||
|
||||
import process from "process";
|
||||
import { basename } from "path";
|
||||
import process from "process";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore; Type definitions are not found. This occurs when `strict: true` in tsconfig.json
|
||||
@@ -25,7 +25,7 @@ const shinyDesc = readcontrol.readSync("./DESCRIPTION") as ShinyDesc;
|
||||
|
||||
const bannerTxt = [
|
||||
`/*! ${shinyDesc.package} ${shinyDesc.version}`,
|
||||
`(c) 2012-${new Date().getFullYear()} RStudio, PBC.`,
|
||||
`(c) 2012-${new Date().getFullYear()} Posit Software, PBC.`,
|
||||
`License: ${shinyDesc.license} */`,
|
||||
].join(" | ");
|
||||
const banner = {
|
||||
|
||||
@@ -142,13 +142,13 @@ class SelectInputBinding extends InputBinding {
|
||||
};
|
||||
};
|
||||
|
||||
// Calling selectize.clear() first works around https://github.com/selectize/selectize.js/issues/2146
|
||||
// As of selectize.js >= v0.13.1, .clearOptions() clears the selection,
|
||||
// but does NOT remove the previously-selected options. So unless we call
|
||||
// .clear() first, the current selection(s) will remain as (deselected)
|
||||
// options. See #3966 #4142
|
||||
selectize.clear();
|
||||
selectize.clearOptions();
|
||||
// If a new `selected` value is provided, also clear the current selection (otherwise it gets added as an option).
|
||||
// Note: although the selectize docs suggest otherwise, as of selectize.js >v0.15.2,
|
||||
// .clearOptions() no longer implicitly .clear()s (see #3967)
|
||||
if (hasDefinedProperty(data, "value")) {
|
||||
selectize.clear();
|
||||
}
|
||||
let loaded = false;
|
||||
|
||||
selectize.settings.load = function (query: string, callback: CallbackFn) {
|
||||
|
||||
@@ -307,6 +307,7 @@ export class ShinyErrorMessage extends LitElement {
|
||||
|
||||
.error-message {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.decoration-container {
|
||||
@@ -489,6 +490,52 @@ export class ShinyErrorMessage extends LitElement {
|
||||
|
||||
customElements.define("shiny-error-message", ShinyErrorMessage);
|
||||
|
||||
export type ShinyClientMessage = {
|
||||
message: string;
|
||||
headline?: string;
|
||||
status?: "error" | "info" | "warning";
|
||||
};
|
||||
|
||||
function showShinyClientMessage({
|
||||
headline = "",
|
||||
message,
|
||||
status = "warning",
|
||||
}: ShinyClientMessage): void {
|
||||
const consoleMessage = `[shiny] ${headline}${
|
||||
headline ? " - " : ""
|
||||
}${message}`;
|
||||
|
||||
switch (status) {
|
||||
case "error":
|
||||
console.error(consoleMessage);
|
||||
break;
|
||||
case "warning":
|
||||
console.warn(consoleMessage);
|
||||
break;
|
||||
default:
|
||||
console.log(consoleMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Shiny.inDevMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if an Error Console Container element already exists. If it
|
||||
// doesn't we need to add it before putting an error on the screen
|
||||
let errorConsoleContainer = document.querySelector("shiny-error-console");
|
||||
if (!errorConsoleContainer) {
|
||||
errorConsoleContainer = document.createElement("shiny-error-console");
|
||||
document.body.appendChild(errorConsoleContainer);
|
||||
}
|
||||
|
||||
const errorConsole = document.createElement("shiny-error-message");
|
||||
errorConsole.setAttribute("headline", headline);
|
||||
errorConsole.setAttribute("message", message);
|
||||
|
||||
errorConsoleContainer.appendChild(errorConsole);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to show an error message to user in shiny-error-message web
|
||||
* component. Only shows the error if we're in development mode.
|
||||
@@ -497,11 +544,6 @@ customElements.define("shiny-error-message", ShinyErrorMessage);
|
||||
* object.
|
||||
*/
|
||||
export function showErrorInClientConsole(e: unknown): void {
|
||||
if (!Shiny.inDevMode()) {
|
||||
// If we're in production, don't show the error to the user
|
||||
return;
|
||||
}
|
||||
|
||||
let errorMsg: string | null = null;
|
||||
let headline = "Error on client while running Shiny app";
|
||||
|
||||
@@ -516,17 +558,24 @@ export function showErrorInClientConsole(e: unknown): void {
|
||||
errorMsg = "Unknown error";
|
||||
}
|
||||
|
||||
// Check to see if an Error Console Container element already exists. If it
|
||||
// doesn't we need to add it before putting an error on the screen
|
||||
let errorConsoleContainer = document.querySelector("shiny-error-console");
|
||||
if (!errorConsoleContainer) {
|
||||
errorConsoleContainer = document.createElement("shiny-error-console");
|
||||
document.body.appendChild(errorConsoleContainer);
|
||||
}
|
||||
|
||||
const errorConsole = document.createElement("shiny-error-message");
|
||||
errorConsole.setAttribute("headline", headline || "");
|
||||
errorConsole.setAttribute("message", errorMsg);
|
||||
|
||||
errorConsoleContainer.appendChild(errorConsole);
|
||||
showShinyClientMessage({ headline, message: errorMsg, status: "error" });
|
||||
}
|
||||
|
||||
export class ShinyClientMessageEvent extends CustomEvent<ShinyClientMessage> {
|
||||
constructor(detail: ShinyClientMessage) {
|
||||
super("shiny:client-message", { detail, bubbles: true, cancelable: true });
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("shiny:client-message", (ev: Event) => {
|
||||
if (!(ev instanceof CustomEvent)) {
|
||||
throw new Error("[shiny] shiny:client-message expected a CustomEvent");
|
||||
}
|
||||
const { headline, message, status } = ev.detail;
|
||||
if (!message) {
|
||||
throw new Error(
|
||||
"[shiny] shiny:client-message expected a `message` property in `event.detail`."
|
||||
);
|
||||
}
|
||||
showShinyClientMessage({ headline, message, status });
|
||||
});
|
||||
|
||||
@@ -3,16 +3,28 @@ import { Shiny } from "..";
|
||||
import type { InputBinding, OutputBinding } from "../bindings";
|
||||
import { OutputBindingAdapter } from "../bindings/outputAdapter";
|
||||
import type { BindingRegistry } from "../bindings/registry";
|
||||
import { ShinyClientMessageEvent } from "../components/errorConsole";
|
||||
import type {
|
||||
InputRateDecorator,
|
||||
InputValidateDecorator,
|
||||
} from "../inputPolicies";
|
||||
import { ShinyClientError } from "./error";
|
||||
import { shinyAppBindOutput, shinyAppUnbindOutput } from "./initedMethods";
|
||||
import { sendImageSizeFns } from "./sendImageSize";
|
||||
|
||||
type BindScope = HTMLElement | JQuery<HTMLElement>;
|
||||
|
||||
/**
|
||||
* Type guard to check if a value is a jQuery object containing HTMLElements
|
||||
* @param value The value to check
|
||||
* @returns A type predicate indicating if the value is a jQuery<HTMLElement>
|
||||
*/
|
||||
function isJQuery<T = HTMLElement>(value: unknown): value is JQuery<T> {
|
||||
return (
|
||||
Object.prototype.hasOwnProperty.call(value, "jquery") &&
|
||||
typeof (value as any).jquery === "string"
|
||||
);
|
||||
}
|
||||
|
||||
// todo make sure allowDeferred can NOT be supplied and still work
|
||||
function valueChangeCallback(
|
||||
inputs: InputValidateDecorator,
|
||||
@@ -75,14 +87,17 @@ const bindingsRegistry = (() => {
|
||||
* accessibility and other reasons. However, in practice our bindings still
|
||||
* work as long as inputs the IDs within a binding type don't overlap.
|
||||
*
|
||||
* @returns ShinyClientError if current ID bindings are invalid, otherwise
|
||||
* returns an ok status.
|
||||
* @returns ShinyClientMessageEvent if current ID bindings are invalid,
|
||||
* otherwise returns an ok status.
|
||||
*/
|
||||
function checkValidity():
|
||||
| { status: "error"; error: ShinyClientError }
|
||||
| { status: "ok" } {
|
||||
function checkValidity(scope: BindScope): void {
|
||||
if (!isJQuery(scope) && !(scope instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
type BindingCounts = { [T in BindingTypes]: number };
|
||||
const duplicateIds = new Map<string, BindingCounts>();
|
||||
const problems: Set<string> = new Set();
|
||||
|
||||
// count duplicate IDs of each binding type
|
||||
bindings.forEach((idTypes, id) => {
|
||||
@@ -90,22 +105,30 @@ const bindingsRegistry = (() => {
|
||||
|
||||
idTypes.forEach((type) => (counts[type] += 1));
|
||||
|
||||
// If there's a single duplication of ids across both binding types, then
|
||||
// when we're not in devmode, we allow this to pass because a good amount of
|
||||
// existing applications use this pattern even though its invalid. Eventually
|
||||
// this behavior should be removed.
|
||||
if (counts.input === 1 && counts.output === 1 && !Shiny.inDevMode()) {
|
||||
if (counts.input + counts.output < 2) {
|
||||
return;
|
||||
}
|
||||
// We have duplicated IDs, add them to the set of duplicated IDs to be
|
||||
// reported to the user.
|
||||
duplicateIds.set(id, counts);
|
||||
|
||||
// If we have duplicated IDs, then add them to the set of duplicated IDs
|
||||
// to be reported to the user.
|
||||
if (counts.input + counts.output > 1) {
|
||||
duplicateIds.set(id, counts);
|
||||
if (counts.input > 1) {
|
||||
problems.add("input");
|
||||
}
|
||||
if (counts.output > 1) {
|
||||
problems.add("output");
|
||||
}
|
||||
if (counts.input >= 1 && counts.output >= 1) {
|
||||
problems.add("shared");
|
||||
}
|
||||
});
|
||||
|
||||
if (duplicateIds.size === 0) return { status: "ok" };
|
||||
if (duplicateIds.size === 0) return;
|
||||
// Duplicated IDs are now always a warning. Before the ShinyClient console
|
||||
// was added duplicate output IDs were errors in "production" mode. After
|
||||
// the Shiny Client console was introduced, duplicate IDs were no longer
|
||||
// production errors but *would* break apps in dev mode. Now, in v1.10+,
|
||||
// duplicate IDs are always warnings in all modes for consistency.
|
||||
|
||||
const duplicateIdMsg = Array.from(duplicateIds.entries())
|
||||
.map(([id, counts]) => {
|
||||
@@ -120,15 +143,27 @@ const bindingsRegistry = (() => {
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
return {
|
||||
status: "error",
|
||||
error: new ShinyClientError({
|
||||
headline: "Duplicate input/output IDs found",
|
||||
message: `The following ${
|
||||
duplicateIds.size === 1 ? "ID was" : "IDs were"
|
||||
} repeated:\n${duplicateIdMsg}`,
|
||||
}),
|
||||
};
|
||||
let txtVerb = "Duplicate";
|
||||
let txtNoun = "input/output";
|
||||
if (problems.has("input") && problems.has("output")) {
|
||||
// base case
|
||||
} else if (problems.has("input")) {
|
||||
txtNoun = "input";
|
||||
} else if (problems.has("output")) {
|
||||
txtNoun = "output";
|
||||
} else if (problems.has("shared")) {
|
||||
txtVerb = "Shared";
|
||||
}
|
||||
|
||||
const txtIdsWere = duplicateIds.size == 1 ? "ID was" : "IDs were";
|
||||
const headline = `${txtVerb} ${txtNoun} ${txtIdsWere} found`;
|
||||
const message = `The following ${txtIdsWere} used for more than one ${
|
||||
problems.has("shared") ? "input/output" : txtNoun
|
||||
}:\n${duplicateIdMsg}`;
|
||||
|
||||
const event = new ShinyClientMessageEvent({ headline, message });
|
||||
const scopeElement = isJQuery(scope) ? scope.get(0) : scope;
|
||||
(scopeElement || window).dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -423,15 +458,7 @@ async function _bindAll(
|
||||
// complete error message that contains everything they will need to fix. If
|
||||
// we threw as we saw collisions then the user would fix the first collision,
|
||||
// re-run, and then see the next collision, etc.
|
||||
const bindingValidity = bindingsRegistry.checkValidity();
|
||||
if (bindingValidity.status === "error") {
|
||||
// Only throw if we're in dev mode. Otherwise, just log a warning.
|
||||
if (Shiny.inDevMode()) {
|
||||
throw bindingValidity.error;
|
||||
} else {
|
||||
console.warn("[shiny] " + bindingValidity.error.message);
|
||||
}
|
||||
}
|
||||
bindingsRegistry.checkValidity(scope);
|
||||
|
||||
return currentInputs;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { debounce, Debouncer } from "../time";
|
||||
import {
|
||||
$escape,
|
||||
compareVersion,
|
||||
getBoundingClientSizeBeforeZoom,
|
||||
getComputedLinkColor,
|
||||
getStyle,
|
||||
hasDefinedProperty,
|
||||
@@ -289,7 +290,7 @@ class ShinyClass {
|
||||
$(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(
|
||||
function () {
|
||||
const id = getIdFromEl(this),
|
||||
rect = this.getBoundingClientRect();
|
||||
rect = getBoundingClientSizeBeforeZoom(this);
|
||||
|
||||
if (rect.width !== 0 || rect.height !== 0) {
|
||||
initialValues[".clientdata_output_" + id + "_width"] = rect.width;
|
||||
@@ -425,7 +426,7 @@ class ShinyClass {
|
||||
$(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(
|
||||
function () {
|
||||
const id = getIdFromEl(this),
|
||||
rect = this.getBoundingClientRect();
|
||||
rect = getBoundingClientSizeBeforeZoom(this);
|
||||
|
||||
if (rect.width !== 0 || rect.height !== 0) {
|
||||
inputs.setInput(".clientdata_output_" + id + "_width", rect.width);
|
||||
|
||||
@@ -71,8 +71,12 @@ function remove(): void {
|
||||
// Look for a Bootstrap modal and if present, trigger hide event. This will
|
||||
// trigger the hidden.bs.modal callback that we set in show(), which unbinds
|
||||
// and removes the element.
|
||||
if ($modal.find(".modal").length > 0) {
|
||||
$modal.find(".modal").modal("hide");
|
||||
const $bsModal = $modal.find(".modal");
|
||||
if ($bsModal.length > 0) {
|
||||
// We both hide the modal when its shown and also immediately; the immediate
|
||||
// version is a no-op in Bootstrap if called before the modal is fully shown
|
||||
$bsModal.on("shown.bs.modal", () => $bsModal.modal("hide"));
|
||||
$bsModal.modal("hide");
|
||||
} else {
|
||||
// If not a Bootstrap modal dialog, simply unbind and remove it.
|
||||
shinyUnbindAll($modal);
|
||||
|
||||
@@ -1053,6 +1053,12 @@ class ShinyApp {
|
||||
const $tabContent = getTabContent($tabset);
|
||||
let tabsetId = $parentTabset.attr("data-tabsetid");
|
||||
|
||||
// TODO: Only render tab content HTML once
|
||||
// The following lines turn the content/nav control HTML into DOM nodes,
|
||||
// but we don't insert these directly, instead we take the HTML from
|
||||
// these nodes and pass it through `renderContentAsync()`. This means
|
||||
// the inserted HTML may not perfectly match the message HTML, esp. if
|
||||
// the content uses web components that alter their HTML when loaded.
|
||||
const $divTag = $(message.divTag.html);
|
||||
const $liTag = $(message.liTag.html);
|
||||
const $aTag = $liTag.find("> a");
|
||||
@@ -1166,12 +1172,14 @@ class ShinyApp {
|
||||
// Must not use jQuery for appending el to the doc, we don't want any
|
||||
// scripts to run (since they will run when renderContent takes a crack).
|
||||
$tabContent[0].appendChild(el);
|
||||
// If `el` itself is a script tag, this approach won't work (the script
|
||||
// won't be run), since we're only sending innerHTML through renderContent
|
||||
// and not the whole tag. That's fine in this case because we control the
|
||||
// R code that generates this HTML, and we know that the element is not
|
||||
// a script tag.
|
||||
await renderContentAsync(el, el.innerHTML || el.textContent);
|
||||
if (el.nodeType === Node.ELEMENT_NODE) {
|
||||
// If `el` itself is a script tag, this approach won't work (the script
|
||||
// won't be run), since we're only sending innerHTML through renderContent
|
||||
// and not the whole tag. That's fine in this case because we control the
|
||||
// R code that generates this HTML, and we know that the element is not
|
||||
// a script tag.
|
||||
await renderContentAsync(el, el.innerHTML || el.textContent);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.select) {
|
||||
|
||||
@@ -144,6 +144,20 @@ function pixelRatio(): number {
|
||||
}
|
||||
}
|
||||
|
||||
function getBoundingClientSizeBeforeZoom(el: HTMLElement): {
|
||||
width: number;
|
||||
height: number;
|
||||
} {
|
||||
const rect = el.getBoundingClientRect();
|
||||
// Cast to any because currentCSSZoom isn't in the type def of HTMLElement
|
||||
// TODO: typescript >= 5.5.2 added this property to the type definition
|
||||
const zoom = (el as any).currentCSSZoom || 1;
|
||||
return {
|
||||
width: rect.width / zoom,
|
||||
height: rect.height / zoom,
|
||||
};
|
||||
}
|
||||
|
||||
// Takes a string expression and returns a function that takes an argument.
|
||||
//
|
||||
// When the function is executed, it will evaluate that expression using
|
||||
@@ -398,6 +412,7 @@ export {
|
||||
formatDateUTC,
|
||||
makeResizeFilter,
|
||||
pixelRatio,
|
||||
getBoundingClientSizeBeforeZoom,
|
||||
scopeExprToFunc,
|
||||
asArray,
|
||||
mergeSort,
|
||||
|
||||
8
srcts/types/src/components/errorConsole.d.ts
vendored
8
srcts/types/src/components/errorConsole.d.ts
vendored
@@ -10,6 +10,11 @@ export declare class ShinyErrorMessage extends LitElement {
|
||||
copyErrorToClipboard(): Promise<void>;
|
||||
render(): import("lit-html").TemplateResult<1>;
|
||||
}
|
||||
export type ShinyClientMessage = {
|
||||
message: string;
|
||||
headline?: string;
|
||||
status?: "error" | "info" | "warning";
|
||||
};
|
||||
/**
|
||||
* Function to show an error message to user in shiny-error-message web
|
||||
* component. Only shows the error if we're in development mode.
|
||||
@@ -18,3 +23,6 @@ export declare class ShinyErrorMessage extends LitElement {
|
||||
* object.
|
||||
*/
|
||||
export declare function showErrorInClientConsole(e: unknown): void;
|
||||
export declare class ShinyClientMessageEvent extends CustomEvent<ShinyClientMessage> {
|
||||
constructor(detail: ShinyClientMessage);
|
||||
}
|
||||
|
||||
6
srcts/types/src/utils/index.d.ts
vendored
6
srcts/types/src/utils/index.d.ts
vendored
@@ -10,6 +10,10 @@ declare function parseDate(dateString: string): Date;
|
||||
declare function formatDateUTC(x: Date): string;
|
||||
declare function makeResizeFilter(el: HTMLElement, func: (width: HTMLElement["offsetWidth"], height: HTMLElement["offsetHeight"]) => void): () => void;
|
||||
declare function pixelRatio(): number;
|
||||
declare function getBoundingClientSizeBeforeZoom(el: HTMLElement): {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
declare function scopeExprToFunc(expr: string): (scope: unknown) => unknown;
|
||||
declare function asArray<T>(value: T | T[] | null | undefined): T[];
|
||||
declare function mergeSort<Item>(list: Item[], sortfunc: (a: Item, b: Item) => boolean | number): Item[];
|
||||
@@ -26,4 +30,4 @@ declare function updateLabel(labelTxt: string | undefined, labelNode: JQuery<HTM
|
||||
declare function getComputedLinkColor(el: HTMLElement): string;
|
||||
declare function isBS3(): boolean;
|
||||
declare function toLowerCase<T extends string>(str: T): Lowercase<T>;
|
||||
export { escapeHTML, randomId, strToBool, getStyle, padZeros, roundSignif, parseDate, formatDateUTC, makeResizeFilter, pixelRatio, scopeExprToFunc, asArray, mergeSort, $escape, mapValues, isnan, _equal, equal, compareVersion, updateLabel, getComputedLinkColor, hasOwnProperty, hasDefinedProperty, isBS3, toLowerCase, };
|
||||
export { escapeHTML, randomId, strToBool, getStyle, padZeros, roundSignif, parseDate, formatDateUTC, makeResizeFilter, pixelRatio, getBoundingClientSizeBeforeZoom, scopeExprToFunc, asArray, mergeSort, $escape, mapValues, isnan, _equal, equal, compareVersion, updateLabel, getComputedLinkColor, hasOwnProperty, hasDefinedProperty, isBS3, toLowerCase, };
|
||||
|
||||
685
tests/testthat/_snaps/stacks-deep.md
Normal file
685
tests/testthat/_snaps/stacks-deep.md
Normal file
@@ -0,0 +1,685 @@
|
||||
# deep stack capturing
|
||||
|
||||
Code
|
||||
cat(sep = "\n", formatError(err))
|
||||
Output
|
||||
Error in onFinally: boom
|
||||
: stop
|
||||
: onFinally [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: self$then
|
||||
: promise$finally
|
||||
: finally
|
||||
: onRejected [test-stacks-deep.R#XXX]
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onRejected
|
||||
: handleReject
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnRejected
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: self$then
|
||||
: promise$catch
|
||||
: catch
|
||||
: %...!%
|
||||
: onFulfilled [test-stacks-deep.R#XXX]
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
|
||||
---
|
||||
|
||||
Code
|
||||
cat(sep = "\n", formatError(err, full = TRUE))
|
||||
Output
|
||||
Error in onFinally: boom
|
||||
: h
|
||||
: .handleSimpleError
|
||||
: stop
|
||||
: onFinally [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: withCallingHandlers
|
||||
: callback
|
||||
: force
|
||||
: reenter_promise_domain
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: withVisible
|
||||
: private$doResolve
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: base::tryCatch
|
||||
: tryCatch
|
||||
: resolve
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: with_reporter
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: base::tryCatch
|
||||
: tryCatch
|
||||
: promise
|
||||
: self$then
|
||||
: promise$finally
|
||||
: finally
|
||||
: onRejected [test-stacks-deep.R#XXX]
|
||||
: withCallingHandlers
|
||||
: callback
|
||||
: force
|
||||
: reenter_promise_domain
|
||||
: <Anonymous>
|
||||
: onRejected
|
||||
: withVisible
|
||||
: private$doResolve
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: base::tryCatch
|
||||
: tryCatch
|
||||
: resolve
|
||||
: handleReject
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: with_reporter
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnRejected
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: base::tryCatch
|
||||
: tryCatch
|
||||
: promise
|
||||
: self$then
|
||||
: promise$catch
|
||||
: catch
|
||||
: %...!%
|
||||
: onFulfilled [test-stacks-deep.R#XXX]
|
||||
: withCallingHandlers
|
||||
: callback
|
||||
: force
|
||||
: reenter_promise_domain
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: withVisible
|
||||
: private$doResolve
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: base::tryCatch
|
||||
: tryCatch
|
||||
: resolve
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: with_reporter
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: base::tryCatch
|
||||
: tryCatch
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: withCallingHandlers [test-stacks-deep.R#XXX]
|
||||
: domain$wrapSync
|
||||
: promises::with_promise_domain
|
||||
: captureStackTraces
|
||||
: as.promise
|
||||
: catch
|
||||
: %...!%
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: withCallingHandlers
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: doTryCatch
|
||||
: tryCatchOne
|
||||
: tryCatchList
|
||||
: tryCatch
|
||||
: with_reporter
|
||||
: test_files_serial
|
||||
: test_files
|
||||
|
||||
# deep stacks long chain
|
||||
|
||||
Code
|
||||
cat(sep = "\n", stacktrace <- formatError(dserr))
|
||||
Output
|
||||
Error in onFulfilled: boom
|
||||
: stop
|
||||
: onFulfilled [test-stacks-deep.R#XXX]
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: J__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: I__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: H__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: G__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: F__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: E__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: D__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: C__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: B__ [test-stacks-deep.R#XXX]
|
||||
: onFulfilled
|
||||
: callback
|
||||
: <Anonymous>
|
||||
: onFulfilled
|
||||
: handleFulfill
|
||||
: <Anonymous>
|
||||
: execCallbacks
|
||||
: later::run_now
|
||||
: wait_for_it
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
From earlier call:
|
||||
: domain$wrapOnFulfilled
|
||||
: promiseDomain$onThen
|
||||
: action
|
||||
: promise
|
||||
: promise$then
|
||||
: then
|
||||
: %...>%
|
||||
: A__ [test-stacks-deep.R#XXX]
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: test_that
|
||||
: eval [test-stacks-deep.R#XXX]
|
||||
: eval
|
||||
: test_code
|
||||
: source_file
|
||||
: FUN
|
||||
: lapply
|
||||
: test_files_serial
|
||||
: test_files
|
||||
|
||||
90
tests/testthat/_snaps/stacks.md
Normal file
90
tests/testthat/_snaps/stacks.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# integration tests
|
||||
|
||||
Code
|
||||
df
|
||||
Output
|
||||
num call loc
|
||||
1 64 A [test-stacks.R#3]
|
||||
2 63 B [test-stacks.R#7]
|
||||
3 62 <reactive:C> [test-stacks.R#11]
|
||||
4 42 C
|
||||
5 41 renderTable [test-stacks.R#18]
|
||||
6 40 func
|
||||
7 39 force
|
||||
8 38 withVisible
|
||||
9 37 withCallingHandlers
|
||||
|
||||
---
|
||||
|
||||
Code
|
||||
df
|
||||
Output
|
||||
num call loc
|
||||
1 67 h
|
||||
2 66 .handleSimpleError
|
||||
3 65 stop
|
||||
4 64 A [test-stacks.R#3]
|
||||
5 63 B [test-stacks.R#7]
|
||||
6 62 <reactive:C> [test-stacks.R#11]
|
||||
7 61 ..stacktraceon..
|
||||
8 60 .func
|
||||
9 59 withVisible
|
||||
10 58 withCallingHandlers
|
||||
11 57 contextFunc
|
||||
12 56 env$runWith
|
||||
13 55 withCallingHandlers
|
||||
14 54 domain$wrapSync
|
||||
15 53 promises::with_promise_domain
|
||||
16 52 captureStackTraces
|
||||
17 51 force
|
||||
18 50 domain$wrapSync
|
||||
19 49 promises::with_promise_domain
|
||||
20 48 withReactiveDomain
|
||||
21 47 domain$wrapSync
|
||||
22 46 promises::with_promise_domain
|
||||
23 45 ctx$run
|
||||
24 44 self$.updateValue
|
||||
25 43 ..stacktraceoff..
|
||||
26 42 C
|
||||
27 41 renderTable [test-stacks.R#18]
|
||||
28 40 func
|
||||
29 39 force
|
||||
30 38 withVisible
|
||||
31 37 withCallingHandlers
|
||||
32 36 domain$wrapSync
|
||||
33 35 promises::with_promise_domain
|
||||
34 34 captureStackTraces
|
||||
35 33 doTryCatch
|
||||
36 32 tryCatchOne
|
||||
37 31 tryCatchList
|
||||
38 30 tryCatch
|
||||
39 29 do
|
||||
40 28 hybrid_chain
|
||||
41 27 renderFunc
|
||||
42 26 renderTable({ C() }, server = FALSE)
|
||||
43 25 ..stacktraceon.. [test-stacks.R#17]
|
||||
44 24 contextFunc
|
||||
45 23 env$runWith
|
||||
46 22 withCallingHandlers
|
||||
47 21 domain$wrapSync
|
||||
48 20 promises::with_promise_domain
|
||||
49 19 captureStackTraces
|
||||
50 18 force
|
||||
51 17 domain$wrapSync
|
||||
52 16 promises::with_promise_domain
|
||||
53 15 withReactiveDomain
|
||||
54 14 domain$wrapSync
|
||||
55 13 promises::with_promise_domain
|
||||
56 12 ctx$run
|
||||
57 11 ..stacktraceoff..
|
||||
58 10 isolate
|
||||
59 9 withCallingHandlers [test-stacks.R#16]
|
||||
60 8 domain$wrapSync
|
||||
61 7 promises::with_promise_domain
|
||||
62 6 captureStackTraces
|
||||
63 5 doTryCatch [test-stacks.R#15]
|
||||
64 4 tryCatchOne
|
||||
65 3 tryCatchList
|
||||
66 2 tryCatch
|
||||
67 1 try
|
||||
|
||||
49
tests/testthat/test-promise-domains.R
Normal file
49
tests/testthat/test-promise-domains.R
Normal file
@@ -0,0 +1,49 @@
|
||||
with_several_promise_domains <- function(expr) {
|
||||
withReactiveDomain(MockShinySession$new(), {
|
||||
promises::with_promise_domain(reactivePromiseDomain(), {
|
||||
captureStackTraces({
|
||||
expr
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
recursive_promise <- function(n, callback = identity) {
|
||||
if (n <= 0) {
|
||||
return(promise_resolve(0))
|
||||
}
|
||||
|
||||
p <- promises::promise_resolve(TRUE)
|
||||
promises::then(p, ~{
|
||||
callback(n)
|
||||
recursive_promise(n - 1, callback = callback)
|
||||
})
|
||||
}
|
||||
|
||||
test_that("Stack trace doesn't grow (resolution within domain)", {
|
||||
|
||||
depths <- list()
|
||||
with_several_promise_domains({
|
||||
recursive_promise(10, function(n) {
|
||||
depths <<- c(depths, list(length(sys.calls())))
|
||||
})
|
||||
while (!later::loop_empty()) {
|
||||
later::run_now()
|
||||
}
|
||||
})
|
||||
expect_equal(diff(range(depths)), 0)
|
||||
})
|
||||
|
||||
test_that("Stack trace doesn't grow (resolution outside domain)", {
|
||||
|
||||
depths <- list()
|
||||
with_several_promise_domains({
|
||||
recursive_promise(10, function(n) {
|
||||
depths <<- c(depths, list(length(sys.calls())))
|
||||
})
|
||||
})
|
||||
while (!later::loop_empty()) {
|
||||
later::run_now()
|
||||
}
|
||||
expect_equal(diff(range(depths)), 0)
|
||||
})
|
||||
@@ -129,13 +129,9 @@ test_that("message logger appears", {
|
||||
|
||||
|
||||
test_that("reactlog_version is as expected", {
|
||||
suggests <- strsplit(packageDescription("shiny")$Suggests, ",")[[1]]
|
||||
reactlog <- trimws(
|
||||
grep("reactlog", suggests, value = TRUE)
|
||||
)
|
||||
expect_length(reactlog, 1)
|
||||
expect_equal(
|
||||
reactlog,
|
||||
sprintf("reactlog (>= %s)", reactlog_min_version)
|
||||
expect_match(
|
||||
packageDescription("shiny")$Suggests,
|
||||
# The space between reactlog and the version number can include \n
|
||||
sprintf("\\breactlog\\s+\\Q(>= %s)\\E", reactlog_min_version)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,3 +1,47 @@
|
||||
formatError <- function(err, full = FALSE, offset = TRUE, cleanPaths = TRUE) {
|
||||
# This complicated capturing code is necessary because printStackTrace uses a
|
||||
# combination of `message()` and `cat(file=stderr())` to print the error,
|
||||
# stack traces, and stack trace boundaries ("From earlier call:"). We want to
|
||||
# treat all of it as part of the same string.
|
||||
|
||||
str <- noquote(capture.output(
|
||||
suppressWarnings(
|
||||
suppressMessages(
|
||||
withCallingHandlers(
|
||||
printError(err, full = full, offset = offset),
|
||||
warning = function(cnd) {
|
||||
cat(conditionMessage(cnd), "\n", sep = "", file = stderr())
|
||||
},
|
||||
message = function(cnd) {
|
||||
cat(conditionMessage(cnd), file = stderr())
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
type = "message"
|
||||
))
|
||||
|
||||
# Remove directories and line numbers from file/line references, e.g.
|
||||
# 53: callback [/Users/jcheng/Development/rstudio/shiny/R/conditions.R#155]
|
||||
# becomes
|
||||
# 53: callback [conditions.R#XXX]
|
||||
#
|
||||
# This is to make the snapshot tests more stable across different machines and
|
||||
# ignores benign code movement within a file.
|
||||
str <- sub("#\\d+\\]$", "#XXX]", str, perl = TRUE)
|
||||
# Remove any file/line number reference that's not test-stacks-deep.R. These
|
||||
# are just too inconsistent across different ways of invoking testthat--not
|
||||
# relative vs. absolute paths, but whether the file/line number is included at
|
||||
# all!
|
||||
str <- sub(" \\[(?!test-stacks-deep.R)[^[]+#XXX\\]", "", str, perl = TRUE)
|
||||
# The frame numbers vary too much between different ways of invoking testthat
|
||||
# ("Run Tests" editor toolbar button and "Test" Build tab button in RStudio,
|
||||
# devtools::test(), etc.) so we blank them out.
|
||||
str <- sub("^[ \\d]+:", " :", str, perl = TRUE)
|
||||
str
|
||||
}
|
||||
|
||||
|
||||
describe("deep stack trace filtering", {
|
||||
it("passes smoke test", {
|
||||
st <- list(
|
||||
@@ -43,3 +87,170 @@ describe("deep stack trace filtering", {
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test_that("deep stack capturing", {
|
||||
`%...>%` <- promises::`%...>%`
|
||||
`%...!%` <- promises::`%...!%`
|
||||
finally <- promises::finally
|
||||
|
||||
err <- NULL
|
||||
captureStackTraces({
|
||||
promise_resolve("one") %...>% {
|
||||
promise_reject("error") %...!% {
|
||||
finally(promise_resolve("two"), ~{
|
||||
stop("boom")
|
||||
})
|
||||
}
|
||||
}
|
||||
}) %...!% (function(err) {
|
||||
err <<- err
|
||||
})
|
||||
|
||||
wait_for_it()
|
||||
|
||||
expect_s3_class(err, "error", exact = FALSE)
|
||||
expect_snapshot(cat(sep="\n", formatError(err)))
|
||||
expect_snapshot(cat(sep="\n", formatError(err, full = TRUE)))
|
||||
})
|
||||
|
||||
test_that("deep stack capturing within reactives", {
|
||||
rerr <- NULL
|
||||
observe({
|
||||
promise_resolve("one") %...>% {
|
||||
promise_resolve("two") %...>% {
|
||||
stop("boom")
|
||||
}
|
||||
} %...!% (function(err) {
|
||||
rerr <<- err
|
||||
})
|
||||
})
|
||||
|
||||
flushReact()
|
||||
wait_for_it()
|
||||
|
||||
expect_s3_class(rerr, "error", exact = FALSE)
|
||||
expect_length(attr(rerr, "deep.stack.trace"), 2)
|
||||
})
|
||||
|
||||
test_that("deep stacks long chain", {
|
||||
op <- options(shiny.deepstacktrace = 3L)
|
||||
on.exit(options(op), add = TRUE, after = FALSE)
|
||||
|
||||
# Without deep stack traces, the stack trace would give no clue that the error
|
||||
# originally started from a call to `A__()`. With deep stack traces, we can
|
||||
# see that the error originated from `A__` and passed through `I__` and `J__`.
|
||||
# But due to culling, we don't see `B__` through `H__`--these are omitted for
|
||||
# brevity and to prevent unbounded growth of the accounting we do.
|
||||
|
||||
A__ <- function() promise_resolve(TRUE) %...>% B__()
|
||||
B__ <- function(x) promise_resolve(TRUE) %...>% C__()
|
||||
C__ <- function(x) promise_resolve(TRUE) %...>% D__()
|
||||
D__ <- function(x) promise_resolve(TRUE) %...>% E__()
|
||||
E__ <- function(x) promise_resolve(TRUE) %...>% F__()
|
||||
F__ <- function(x) promise_resolve(TRUE) %...>% G__()
|
||||
G__ <- function(x) promise_resolve(TRUE) %...>% H__()
|
||||
H__ <- function(x) promise_resolve(TRUE) %...>% I__()
|
||||
I__ <- function(x) promise_resolve(TRUE) %...>% J__()
|
||||
J__ <- function(x) promise_resolve(TRUE) %...>% { stop("boom") }
|
||||
|
||||
dserr <- NULL
|
||||
captureStackTraces(
|
||||
A__()
|
||||
) %...!% (function(err) {
|
||||
dserr <<- err
|
||||
})
|
||||
|
||||
wait_for_it()
|
||||
|
||||
expect_s3_class(dserr, "error", exact = FALSE)
|
||||
expect_snapshot(cat(sep="\n", stacktrace <- formatError(dserr)))
|
||||
# Ensure we dropTrivialTestFrames only when snapshotting
|
||||
expect_false(length(stacktrace) == length(formatError(dserr)))
|
||||
# Ensure that A__ through J__ are present in the traces
|
||||
for (letter in LETTERS[1:10]) {
|
||||
expect_length(which(grepl(paste0(letter, "__"), stacktrace)), 1L)
|
||||
}
|
||||
})
|
||||
|
||||
test_that("Deep stack deduplication", {
|
||||
recursive_promise <- function(n) {
|
||||
if (n <= 0) {
|
||||
stop("boom")
|
||||
}
|
||||
|
||||
p <- promises::promise_resolve(TRUE)
|
||||
promises::then(p, ~{
|
||||
recursive_promise(n - 1)
|
||||
})
|
||||
}
|
||||
|
||||
op <- options(shiny.deepstacktrace = TRUE)
|
||||
on.exit(options(op), add = TRUE, after = FALSE)
|
||||
|
||||
uerr <- NULL
|
||||
captureStackTraces(recursive_promise(100)) %...!% (function(err) {
|
||||
uerr <<- err
|
||||
})
|
||||
|
||||
wait_for_it()
|
||||
|
||||
expect_s3_class(uerr, "error", exact = FALSE)
|
||||
# Even though we traveled through 100 promises recursively, we only retained
|
||||
# the unique ones
|
||||
expect_identical(length(attr(uerr, "deep.stack.trace", exact = TRUE)), 2L)
|
||||
})
|
||||
|
||||
test_that("stack trace stripping works", {
|
||||
A__ <- function() promise_resolve(TRUE) %...>% B__()
|
||||
B__ <- function(x) promise_resolve(TRUE) %...>% { ..stacktraceoff..(C__()) }
|
||||
C__ <- function(x) promise_resolve(TRUE) %...>% D__()
|
||||
D__ <- function(x) promise_resolve(TRUE) %...>% { ..stacktraceon..(E__()) }
|
||||
E__ <- function(x) promise_resolve(TRUE) %...>% { stop("boom") }
|
||||
|
||||
strperr <- NULL
|
||||
captureStackTraces(A__()) %...!% (function(err) {
|
||||
strperr <<- err
|
||||
})
|
||||
|
||||
..stacktracefloor..(
|
||||
wait_for_it()
|
||||
)
|
||||
|
||||
expect_s3_class(strperr, "error", exact = FALSE)
|
||||
|
||||
str <- formatError(strperr)
|
||||
expect_length(which(grepl("A__", str)), 1L)
|
||||
expect_length(which(grepl("B__", str)), 1L)
|
||||
expect_length(which(grepl("C__", str)), 0L)
|
||||
expect_length(which(grepl("D__", str)), 0L)
|
||||
expect_length(which(grepl("E__", str)), 1L)
|
||||
|
||||
str_full <- formatError(strperr, full = TRUE)
|
||||
expect_length(which(grepl("A__", str_full)), 1L)
|
||||
expect_length(which(grepl("B__", str_full)), 1L)
|
||||
expect_length(which(grepl("C__", str_full)), 1L)
|
||||
expect_length(which(grepl("D__", str_full)), 1L)
|
||||
expect_length(which(grepl("E__", str_full)), 1L)
|
||||
})
|
||||
|
||||
test_that("coro async generator deep stack count is low", {
|
||||
gen <- coro::async_generator(function() {
|
||||
for (i in 1:50) {
|
||||
await(coro::async_sleep(0.001))
|
||||
yield(i)
|
||||
}
|
||||
stop("boom")
|
||||
})
|
||||
|
||||
cgerr <- NULL
|
||||
captureStackTraces(
|
||||
coro::async_collect(gen()) %...!% (function(err) {
|
||||
cgerr <<- err
|
||||
})
|
||||
)
|
||||
|
||||
wait_for_it()
|
||||
|
||||
expect_s3_class(cgerr, "error", exact = FALSE)
|
||||
expect_length(attr(cgerr, "deep.stack.trace"), 2L)
|
||||
})
|
||||
|
||||
@@ -98,14 +98,15 @@ extractStackTrace <- function(calls,
|
||||
num = index,
|
||||
call = getCallNames(calls),
|
||||
loc = getLocs(calls),
|
||||
category = getCallCategories(calls),
|
||||
# category = getCallCategories(calls),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
}
|
||||
|
||||
cleanLocs <- function(locs) {
|
||||
locs[!grepl("test-stacks\\.R", locs, perl = TRUE)] <- ""
|
||||
sub("^.*#", "", locs)
|
||||
# sub("^.*#", "", locs)
|
||||
locs
|
||||
}
|
||||
|
||||
dumpTests <- function(df) {
|
||||
@@ -129,46 +130,12 @@ test_that("integration tests", {
|
||||
df <- causeError(full = FALSE)
|
||||
# dumpTests(df)
|
||||
|
||||
expect_equal(df$num, c(56L, 55L, 54L, 38L, 37L, 36L, 35L, 34L, 33L))
|
||||
expect_equal(df$call, c("A", "B", "<reactive:C>", "C", "renderTable",
|
||||
"func", "force", "withVisible", "withCallingHandlers"))
|
||||
expect_equal(nzchar(df$loc), c(TRUE, TRUE, TRUE, FALSE, TRUE,
|
||||
FALSE, FALSE, FALSE, FALSE))
|
||||
expect_snapshot(df)
|
||||
|
||||
df <- causeError(full = TRUE)
|
||||
# dumpTests(df)
|
||||
|
||||
expect_equal(df$num, c(59L, 58L, 57L, 56L, 55L, 54L, 53L,
|
||||
52L, 51L, 50L, 49L, 48L, 47L, 46L, 45L, 44L, 43L, 42L, 41L,
|
||||
40L, 39L, 38L, 37L, 36L, 35L, 34L, 33L, 32L, 31L, 30L, 29L,
|
||||
28L, 27L, 26L, 25L, 24L, 23L, 22L, 21L, 20L, 19L, 18L, 17L,
|
||||
16L, 15L, 14L, 13L, 12L, 11L, 10L, 9L, 8L, 7L, 6L, 5L, 4L,
|
||||
3L, 2L, 1L))
|
||||
expect_equal(df$call, c("h", ".handleSimpleError", "stop",
|
||||
"A", "B", "<reactive:C>", "..stacktraceon..", ".func", "withVisible",
|
||||
"withCallingHandlers", "contextFunc", "env$runWith", "force",
|
||||
"domain$wrapSync", "promises::with_promise_domain",
|
||||
"withReactiveDomain", "domain$wrapSync", "promises::with_promise_domain",
|
||||
"ctx$run", "self$.updateValue", "..stacktraceoff..", "C",
|
||||
"renderTable", "func", "force", "withVisible", "withCallingHandlers",
|
||||
"domain$wrapSync", "promises::with_promise_domain",
|
||||
"captureStackTraces", "doTryCatch", "tryCatchOne", "tryCatchList",
|
||||
"tryCatch", "do", "hybrid_chain", "renderFunc", "renderTable({ C() }, server = FALSE)",
|
||||
"..stacktraceon..", "contextFunc", "env$runWith", "force",
|
||||
"domain$wrapSync", "promises::with_promise_domain",
|
||||
"withReactiveDomain", "domain$wrapSync", "promises::with_promise_domain",
|
||||
"ctx$run", "..stacktraceoff..", "isolate", "withCallingHandlers",
|
||||
"domain$wrapSync", "promises::with_promise_domain",
|
||||
"captureStackTraces", "doTryCatch", "tryCatchOne", "tryCatchList",
|
||||
"tryCatch", "try"))
|
||||
expect_equal(nzchar(df$loc), c(FALSE, FALSE, FALSE, TRUE,
|
||||
TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
|
||||
FALSE))
|
||||
expect_snapshot(df)
|
||||
# dumpTests(df)
|
||||
})
|
||||
|
||||
test_that("shiny.error", {
|
||||
@@ -239,6 +206,57 @@ test_that("validation error logging", {
|
||||
captureErrorLog(validate("boom"))
|
||||
expect_null(caught)
|
||||
|
||||
caught <- NULL
|
||||
captureErrorLog(stop("boom"))
|
||||
expect_true(!is.null(caught))
|
||||
})
|
||||
|
||||
test_that("observeEvent is not overly stripped (#4162)", {
|
||||
caught <- NULL
|
||||
..stacktraceoff..(
|
||||
..stacktracefloor..({
|
||||
observeEvent(1, {
|
||||
tryCatch(
|
||||
captureStackTraces(stop("boom")),
|
||||
error = function(cond) {
|
||||
caught <<- cond
|
||||
}
|
||||
)
|
||||
})
|
||||
flushReact()
|
||||
})
|
||||
)
|
||||
st_str <- capture.output(printStackTrace(caught), type = "message")
|
||||
expect_true(any(grepl("observeEvent\\(1\\)", st_str)))
|
||||
|
||||
# Now same thing, but deep stack trace version
|
||||
|
||||
A__ <- function() {
|
||||
promises::then(promises::promise_resolve(TRUE), ~{
|
||||
stop("boom")
|
||||
})
|
||||
}
|
||||
|
||||
B__ <- function() {
|
||||
promises::then(promises::promise_resolve(TRUE), ~{
|
||||
A__()
|
||||
})
|
||||
}
|
||||
|
||||
caught <- NULL
|
||||
..stacktraceoff..(
|
||||
..stacktracefloor..({
|
||||
observeEvent(1, {
|
||||
captureStackTraces(promises::catch(B__(), ~{
|
||||
caught <<- .
|
||||
}))
|
||||
})
|
||||
flushReact()
|
||||
wait_for_it()
|
||||
})
|
||||
)
|
||||
st_str <- capture.output(printStackTrace(caught), type = "message")
|
||||
# cat(st_str, sep = "\n")
|
||||
expect_true(any(grepl("A__", st_str)))
|
||||
expect_true(any(grepl("B__", st_str)))
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user