From 38b4bdd22f9e026e617d976588e360abaf7ae04c Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Tue, 6 Oct 2026 19:38:56 +0200
Subject: [PATCH 01/44] multi-dataset aware test analysis + local bundle build
- 'Test Multi-DataSet' (multiDataSetAware+preloadData) and its non-aware counterpart,
sharing R/multiDataSet.R and inst/qml/testMultiDataSet.qml: the VariablesForm
dataset/filter selection, per-dataset routing of encoded option values via
jaspBase's dataSetIdFromEncoded/dataSetNameFromEncoded/getDataSetColumn, a
.meta provenance dump and the readDataSet() guard demo.
- Tools/buildBundle.R: builds bundles_out/jaspTestModule.JASPModule with the local
jasp-desktop/Engine/jaspBase checkout swapped into renv.lock as a Local record
(verified inside the bundle afterwards); cellar-free, works on Arch R 4.6.1.
- renv.lock refresh for R 4.6.1 in the next commit (kept separate: buildBundle.R
swaps it transiently).
---
.gitignore | 2 +
NEWS.md | 11 +++
R/multiDataSet.R | 141 +++++++++++++++++++++++++++++++
Tools/buildBundle.R | 152 ++++++++++++++++++++++++++++++++++
inst/Description.qml | 30 +++++++
inst/qml/testMultiDataSet.qml | 48 +++++++++++
6 files changed, 384 insertions(+)
create mode 100644 R/multiDataSet.R
create mode 100644 Tools/buildBundle.R
create mode 100644 inst/qml/testMultiDataSet.qml
diff --git a/.gitignore b/.gitignore
index e1db096..adfe98d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,5 @@
.RData
.Ruserdata
_processedLockFile.lock
+ModuleBundleBuildDir/
+bundles_out/
diff --git a/NEWS.md b/NEWS.md
index 361436b..7b6cd18 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -15,6 +15,17 @@
---
# jaspTestModule (development version)
+## Added
+* "Test Multi-DataSet": analysis + form to exercise multi-dataset aware analyses
+ (`multiDataSetAware` Description entries, the VariablesForm dataset/filter selection,
+ the `datasets` handout and encoded-name routing of jaspBase, the readDataSet() guard,
+ the `.meta` dataSetId/filterId provenance and the non-aware counterpart as controls).
+* `Tools/buildBundle.R`: builds an installable `bundles_out/jaspTestModule.JASPModule`
+ from this checkout with the local `jasp-desktop/Engine/jaspBase` (or any checkout via
+ `JASP_BASE_DIR`) packed into the bundle; no JASP cellar needed.
+
+## Changed
+* `renv.lock` re-resolved for R 4.6.1 (current CRAN, jaspBase/jaspGraphs from GitHub HEAD).
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
new file mode 100644
index 0000000..1813867
--- /dev/null
+++ b/R/multiDataSet.R
@@ -0,0 +1,141 @@
+# Multi-dataset aware analyses (jasp-desktop branch dataSetAwareVarForm, jaspBase branch
+# multiDataSetAware). An analysis whose Description/Analysis entry sets multiDataSetAware gets
+# every dataset it references as `datasets`: a named list keyed by dataset id, with the user
+# facing titles in attr(datasets, "dataSetNames"). Its variable options carry encoded column
+# names whose prefix embeds the dataset they were selected from (JASPColumn__),
+# which jaspBase's dataSetIdFromEncoded / dataSetNameFromEncoded / getDataSetColumn route.
+# While such a run is active, readDataSet* stops: one 'current dataset' is meaningless here.
+
+multiDataSetFunc <- function(jaspResults, dataset, options, datasets = NULL) {
+ aware <- !is.null(datasets)
+
+ jaspResults[["explanation"]] <- createJaspHtml(paste0(
+ if (aware)
+ paste0("Aware run. This analysis received ", length(datasets),
+ " dataset(s) as the `datasets` argument; readDataSet() is disabled while it runs.")
+ else
+ "Non-aware run. No `datasets` argument: data comes in through `dataset`/readDataSet as always, and the dataset selection in the form should have been inert.",
+ "
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form."))
+
+ dataSetOverviewTable(jaspResults, datasets, dataset)
+ selectedVariablesTable(jaspResults, options, datasets, dataset)
+
+ if (isTRUE(options$showMeta))
+ metaDump(jaspResults, options)
+
+ if (isTRUE(options$guardDemo))
+ readDataSetGuardDemo(jaspResults)
+}
+
+dataSetOverviewTable <- function(jaspResults, datasets, dataset) {
+ table <- createJaspTable("Datasets in this run")
+ jaspResults[["dataSetOverview"]] <- table
+
+ table$addColumnInfo("id", title = "Dataset id")
+ table$addColumnInfo("title", title = "Title")
+ table$addColumnInfo("rows", title = "Rows")
+ table$addColumnInfo("cols", title = "Columns")
+ table$addColumnInfo("columnNames", title = "Column names")
+
+ if (!is.null(datasets)) {
+ titles <- attr(datasets, "dataSetNames")
+
+ for (id in names(datasets)) {
+ df <- datasets[[id]]
+ table[[id]] <- list(
+ id = id, title = titles[[id]], rows = nrow(df), cols = ncol(df),
+ columnNames = paste(names(df), collapse = ", "))
+ }
+ } else if (!is.null(dataset)) {
+ table[["current"]] <- list(
+ id = "(current)", title = "(the one dataset)", rows = nrow(dataset), ncol(dataset),
+ columnNames = paste(names(dataset), collapse = ", "))
+ }
+}
+
+selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
+ table <- createJaspTable("Selected variables")
+ jaspResults[["selectedVariables"]] <- table
+
+ table$addColumnInfo("variable", title = "Variable (routed to)")
+ table$addColumnInfo("dataSetId", title = "Dataset id")
+ table$addColumnInfo("dataSetName", title = "Dataset title")
+ table$addColumnInfo("column", title = "Column")
+ table$addColumnInfo("type", title = "Type")
+ table$addColumnInfo("n", title = "n")
+ table$addColumnInfo("values", title = "mean (scale) / first levels (factor)")
+
+ values <- .dependentValues(options)
+
+ for (value in values) {
+ if (is.null(datasets)) {
+ # Non-aware: plain preload semantics, decode against the current encoder.
+ column <- sub("\\.(scale|ordinal|nominal)$", "", jaspBase::decodeColNames(value))
+ entry <- list(variable = column, dataSetId = "-", dataSetName = "-", column = column,
+ type = .typeSuffix(value), n = NA_integer_, values = "")
+ if (!is.null(dataset) && column %in% names(dataset))
+ entry <- c(entry, .describeColumn(dataset[[column]]))
+ table[[value]] <- entry
+ next
+ }
+
+ id <- jaspBase::dataSetIdFromEncoded(value)
+ column <- jaspBase::dataSetColumnFromEncoded(value, datasets)
+ entry <- list(
+ variable = value,
+ dataSetId = if (is.na(id)) "none (legacy)" else id,
+ dataSetName = jaspBase::dataSetNameFromEncoded(value, datasets),
+ column = column,
+ type = .typeSuffix(value),
+ n = NA_integer_, values = "")
+
+ columnData <- jaspBase::getDataSetColumn(value, datasets)
+ if (!is.null(columnData))
+ entry <- c(entry, .describeColumn(columnData))
+
+ table[[value]] <- entry
+ }
+}
+
+metaDump <- function(jaspResults, options) {
+ meta <- options[[".meta"]]
+ jaspResults[["metaDump"]] <- createJaspHtml(paste0(
+ "options$.meta
",
+ jsonlite::toJSON(if (is.null(meta)) list() else meta, auto_unbox = TRUE, pretty = 2),
+ "
"))
+}
+
+readDataSetGuardDemo <- function(jaspResults) {
+ message <- tryCatch(
+ {
+ .readDataSetToEnd(columns = "MPG") # would work outside an aware run
+ "No error - readDataSet() should have stopped though! (not in multi-dataset mode?)"
+ },
+ error = function(e) paste0("readDataSet() stopped it, as it should:
",
+ "", conditionMessage(e), "
"))
+
+ jaspResults[["guardDemo"]] <- createJaspHtml(message)
+}
+
+# ------------------------------------------------------------------ internals
+
+.dependentValues <- function(options) {
+ values <- unlist(options$dependent, recursive = TRUE)
+ values[!is.na(values) & as.character(values) != ""]
+}
+
+.typeSuffix <- function(value) {
+ match <- regmatches(as.character(value), regexec("\\.(scale|ordinal|nominal)$", value))[[1]]
+ if (length(match) == 2L) match[2] else NA_character_
+}
+
+.describeColumn <- function(columnData) {
+ if (is.numeric(columnData)) {
+ list(n = sum(!is.na(columnData)),
+ values = sprintf("mean %.2f, sd %.2f", mean(columnData, na.rm = TRUE), sd(columnData, na.rm = TRUE)))
+ } else {
+ levels <- unique(as.character(stats::na.omit(columnData)))
+ list(n = length(stats::na.omit(columnData)),
+ values = paste(utils::head(levels, 5), collapse = ", "))
+ }
+}
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
new file mode 100644
index 0000000..23bf84d
--- /dev/null
+++ b/Tools/buildBundle.R
@@ -0,0 +1,152 @@
+#!/usr/bin/env Rscript
+# Build an installable .JASPModule bundle of jaspTestModule from this checkout.
+#
+# The jaspBase record in renv.lock is temporarily swapped for a Local record pointing at the
+# jasp-desktop checkout (default: ../jasp-desktop/Engine/jaspBase), so whatever is checked out
+# there (e.g. branch multiDataSetAware) is compiled and packed into the bundle. Everything is
+# built from source into a private renv library under ModuleBundleBuildDir/ - no JASP cellar
+# involved, so it works on a rolling-release system (Arch) with the R you have.
+#
+# Requires the tool library (jaspModuleTools + jaspModuleBundleManager + renv etc.), by default
+# ../.toolLib; see the bottom of this file for how it was created.
+#
+# Usage (from the jaspTestModule directory, or anywhere):
+# Rscript Tools/buildBundle.R # bundle with local jaspBase
+# Rscript Tools/buildBundle.R --update-lockfile # re-resolve renv.lock first (network)
+# Rscript Tools/buildBundle.R --remote-jaspbase # use the jaspBase from renv.lock (GitHub)
+# Rscript Tools/buildBundle.R --jasp-version=development
+#
+# Result: bundles_out/jaspTestModule.JASPModule (+ manifest json), installable via
+# JASP: + (add modules) menu -> Add module -> From file.
+#
+# One-time tool library setup:
+# toolLib=/path/to/.toolLib; mkdir -p $toolLib
+# Rscript -e '.libPaths(c(toolLib, .libPaths()))
+# install.packages(c("renv","fs","pkgdepends","usethis","withr","curl","rjson","stringr",
+# "archive","openssl","jsonlite","remotes"), lib=toolLib,
+# repos="https://cloud.r-project.org")
+# remotes::install_local("/Engine/jaspModuleBundleManager", lib=toolLib,
+# upgrade="never", dependencies=FALSE)
+# remotes::install_local("", lib=toolLib,
+# upgrade="never", dependencies=FALSE)'
+
+args <- commandArgs(trailingOnly = TRUE)
+
+scriptPath <- normalizePath(sub("^--file=", "", grep("^--file=", commandArgs(FALSE), value = TRUE)[[1]]))
+moduledir <- normalizePath(file.path(dirname(scriptPath), ".."))
+rootdir <- normalizePath(file.path(moduledir, ".."))
+
+jaspBaseDir <- Sys.getenv("JASP_BASE_DIR", file.path(rootdir, "jasp-desktop", "Engine", "jaspBase"))
+toolLib <- Sys.getenv("JASP_MODULE_TOOLLIB", file.path(rootdir, ".toolLib"))
+workdir <- file.path(moduledir, "ModuleBundleBuildDir")
+resultdir <- file.path(moduledir, "bundles_out")
+
+localJaspBase <- !("--remote-jaspbase" %in% args)
+updateLockfile <- "--update-lockfile" %in% args
+
+jaspVersion <- "development"
+for (a in args) if (grepl("^--jasp-version=", a)) jaspVersion <- sub("^--jasp-version=", "", a)
+
+if (!dir.exists(toolLib))
+ stop("Tool library not found at ", toolLib, " - see the setup instructions at the bottom of this script.")
+
+.libPaths(c(toolLib, .libPaths()))
+suppressPackageStartupMessages({ library(jsonlite) })
+library(jaspModuleTools)
+
+# No renv sandbox: binary R distributions (Arch!) have no R sources to link it against.
+Sys.setenv(RENV_CONFIG_SANDBOX_ENABLED = "false")
+options(jaspRemoteCellarRedownload = FALSE)
+
+lockPath <- file.path(moduledir, "renv.lock")
+lockBackup <- NULL
+on.exit({
+ if (!is.null(lockBackup)) {
+ writeLines(lockBackup, lockPath)
+ message("restored original ", lockPath)
+ }
+})
+
+if (updateLockfile) {
+ message("re-resolving ", lockPath, " with pkgdepends ...")
+ jaspModuleTools::updateLockfile(moduledir)
+}
+
+if (localJaspBase) {
+ if (!dir.exists(jaspBaseDir))
+ stop("No jaspBase checkout at ", jaspBaseDir, " (set JASP_BASE_DIR or use --remote-jaspbase).")
+
+ baseDesc <- read.dcf(file.path(jaspBaseDir, "DESCRIPTION"))[1, ]
+ message("swapping jaspBase in renv.lock for local checkout: ", jaspBaseDir,
+ " (v", baseDesc[["Version"]], ", ",
+ system2("git", c("-C", jaspBaseDir, "rev-parse", "--abbrev-ref", "HEAD"), stdout = TRUE), ")")
+
+ lockBackup <- readLines(lockPath)
+ lock <- jsonlite::fromJSON(lockPath, simplifyVector = FALSE)
+
+ depsFields <- baseDesc[c("Depends", "Imports")]
+ depsFields <- depsFields[!is.na(depsFields)]
+ requires <- unique(trimws(unlist(strsplit(paste(depsFields, collapse = ","), ","))))
+ requires <- gsub("\\s*\\(.*", "", requires) # "Rcpp (>= 0.12.14)" -> "Rcpp"
+ requires <- setdiff(requires, c("", "R"))
+
+ # Same local-record shape jaspModuleTools uses for the module itself (createLocalRecord).
+ lock$Packages$jaspBase <- list(
+ Package = "jaspBase",
+ Version = baseDesc[["Version"]],
+ Source = "Local",
+ Requirements = requires,
+ RemoteType = "local",
+ RemoteUrl = normalizePath(jaspBaseDir),
+ Cacheable = TRUE,
+ Hash = unname(rlang::hash(rlang::hash_file(fs::dir_ls(jaspBaseDir, type = "file", recurse = TRUE))))
+ )
+
+ writeLines(jsonlite::toJSON(lock, auto_unbox = TRUE, pretty = 2), lockPath)
+}
+
+dir.create(workdir, recursive = TRUE, showWarnings = FALSE)
+dir.create(resultdir, showWarnings = FALSE)
+
+message("compiling + bundling (log is chatty, first run compiles all of jaspBase's deps) ...")
+jaspModuleTools::compile(
+ moduledir = moduledir,
+ workdir = file.path(workdir, "build_dir"),
+ resultdir = resultdir,
+ createBundle = TRUE,
+ bundleAll = TRUE,
+ buildforJaspVersion = jaspVersion,
+ useJASPRemoteCellar = FALSE,
+ localizeJASPModules = "identicalToLockfile" # our lockfile (incl. the swapped jaspBase) is what we want
+)
+
+# restore the pristine lockfile before verifying so an interrupted run can't leak the local record
+if (!is.null(lockBackup)) { writeLines(lockBackup, lockPath); lockBackup <- NULL }
+
+# ---------------------------------------------------------------------------------------------
+# Verify: the bundle manifest must list jaspBase, and the packed jaspBase must be OUR checkout
+# (guard against silently packing a cached GitHub build instead).
+bundle <- file.path(resultdir, "jaspTestModule.JASPModule")
+if (!file.exists(bundle)) stop("compile() did not produce ", bundle)
+
+checkdir <- file.path(tempdir(), "bundleCheck")
+unlink(checkdir, recursive = TRUE); dir.create(checkdir, recursive = TRUE)
+archive::archive_extract(bundle, dir = checkdir)
+
+manifest <- jsonlite::fromJSON(file.path(checkdir, "jaspTestModule_manifest.json"))
+jaspBaseHash <- sub(" .*", "", grep("^jaspBase ", manifest$mapping, value = TRUE))
+if (length(jaspBaseHash) != 1) stop("jaspBase not in the bundle manifest (mapping: ", manifest$mapping, ")")
+
+pkgdir <- file.path(checkdir, "jaspBase")
+archive::archive_extract(file.path(checkdir, jaspBaseHash), dir = pkgdir)
+
+commonR <- file.path(pkgdir, "jaspBase", "R", "common.R")
+if (!file.exists(commonR)) commonR <- file.path(pkgdir, "common.R") # L0 tar may sit one level deeper
+packed <- paste(readLines(commonR), collapse = "\n")
+if (localJaspBase) {
+ stopifnot(grepl("\\.multiDataSetMode", packed), grepl("dataSetColumnFromEncoded", packed))
+ message("VERIFIED: bundled jaspBase contains the multiDataSetAware code (.multiDataSetMode + dataSetColumnFromEncoded).")
+}
+
+message("Bundle: ", bundle, " (size: ", format(file.size(bundle) / 2^20, digits = 1), " MiB)")
+message("Install in JASP: + menu -> Add module -> From file, pick that .JASPModule.")
diff --git a/inst/Description.qml b/inst/Description.qml
index a6b066d..ca0f46d 100644
--- a/inst/Description.qml
+++ b/inst/Description.qml
@@ -106,6 +106,36 @@ Description
preloadData : true
}
+ Separator {}
+
+ GroupTitle { title: "Multi dataset" }
+
+ // multiDataSetAware: the analysis gets every dataset its options reference as the `datasets`
+ // argument (jaspBase >= the multiDataSetAware branch) and VariablesForm's dataSetSelection
+ // dropdown becomes live. It only kicks in combined with preloadData; without it the engine
+ // logs that the analysis gets its data like a non-aware one.
+ Analysis
+ {
+ title: "Test Multi-DataSet"
+ qml: "testMultiDataSet.qml"
+ func: "multiDataSetFunc"
+ requiresData: true
+ preloadData: true
+ multiDataSetAware: true
+ }
+
+ // Same form and function, but NOT aware: dataSetSelection must stay inert and data must
+ // arrive the old way (through dataset/readDataSet), as a controls-and-regression check.
+ Analysis
+ {
+ title: "Test Multi-DataSet (non-aware counterpart)"
+ qml: "testMultiDataSet.qml"
+ func: "multiDataSetFunc"
+ requiresData: true
+ preloadData: true
+ multiDataSetAware: false
+ }
+
Analysis
{
title: qsTr("Test optionContainsValue")
diff --git a/inst/qml/testMultiDataSet.qml b/inst/qml/testMultiDataSet.qml
new file mode 100644
index 0000000..87167c6
--- /dev/null
+++ b/inst/qml/testMultiDataSet.qml
@@ -0,0 +1,48 @@
+import QtQuick
+import JASP.Controls
+
+Form
+{
+ columns: 1
+
+ ExplanationText
+ {
+ text:
+ "Test the multi-dataset awareness of VariablesForm: the dataset/filter selection at the top " +
+ "(only live for multiDataSetAware analyses) plus the per-dataset routing in the results.
" +
+ "" +
+ "- Open a second dataset (e.g. add another CSV) so the selection has something to choose from.
" +
+ "- Drag variables from different datasets into the list: the results table should route " +
+ "each one to its own dataset (id, title, column).
" +
+ "- Pick another dataset/filter in the selection: only columns of that dataset should remain " +
+ "selectable for new drags and the run should recompute.
" +
+ "- show .meta: the provenance stamps (dataSetId/filterId) on the bound options.
" +
+ "- guard demo: readDataSet() must hard-stop inside an aware run.
" +
+ "- Save the analysis to a .jasp and reopen it: the dataset routing must survive the round trip.
" +
+ "
"
+ }
+
+ VariablesForm
+ {
+ dataSetSelection: true
+
+ AvailableVariablesList { name: "allVariables" }
+ AssignedVariablesList
+ {
+ name: "dependent"
+ title: qsTr("Variables (from any dataset)")
+ }
+ }
+
+ CheckBox
+ {
+ name: "showMeta"
+ label: qsTr("Show options .meta (dataSetId/filterId provenance)")
+ }
+
+ CheckBox
+ {
+ name: "guardDemo"
+ label: qsTr("Call readDataSet() anyway (should error in aware runs)")
+ }
+}
From 2bcce9808e578b7c9e5a8a56754a771633df4989 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Tue, 6 Oct 2026 20:10:02 +0200
Subject: [PATCH 02/44] renv.lock for R 4.6.1 + working bundle build (local
jaspBase swapped in)
- renv.lock re-resolved on R 4.6.1 (jaspBase 6a6910db / jaspGraphs cdc4c9cf from GitHub).
- Tools/buildBundle.R end-to-end on Arch: local-jaspBase Local record swapped into a
copy of the lock during the build (tryCatch/finally restore - top-level on.exit is a
no-op in Rscript), fake renv sandbox (symlink farm at the resolved
RENV_PATHS_SANDBOX path) so jaspModuleTools' copy of restore-skipped recommended
packages (codetools) works on binary R, --check-only to re-verify a bundle without
rebuilding, and manifest/namespace verification that loads the bundled jaspBase and
asserts the multiDataSetAware code is in it.
- Tools/testdata: DataSetA/DataSetB.csv with deliberately overlapping column names
(Score, Age) for the per-dataset routing test.
---
Tools/buildBundle.R | 62 +++++++++++++++------
Tools/testdata/DataSetA.csv | 11 ++++
Tools/testdata/DataSetB.csv | 11 ++++
renv.lock | 104 +++++++++++++++++++-----------------
4 files changed, 121 insertions(+), 67 deletions(-)
create mode 100644 Tools/testdata/DataSetA.csv
create mode 100644 Tools/testdata/DataSetB.csv
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index 23bf84d..7b4d398 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -60,19 +60,37 @@ options(jaspRemoteCellarRedownload = FALSE)
lockPath <- file.path(moduledir, "renv.lock")
lockBackup <- NULL
-on.exit({
+
+restoreLock <- function() {
if (!is.null(lockBackup)) {
writeLines(lockBackup, lockPath)
+ lockBackup <<- NULL
message("restored original ", lockPath)
}
-})
+}
if (updateLockfile) {
message("re-resolving ", lockPath, " with pkgdepends ...")
jaspModuleTools::updateLockfile(moduledir)
+ lockBackup <- readLines(lockPath) # keep the freshly resolved one; never lose it
}
-if (localJaspBase) {
+dir.create(workdir, recursive = TRUE, showWarnings = FALSE)
+
+# Binary R distributions (Arch!) have no R sources, so renv's sandbox can't be built - but
+# jaspModuleTools copies packages that renv::restore skips because they live in the system
+# library (recommended ones like codetools) out of it. Fake it: the sandbox is nothing but a
+# symlink farm over the system library, so build exactly that at the path renv resolves
+# (RENV_PATHS_SANDBOX plus its linux-arch-rolling/R-4.6/ suffix).
+Sys.setenv(RENV_PATHS_SANDBOX = file.path(workdir, "sandbox"))
+fakeSandbox <- renv:::renv_paths_sandbox()
+dir.create(fakeSandbox, recursive = TRUE, showWarnings = FALSE)
+for (lib in unique(c(R.home("library"), .libPaths())))
+ for (pkg in list.dirs(lib, recursive = FALSE, full.names = FALSE))
+ if (!file.exists(file.path(fakeSandbox, pkg)) && nzchar(pkg) && !grepl("^00LOCK", pkg))
+ file.symlink(file.path(lib, pkg), file.path(fakeSandbox, pkg))
+
+if (localJaspBase && !("--check-only" %in% args)) {
if (!dir.exists(jaspBaseDir))
stop("No jaspBase checkout at ", jaspBaseDir, " (set JASP_BASE_DIR or use --remote-jaspbase).")
@@ -105,11 +123,10 @@ if (localJaspBase) {
writeLines(jsonlite::toJSON(lock, auto_unbox = TRUE, pretty = 2), lockPath)
}
-dir.create(workdir, recursive = TRUE, showWarnings = FALSE)
dir.create(resultdir, showWarnings = FALSE)
message("compiling + bundling (log is chatty, first run compiles all of jaspBase's deps) ...")
-jaspModuleTools::compile(
+if (!("--check-only" %in% args)) tryCatch(jaspModuleTools::compile(
moduledir = moduledir,
workdir = file.path(workdir, "build_dir"),
resultdir = resultdir,
@@ -118,10 +135,12 @@ jaspModuleTools::compile(
buildforJaspVersion = jaspVersion,
useJASPRemoteCellar = FALSE,
localizeJASPModules = "identicalToLockfile" # our lockfile (incl. the swapped jaspBase) is what we want
-)
-
-# restore the pristine lockfile before verifying so an interrupted run can't leak the local record
-if (!is.null(lockBackup)) { writeLines(lockBackup, lockPath); lockBackup <- NULL }
+), error = function(e) {
+ message("compile() failed: ", conditionMessage(e))
+ calls <- sys.calls()
+ for (i in seq_along(calls)) message(sprintf(" #%02d %s", i, substr(paste(deparse(calls[[i]]), collapse = " "), 1, 160)))
+ stop(e)
+}, finally = restoreLock())
# ---------------------------------------------------------------------------------------------
# Verify: the bundle manifest must list jaspBase, and the packed jaspBase must be OUR checkout
@@ -134,18 +153,27 @@ unlink(checkdir, recursive = TRUE); dir.create(checkdir, recursive = TRUE)
archive::archive_extract(bundle, dir = checkdir)
manifest <- jsonlite::fromJSON(file.path(checkdir, "jaspTestModule_manifest.json"))
-jaspBaseHash <- sub(" .*", "", grep("^jaspBase ", manifest$mapping, value = TRUE))
-if (length(jaspBaseHash) != 1) stop("jaspBase not in the bundle manifest (mapping: ", manifest$mapping, ")")
+jaspBaseHash <- sub(" .*", "", grep("=> jaspBase_", manifest$mapping, value = TRUE))
+if (length(jaspBaseHash) != 1) stop("jaspBase not in the bundle manifest (mapping: ", paste(manifest$mapping, collapse=", "), ")")
-pkgdir <- file.path(checkdir, "jaspBase")
+pkgdir <- file.path(checkdir, "lib", "jaspBase")
+dir.create(pkgdir, recursive = TRUE, showWarnings = FALSE)
archive::archive_extract(file.path(checkdir, jaspBaseHash), dir = pkgdir)
-commonR <- file.path(pkgdir, "jaspBase", "R", "common.R")
-if (!file.exists(commonR)) commonR <- file.path(pkgdir, "common.R") # L0 tar may sit one level deeper
-packed <- paste(readLines(commonR), collapse = "\n")
+# The L0 tars are *installed* package trees: load the bundled jaspBase and look at what is
+# actually in it. That proves OUR build (not some cached GitHub one) is in the bundle.
+.libPaths(c(file.path(checkdir, "lib"), file.path(workdir, "build_dir", "jaspTestModule"), .libPaths()))
+suppressPackageStartupMessages(library(jaspBase, lib.loc = file.path(checkdir, "lib")))
+
if (localJaspBase) {
- stopifnot(grepl("\\.multiDataSetMode", packed), grepl("dataSetColumnFromEncoded", packed))
- message("VERIFIED: bundled jaspBase contains the multiDataSetAware code (.multiDataSetMode + dataSetColumnFromEncoded).")
+ markers <- c("dataSetColumnFromEncoded", "dataSetIdFromEncoded", "getDataSetColumn") %in% getNamespaceExports("jaspBase")
+ runBody <- any(grepl("multiDataSet|dataSetEncodedNames", deparse(body(jaspBase::runJaspResults))))
+ if (!all(markers) || !runBody)
+ stop("bundled jaspBase is MISSING the local multiDataSetAware code (exports: ",
+ paste(names(markers)[!markers], collapse = ", "), if (runBody) "" else " + runJaspResults body", ")")
+ message("VERIFIED: bundled jaspBase loads and carries the local multiDataSetAware code.")
+} else {
+ message("bundle jaspBase version: ", as.character(utils::packageVersion("jaspBase", lib.loc = file.path(checkdir, "lib"))))
}
message("Bundle: ", bundle, " (size: ", format(file.size(bundle) / 2^20, digits = 1), " MiB)")
diff --git a/Tools/testdata/DataSetA.csv b/Tools/testdata/DataSetA.csv
new file mode 100644
index 0000000..0927de6
--- /dev/null
+++ b/Tools/testdata/DataSetA.csv
@@ -0,0 +1,11 @@
+Score,Age,Group
+12.5,31,A
+9.1,45,B
+15.3,28,A
+7.8,52,C
+19.6,37,B
+11.2,41,A
+8.4,33,C
+16.9,29,B
+13.7,48,A
+10.5,36,C
diff --git a/Tools/testdata/DataSetB.csv b/Tools/testdata/DataSetB.csv
new file mode 100644
index 0000000..6673ac3
--- /dev/null
+++ b/Tools/testdata/DataSetB.csv
@@ -0,0 +1,11 @@
+Score,Age,Condition
+22.4,61,X
+14.8,39,Y
+18.2,44,X
+9.9,50,Z
+25.1,35,Y
+12.6,58,X
+21.3,42,Z
+17.7,47,Y
+11.8,53,X
+23.5,38,Z
diff --git a/renv.lock b/renv.lock
index 3b3ac06..e171ff6 100644
--- a/renv.lock
+++ b/renv.lock
@@ -1,6 +1,6 @@
{
"R": {
- "Version": "4.5.2",
+ "Version": "4.6.1",
"Repositories": [
{
"Name": "CRAN",
@@ -27,7 +27,7 @@
},
"Rcpp": {
"Package": "Rcpp",
- "Version": "1.1.1",
+ "Version": "1.1.2",
"Source": "Repository",
"Requirements": [
"methods",
@@ -37,7 +37,7 @@
},
"S7": {
"Package": "S7",
- "Version": "0.2.1",
+ "Version": "0.2.2",
"Source": "Repository",
"Requirements": [
"R",
@@ -54,7 +54,7 @@
},
"base64enc": {
"Package": "base64enc",
- "Version": "0.1-3",
+ "Version": "0.1-6",
"Source": "Repository",
"Requirements": [
"R"
@@ -62,7 +62,7 @@
},
"bslib": {
"Package": "bslib",
- "Version": "0.9.0",
+ "Version": "0.12.0",
"Source": "Repository",
"Requirements": [
"base64enc",
@@ -91,9 +91,10 @@
},
"callr": {
"Package": "callr",
- "Version": "3.7.6",
+ "Version": "3.8.0",
"Source": "Repository",
"Requirements": [
+ "otel",
"processx",
"R",
"R6",
@@ -102,7 +103,7 @@
},
"cli": {
"Package": "cli",
- "Version": "3.6.5",
+ "Version": "3.6.6",
"Source": "Repository",
"Requirements": [
"R",
@@ -119,7 +120,7 @@
},
"cpp11": {
"Package": "cpp11",
- "Version": "0.5.2",
+ "Version": "0.5.5",
"Source": "Repository",
"Requirements": [
"R"
@@ -138,7 +139,7 @@
},
"curl": {
"Package": "curl",
- "Version": "7.0.0",
+ "Version": "8.0.0",
"Source": "Repository",
"Requirements": [
"R"
@@ -146,7 +147,7 @@
},
"data.table": {
"Package": "data.table",
- "Version": "1.18.0",
+ "Version": "1.18.6.1",
"Source": "Repository",
"Requirements": [
"methods",
@@ -175,7 +176,7 @@
},
"dplyr": {
"Package": "dplyr",
- "Version": "1.1.4",
+ "Version": "1.2.1",
"Source": "Repository",
"Requirements": [
"cli",
@@ -252,7 +253,7 @@
},
"fs": {
"Package": "fs",
- "Version": "1.6.6",
+ "Version": "2.1.0",
"Source": "Repository",
"Requirements": [
"methods",
@@ -261,7 +262,7 @@
},
"gdtools": {
"Package": "gdtools",
- "Version": "0.4.4",
+ "Version": "0.5.1",
"Source": "Repository",
"Requirements": [
"fontquiver",
@@ -283,7 +284,7 @@
},
"ggplot2": {
"Package": "ggplot2",
- "Version": "4.0.1",
+ "Version": "4.0.3",
"Source": "Repository",
"Requirements": [
"cli",
@@ -303,7 +304,7 @@
},
"glue": {
"Package": "glue",
- "Version": "1.8.0",
+ "Version": "1.8.1",
"Source": "Repository",
"Requirements": [
"methods",
@@ -312,7 +313,7 @@
},
"gridExtra": {
"Package": "gridExtra",
- "Version": "2.3",
+ "Version": "2.3.1",
"Source": "Repository",
"Requirements": [
"graphics",
@@ -348,7 +349,7 @@
},
"highr": {
"Package": "highr",
- "Version": "0.11",
+ "Version": "0.12",
"Source": "Repository",
"Requirements": [
"R",
@@ -384,7 +385,7 @@
},
"httr": {
"Package": "httr",
- "Version": "1.4.7",
+ "Version": "1.4.9",
"Source": "Repository",
"Requirements": [
"curl",
@@ -436,14 +437,13 @@
"RemoteHost": "api.github.com",
"RemoteUsername": "jasp-stats",
"RemoteRepo": "jaspBase",
- "RemoteSha": "a5770b1bb36f6c5aebca3d15e5eab0dd4976602e"
+ "RemoteSha": "6a6910dbe148caba2d82d60b8c42305ac40d2f1d"
},
"jaspGraphs": {
"Package": "jaspGraphs",
"Version": "0.20.0",
"Source": "GitHub",
"Requirements": [
- "testthat",
"cli",
"ggplot2",
"gridExtra",
@@ -454,13 +454,15 @@
"plotly",
"R6",
"rlang",
- "scales"
+ "scales",
+ "testthat",
+ "vdiffr"
],
"RemoteType": "github",
"RemoteHost": "api.github.com",
"RemoteUsername": "jasp-stats",
"RemoteRepo": "jaspGraphs",
- "RemoteSha": "db3c899263a1d8d236ed0e7e3a7b6814b48c14ae"
+ "RemoteSha": "cdc4c9cf20f52c22c24162ea6fcbdd6b211e92db"
},
"jquerylib": {
"Package": "jquerylib",
@@ -480,7 +482,7 @@
},
"knitr": {
"Package": "knitr",
- "Version": "1.51",
+ "Version": "1.52",
"Source": "Repository",
"Requirements": [
"evaluate",
@@ -503,7 +505,7 @@
},
"later": {
"Package": "later",
- "Version": "1.4.5",
+ "Version": "1.4.8",
"Source": "Repository",
"Requirements": [
"R",
@@ -513,10 +515,11 @@
},
"lazyeval": {
"Package": "lazyeval",
- "Version": "0.2.2",
+ "Version": "0.2.3",
"Source": "Repository",
"Requirements": [
- "R"
+ "R",
+ "rlang"
]
},
"lifecycle": {
@@ -531,7 +534,7 @@
},
"magrittr": {
"Package": "magrittr",
- "Version": "2.0.4",
+ "Version": "2.0.5",
"Source": "Repository",
"Requirements": [
"R"
@@ -556,7 +559,7 @@
},
"officer": {
"Package": "officer",
- "Version": "0.7.3",
+ "Version": "0.7.6",
"Source": "Repository",
"Requirements": [
"cli",
@@ -576,7 +579,7 @@
},
"openssl": {
"Package": "openssl",
- "Version": "2.3.4",
+ "Version": "2.4.2",
"Source": "Repository",
"Requirements": [
"askpass"
@@ -627,7 +630,7 @@
},
"plotly": {
"Package": "plotly",
- "Version": "4.11.0",
+ "Version": "4.12.1",
"Source": "Repository",
"Requirements": [
"base64enc",
@@ -640,7 +643,6 @@
"htmlwidgets",
"httr",
"jsonlite",
- "lazyeval",
"magrittr",
"promises",
"purrr",
@@ -666,7 +668,7 @@
},
"processx": {
"Package": "processx",
- "Version": "3.8.6",
+ "Version": "3.9.0",
"Source": "Repository",
"Requirements": [
"ps",
@@ -692,7 +694,7 @@
},
"ps": {
"Package": "ps",
- "Version": "1.9.1",
+ "Version": "1.9.3",
"Source": "Repository",
"Requirements": [
"R",
@@ -701,7 +703,7 @@
},
"purrr": {
"Package": "purrr",
- "Version": "1.2.1",
+ "Version": "1.2.2",
"Source": "Repository",
"Requirements": [
"cli",
@@ -714,7 +716,7 @@
},
"ragg": {
"Package": "ragg",
- "Version": "1.5.0",
+ "Version": "1.5.2",
"Source": "Repository",
"Requirements": [
"systemfonts",
@@ -731,7 +733,7 @@
},
"rlang": {
"Package": "rlang",
- "Version": "1.1.7",
+ "Version": "1.3.0",
"Source": "Repository",
"Requirements": [
"R",
@@ -740,7 +742,7 @@
},
"rmarkdown": {
"Package": "rmarkdown",
- "Version": "2.30",
+ "Version": "2.32",
"Source": "Repository",
"Requirements": [
"bslib",
@@ -761,7 +763,7 @@
},
"rvg": {
"Package": "rvg",
- "Version": "0.4.0",
+ "Version": "0.4.2",
"Source": "Repository",
"Requirements": [
"gdtools",
@@ -805,7 +807,7 @@
},
"stringi": {
"Package": "stringi",
- "Version": "1.8.7",
+ "Version": "1.8.9",
"Source": "Repository",
"Requirements": [
"R",
@@ -852,7 +854,7 @@
},
"systemfonts": {
"Package": "systemfonts",
- "Version": "1.3.1",
+ "Version": "1.3.2",
"Source": "Repository",
"Requirements": [
"base64enc",
@@ -867,7 +869,7 @@
},
"textshaping": {
"Package": "textshaping",
- "Version": "1.0.4",
+ "Version": "1.0.5",
"Source": "Repository",
"Requirements": [
"cpp11",
@@ -933,7 +935,7 @@
},
"tinytex": {
"Package": "tinytex",
- "Version": "0.58",
+ "Version": "0.61",
"Source": "Repository",
"Requirements": [
"xfun"
@@ -949,7 +951,7 @@
},
"uuid": {
"Package": "uuid",
- "Version": "1.2-1",
+ "Version": "1.2-2",
"Source": "Repository",
"Requirements": [
"R"
@@ -957,7 +959,7 @@
},
"vctrs": {
"Package": "vctrs",
- "Version": "0.7.0",
+ "Version": "0.7.3",
"Source": "Repository",
"Requirements": [
"cli",
@@ -969,7 +971,7 @@
},
"viridisLite": {
"Package": "viridisLite",
- "Version": "0.4.2",
+ "Version": "0.4.3",
"Source": "Repository",
"Requirements": [
"R"
@@ -977,7 +979,7 @@
},
"withr": {
"Package": "withr",
- "Version": "3.0.2",
+ "Version": "3.0.3",
"Source": "Repository",
"Requirements": [
"graphics",
@@ -987,7 +989,7 @@
},
"xfun": {
"Package": "xfun",
- "Version": "0.56",
+ "Version": "0.61",
"Source": "Repository",
"Requirements": [
"grDevices",
@@ -998,7 +1000,7 @@
},
"xml2": {
"Package": "xml2",
- "Version": "1.5.2",
+ "Version": "1.6.0",
"Source": "Repository",
"Requirements": [
"cli",
@@ -1015,9 +1017,11 @@
},
"zip": {
"Package": "zip",
- "Version": "2.3.3",
+ "Version": "3.0.2",
"Source": "Repository",
- "Requirements": []
+ "Requirements": [
+ "cli"
+ ]
}
}
}
From c689e390159f4e0d9f780f6aaed3ed871216dfb8 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Tue, 6 Oct 2026 20:36:27 +0200
Subject: [PATCH 03/44] fix testMultiDataSet.qml missing ./common import
(ExplanationText is not a type)
ExplanationText is the module-local component in inst/qml/common/, so the form needs
import "./common" like the other test forms do. Caught by loading the form through
the native SyntaxInterface with jaspSyntax (github.com/jasp-stats/jaspSyntax) -
which is why buildBundle.R now runs readModuleDescription() + readDefaultAnalysisOptions()
as a build gate: a QML that does not create its Form throws there, verified with a
deliberately broken copy, so this class of error can no longer ride along into a bundle.
---
Tools/buildBundle.R | 18 ++++++++++++++++++
inst/qml/testMultiDataSet.qml | 1 +
2 files changed, 19 insertions(+)
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index 7b4d398..e4bdcdb 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -142,6 +142,24 @@ if (!("--check-only" %in% args)) tryCatch(jaspModuleTools::compile(
stop(e)
}, finally = restoreLock())
+# Load the module Description and the multi-dataset form through the native SyntaxInterface
+# (jaspSyntax, in the tool library): catches QML errors like missing imports or unknown types
+# at build time, without firing up JASP. Skipped when jaspSyntax isn't installed.
+Sys.setenv(QT_QPA_PLATFORM = "offscreen")
+if (requireNamespace("jaspSyntax", quietly = TRUE)) {
+ message("checking module Description + QML forms via jaspSyntax ...")
+ suppressPackageStartupMessages(library(jaspSyntax))
+ desc <- readModuleDescription(moduledir)
+ stopifnot(!is.null(desc))
+ for (analysisFunc in c("multiDataSetFunc")) {
+ opts <- readDefaultAnalysisOptions(moduledir, analysisFunc)
+ stopifnot(is.list(opts), !is.null(attr(opts, "qmlFile")))
+ message(" ", analysisFunc, " -> ", basename(attr(opts, "qmlFile")), " loads OK")
+ }
+} else {
+ message("NOTE: jaspSyntax not installed (see github.com/jasp-stats/jaspSyntax) - QML not checked.")
+}
+
# ---------------------------------------------------------------------------------------------
# Verify: the bundle manifest must list jaspBase, and the packed jaspBase must be OUR checkout
# (guard against silently packing a cached GitHub build instead).
diff --git a/inst/qml/testMultiDataSet.qml b/inst/qml/testMultiDataSet.qml
index 87167c6..cb29b2b 100644
--- a/inst/qml/testMultiDataSet.qml
+++ b/inst/qml/testMultiDataSet.qml
@@ -1,5 +1,6 @@
import QtQuick
import JASP.Controls
+import "./common"
Form
{
From a1de1e696a0b368fcab8476e28302ea43896598c Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Wed, 7 Oct 2026 00:04:35 +0200
Subject: [PATCH 04/44] multiDataSetFunc wrapped (hasWrapper): Internal entry
point + generated datasets wrapper
- Analysis body renamed to multiDataSetFuncInternal; the aware Description entry gets
hasWrapper: true, so JASP calls ...Internal and the generated wrapper
(R/multiDataSetFuncWrapper.R, via jaspSyntax) exposes multiDataSetFunc(datasets=, ...)
for R syntax use - datasets instead of data, stored via jaspBase::storeDataSets.
- The non-aware twin now points at multiDataSetFuncInternal directly (it cannot use the
wrapper name: JASP would call the wrapper as the analysis).
- NAMESPACE: import(jaspBase) - without it, wrapper calls from a plain R session could
not resolve createJaspHtml etc. (JASP attaches jaspBase, R does not).
- Tools/testMultiDataSet.R: full headless test over three paths - engine-style queued
slices (jaspTools datasets=), the wrapper in a clean subprocess, and a legacy
non-aware run as controls; 21 checks, all passing against the local jaspBase.
---
NAMESPACE | 1 +
R/multiDataSet.R | 17 ++---
R/multiDataSetFuncWrapper.R | 52 ++++++++++++++
Tools/buildBundle.R | 14 +++-
Tools/testMultiDataSet.R | 119 +++++++++++++++++++++++++++++++
Tools/testMultiDataSet_wrapper.R | 51 +++++++++++++
inst/Description.qml | 8 ++-
7 files changed, 250 insertions(+), 12 deletions(-)
create mode 100644 R/multiDataSetFuncWrapper.R
create mode 100644 Tools/testMultiDataSet.R
create mode 100644 Tools/testMultiDataSet_wrapper.R
diff --git a/NAMESPACE b/NAMESPACE
index 080553b..c1e4a3f 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,3 +1,4 @@
exportPattern('^[[:alpha:]]+')
+ import('jaspBase');
import('svglite');
import('stringi');
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index 1813867..9e7fc96 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -6,7 +6,7 @@
# which jaspBase's dataSetIdFromEncoded / dataSetNameFromEncoded / getDataSetColumn route.
# While such a run is active, readDataSet* stops: one 'current dataset' is meaningless here.
-multiDataSetFunc <- function(jaspResults, dataset, options, datasets = NULL) {
+multiDataSetFuncInternal <- function(jaspResults, dataset, options, datasets = NULL) {
aware <- !is.null(datasets)
jaspResults[["explanation"]] <- createJaspHtml(paste0(
@@ -74,7 +74,7 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
entry <- list(variable = column, dataSetId = "-", dataSetName = "-", column = column,
type = .typeSuffix(value), n = NA_integer_, values = "")
if (!is.null(dataset) && column %in% names(dataset))
- entry <- c(entry, .describeColumn(dataset[[column]]))
+ entry <- .fillDescription(entry, dataset[[column]])
table[[value]] <- entry
next
}
@@ -91,7 +91,7 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
columnData <- jaspBase::getDataSetColumn(value, datasets)
if (!is.null(columnData))
- entry <- c(entry, .describeColumn(columnData))
+ entry <- .fillDescription(entry, columnData)
table[[value]] <- entry
}
@@ -129,13 +129,14 @@ readDataSetGuardDemo <- function(jaspResults) {
if (length(match) == 2L) match[2] else NA_character_
}
-.describeColumn <- function(columnData) {
+.fillDescription <- function(entry, columnData) {
if (is.numeric(columnData)) {
- list(n = sum(!is.na(columnData)),
- values = sprintf("mean %.2f, sd %.2f", mean(columnData, na.rm = TRUE), sd(columnData, na.rm = TRUE)))
+ entry$n <- sum(!is.na(columnData))
+ entry$values <- sprintf("mean %.2f, sd %.2f", mean(columnData, na.rm = TRUE), sd(columnData, na.rm = TRUE))
} else {
levels <- unique(as.character(stats::na.omit(columnData)))
- list(n = length(stats::na.omit(columnData)),
- values = paste(utils::head(levels, 5), collapse = ", "))
+ entry$n <- length(stats::na.omit(columnData))
+ entry$values <- paste(utils::head(levels, 5), collapse = ", ")
}
+ entry
}
diff --git a/R/multiDataSetFuncWrapper.R b/R/multiDataSetFuncWrapper.R
new file mode 100644
index 0000000..382455f
--- /dev/null
+++ b/R/multiDataSetFuncWrapper.R
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Multi-DataSet
+#'
+multiDataSetFunc <- function(
+ datasets = NULL,
+ version = "1",
+ dependent = list(types = list(), value = list()),
+ guardDemo = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ showMeta = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::multiDataSetFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["datasets"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(datasets)) {
+ jaspBase::storeDataSets(datasets)
+ }
+
+ data <- if (!is.null(datasets) && length(datasets)) datasets[[1]] else NULL
+
+ optionsWithFormula <- c("dependent")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "multiDataSetFunc", "testMultiDataSet.qml", options, version, TRUE, datasets = datasets))
+}
\ No newline at end of file
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index e4bdcdb..9e07d2d 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -125,6 +125,18 @@ if (localJaspBase && !("--check-only" %in% args)) {
dir.create(resultdir, showWarnings = FALSE)
+# renv::restore skips same-version records, so a changed local jaspBase checkout would silently
+# NOT be rebuilt into the pkglib (the version stays 0.20.4). When bundling against the local
+# checkout: drop the installed jaspBase first so it is always rebuilt from source.
+if (localJaspBase && !("--check-only" %in% args)) {
+ pkglib <- file.path(workdir, "build_dir", basename(moduledir))
+ installedBase <- file.path(pkglib, "jaspBase")
+ if (dir.exists(installedBase)) {
+ message("removing stale jaspBase from ", pkglib, " (will rebuild from the local checkout)")
+ unlink(installedBase, recursive = TRUE)
+ }
+}
+
message("compiling + bundling (log is chatty, first run compiles all of jaspBase's deps) ...")
if (!("--check-only" %in% args)) tryCatch(jaspModuleTools::compile(
moduledir = moduledir,
@@ -184,7 +196,7 @@ archive::archive_extract(file.path(checkdir, jaspBaseHash), dir = pkgdir)
suppressPackageStartupMessages(library(jaspBase, lib.loc = file.path(checkdir, "lib")))
if (localJaspBase) {
- markers <- c("dataSetColumnFromEncoded", "dataSetIdFromEncoded", "getDataSetColumn") %in% getNamespaceExports("jaspBase")
+ markers <- c("dataSetColumnFromEncoded", "dataSetIdFromEncoded", "getDataSetColumn", "storeDataSets") %in% getNamespaceExports("jaspBase")
runBody <- any(grepl("multiDataSet|dataSetEncodedNames", deparse(body(jaspBase::runJaspResults))))
if (!all(markers) || !runBody)
stop("bundled jaspBase is MISSING the local multiDataSetAware code (exports: ",
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
new file mode 100644
index 0000000..fb9b07c
--- /dev/null
+++ b/Tools/testMultiDataSet.R
@@ -0,0 +1,119 @@
+#!/usr/bin/env Rscript
+# Full headless test of the multi-dataset aware analysis (Test Multi-DataSet).
+#
+# Path 1 (engine-style, jaspTools::runAnalysis + datasets=): options carry encoded column
+# names with embedded dataset ids; jaspTools queues the slices exactly like the engine does.
+# Path 2 (wrapper, jaspTestModule::multiDataSetFunc(datasets=...)): plain column names plus a
+# named list of datasets, runWrappedAnalysis -> runJaspResults with a direct R-side handout.
+#
+# Run with: Rscript Tools/testMultiDataSet.R (after Tools/buildBundle.R at least once,
+# which installs the patched jaspBase + this module into the build library)
+#
+# Override locations with JASP_TEST_PKGLIB / JASP_MODULE_TOOLLIB.
+
+moduledir <- normalizePath(file.path(dirname(sub("^--file=", "", grep("^--file=", commandArgs(FALSE), value = TRUE)[[1]])), ".."))
+pkglib <- Sys.getenv("JASP_TEST_PKGLIB", file.path(moduledir, "ModuleBundleBuildDir", "build_dir", "jaspTestModule"))
+toollib <- Sys.getenv("JASP_MODULE_TOOLLIB", normalizePath(file.path(moduledir, "..", ".toolLib")))
+
+stopifnot(dir.exists(pkglib), dir.exists(toollib))
+setwd(moduledir)
+.libPaths(c(pkglib, toollib, .libPaths()))
+
+Sys.setenv(QT_QPA_PLATFORM = "offscreen")
+
+failures <- 0L
+check <- function(ok, label) {
+ cat(if (isTRUE(ok)) "PASS :" else "FAIL :", label, "\n")
+ if (!isTRUE(ok)) failures <<- failures + 1L
+}
+
+# jaspTable json is transposed: data[[j]] holds one table column (schema.fields order), its cells
+# keyed by per-row ids ("colN", NOT in insertion order). columnValues returns cells + their row
+# keys so assertions can be order-independent.
+columnValues <- function(tb, fieldName) {
+ j <- which(vapply(tb$schema$fields, function(f) identical(f$name, fieldName), logical(1)))[1]
+ d <- tb$data[[j]]
+ rowKeys <- names(d)[vapply(d, length, integer(1)) > 0L]
+ stats::setNames(vapply(d[rowKeys], function(v) as.character(v), character(1), USE.NAMES = FALSE), rowKeys)
+}
+
+datasets <- list(
+ "11" = read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")),
+ "12" = read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")))
+attr(datasets, "dataSetNames") <- c("11" = "DataSetA", "12" = "DataSetB")
+
+# ------------------------------------------------------------------ Path 1: jaspTools queue ----
+cat("== Path 1: jaspTools::runAnalysis with queued slices (engine semantics) ==\n")
+suppressMessages(library(jaspTools))
+suppressMessages(jaspTools::setupJaspTools(
+ pathJaspDesktop = normalizePath(file.path(moduledir, "..", "jasp-desktop")),
+ installJaspModules = FALSE, installJaspCorePkgs = FALSE, quiet = TRUE, force = TRUE))
+jaspTools::setPkgOption("module.dirs", moduledir)
+jaspTools::setPkgOption("reinstall.modules", FALSE)
+
+opts1 <- list(dependent = c("JASPColumn_11_0.scale", "JASPColumn_11_2.nominal",
+ "JASPColumn_12_0.scale", "JASPColumn_12_1.scale"),
+ showMeta = FALSE, guardDemo = TRUE, plotWidth = 400, plotHeight = 300)
+res1 <- jaspTools::runAnalysis("multiDataSetFunc", options = opts1, datasets = datasets, view = FALSE, quiet = TRUE)
+r1 <- res1$results
+
+check(identical(res1$status, "complete"), "run 1 completed")
+check(length(r1$dataSetOverview$schema$fields) == 5L, "dataset overview has 5 columns (id/title/rows/cols/columnNames)")
+check(length(r1$dataSetOverview$data) == 5L, "dataset overview data has exactly the 5 schema columns (no duplicate n/values)")
+
+ovId <- columnValues(r1$dataSetOverview, "id")
+ovTitle <- columnValues(r1$dataSetOverview, "title")
+check(identical(unname(ovId), c("11", "12")), "overview ids 11,12")
+check(identical(unname(ovTitle), c("DataSetA", "DataSetB")), "overview titles from dataSetNames attr")
+
+sv <- r1$selectedVariables
+svVar <- columnValues(sv, "variable")
+svId <- columnValues(sv, "dataSetId")
+svName <- columnValues(sv, "dataSetName")
+svCol <- columnValues(sv, "column")
+svType <- columnValues(sv, "type")
+svN <- columnValues(sv, "n")
+# keyed by the row id so assertions do not depend on json row order
+byRow <- function(v) v[svVar]
+expected <- list(
+ "JASPColumn_11_0.scale" = c(id = "11", name = "DataSetA", column = "Score", type = "scale"),
+ "JASPColumn_11_2.nominal" = c(id = "11", name = "DataSetA", column = "Group", type = "nominal"),
+ "JASPColumn_12_0.scale" = c(id = "12", name = "DataSetB", column = "Score", type = "scale"),
+ "JASPColumn_12_1.scale" = c(id = "12", name = "DataSetB", column = "Age", type = "scale"))
+check(all(names(expected) %in% svVar), "all four dependents present in the routing table")
+for (v in names(expected)) if (v %in% svVar) {
+ i <- which(svVar == v)[1]
+ check(svId[i] == expected[[v]]["id"] && svName[i] == expected[[v]]["name"] &&
+ svCol[i] == expected[[v]]["column"] && svType[i] == expected[[v]]["type"],
+ paste0("routing ", v, " -> ", expected[[v]]["name"], "/", expected[[v]]["column"]))
+}
+check(all(svN == "10"), "all four columns read 10 rows")
+
+raw1 <- jsonlite::toJSON(res1, auto_unbox = TRUE)
+check(grepl("not available in multi-dataset aware analyses", raw1, fixed = TRUE),
+ "guard demo: readDataSet() hard-stopped during the aware run")
+
+# ------------------------------------------------------------------ Path 2: wrapper call -------
+# The wrapper path is run in a clean Rscript subprocess (no jaspTools runtime in the way),
+# which is exactly the RStudio/syntax-mode scenario the wrapper is made for.
+cat("\n== Path 2: wrapper (datasets= named list, plain column names; clean subprocess) ==\n")
+path2Script <- file.path(moduledir, "Tools", "testMultiDataSet_wrapper.R")
+status2 <- system2("Rscript", c(shQuote(path2Script)), stdout = TRUE, stderr = FALSE)
+writeLines(status2)
+check(any(grepl("MULTIDATASET-WRAPPER-OK", status2, fixed = TRUE)), "wrapper subprocess succeeded")
+
+# ------------------------------------------------------------------ Path 3: legacy still OK ----
+cat("\n== Path 3: legacy non-aware run (no datasets) ==\n")
+res3 <- jaspTools::runAnalysis("multiDataSetFunc", dataset = datasets[["11"]],
+ options = list(dependent = c("Score"), showMeta = FALSE,
+ guardDemo = TRUE, plotWidth = 400, plotHeight = 300),
+ view = FALSE, quiet = TRUE)
+raw3 <- jsonlite::toJSON(res3, auto_unbox = TRUE)
+check(identical(res3$status, "complete"), "legacy run completed")
+check(grepl("\\(current\\)", raw3), "legacy run used the single-dataset path (no multi mode)")
+check(!grepl("not available in multi-dataset", raw3, fixed = TRUE),
+ "guard demo: readDataSet() works normally outside aware runs")
+
+cat("\n")
+if (failures > 0L) stop(failures, " multi-dataset test check(s) failed")
+cat("All multi-dataset analysis tests passed\n")
diff --git a/Tools/testMultiDataSet_wrapper.R b/Tools/testMultiDataSet_wrapper.R
new file mode 100644
index 0000000..e6329a8
--- /dev/null
+++ b/Tools/testMultiDataSet_wrapper.R
@@ -0,0 +1,51 @@
+#!/usr/bin/env Rscript
+# Wrapper-path check of the multi-dataset analysis: no jaspTools, no JASP - just
+# jaspTestModule::multiDataSetFunc(datasets = , ...) like an R user would call it.
+# Run by Tools/testMultiDataSet.R, but standalone-runnable too.
+
+moduledir <- normalizePath(file.path(dirname(sub("^--file=", "", grep("^--file=", commandArgs(FALSE), value = TRUE)[[1]])), ".."))
+pkglib <- Sys.getenv("JASP_TEST_PKGLIB", file.path(moduledir, "ModuleBundleBuildDir", "build_dir", "jaspTestModule"))
+toollib <- Sys.getenv("JASP_MODULE_TOOLLIB", normalizePath(file.path(moduledir, "..", ".toolLib")))
+stopifnot(dir.exists(pkglib), dir.exists(toollib))
+.libPaths(c(pkglib, toollib, .libPaths()))
+Sys.setenv(QT_QPA_PLATFORM = "offscreen")
+
+suppressMessages(library(jaspTestModule))
+
+datasets <- list(
+ "11" = read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")),
+ "12" = read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")))
+attr(datasets, "dataSetNames") <- c("11" = "DataSetA", "12" = "DataSetB")
+
+res <- jaspTestModule::multiDataSetFunc(datasets = datasets, dependent = c("Score", "Condition"))
+raw <- as.character(res$.__enclos_env__$private$getResults())
+j <- jsonlite::fromJSON(raw, simplifyVector = FALSE)$results
+
+# jaspTable json is transposed: data[[j]] = column j (schema order), cells keyed by row id
+columnValues <- function(tb, fieldName) {
+ idx <- which(vapply(tb$schema$fields, function(f) identical(f$name, fieldName), logical(1)))[1]
+ d <- tb$data[[idx]]
+ rowKeys <- names(d)[vapply(d, length, integer(1)) > 0L]
+ vapply(d[rowKeys], function(v) as.character(v), character(1), USE.NAMES = FALSE)
+}
+
+ok <- TRUE
+check <- function(cond, label) {
+ cat(if (isTRUE(cond)) "PASS :" else "FAIL :", "wrapper -", label, "\n")
+ if (!isTRUE(cond)) ok <<- FALSE
+}
+
+check(grepl("Aware run", raw, fixed = TRUE), "analysis ran in aware mode (datasets= arrived)")
+check(identical(columnValues(j$dataSetOverview, "id"), c("11", "12")), "wrapper overview lists both dataset ids")
+check(identical(columnValues(j$dataSetOverview, "title"), c("DataSetA", "DataSetB")), "wrapper overview lists both titles")
+
+sv <- j$selectedVariables
+svCol <- columnValues(sv, "column")
+svN <- columnValues(sv, "n")
+svValues <- columnValues(sv, "values")
+check(any(svCol == "Score") && any(svCol == "Condition"), "Score and Condition resolved to original column names")
+check(all(svN == "10"), "both columns computed over 10 rows (scan-all found Condition in DataSetB)")
+check(any(grepl("mean", svValues, fixed = TRUE)), "numeric stats computed for Score")
+
+cat(if (ok) "MULTIDATASET-WRAPPER-OK\n" else "MULTIDATASET-WRAPPER-FAILED\n")
+quit(status = if (ok) 0L else 1L)
diff --git a/inst/Description.qml b/inst/Description.qml
index ca0f46d..f341dee 100644
--- a/inst/Description.qml
+++ b/inst/Description.qml
@@ -122,15 +122,17 @@ Description
requiresData: true
preloadData: true
multiDataSetAware: true
+ hasWrapper: true
}
- // Same form and function, but NOT aware: dataSetSelection must stay inert and data must
- // arrive the old way (through dataset/readDataSet), as a controls-and-regression check.
+ // Same form, but NOT aware and NOT wrapped: the engine calls multiDataSetFuncInternal
+ // directly (dataset/readDataSet as always) and the dataset selection must stay inert.
+ // (It cannot use func: "multiDataSetFunc" - that name is the R-syntax wrapper now.)
Analysis
{
title: "Test Multi-DataSet (non-aware counterpart)"
qml: "testMultiDataSet.qml"
- func: "multiDataSetFunc"
+ func: "multiDataSetFuncInternal"
requiresData: true
preloadData: true
multiDataSetAware: false
From b9a99984a783b56946c584a5b7ff9e1128f3d31f Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Wed, 7 Oct 2026 00:07:03 +0200
Subject: [PATCH 05/44] NEWS: wrapped multi-dataset test analysis, headless
test scripts, test data
---
NEWS.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/NEWS.md b/NEWS.md
index 7b6cd18..3dcf6bd 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -20,9 +20,15 @@
(`multiDataSetAware` Description entries, the VariablesForm dataset/filter selection,
the `datasets` handout and encoded-name routing of jaspBase, the readDataSet() guard,
the `.meta` dataSetId/filterId provenance and the non-aware counterpart as controls).
+ The aware analysis is wrapped (`hasWrapper: true`): body in `multiDataSetFuncInternal`,
+ generated `multiDataSetFunc(datasets = ...)` wrapper for R syntax use.
* `Tools/buildBundle.R`: builds an installable `bundles_out/jaspTestModule.JASPModule`
from this checkout with the local `jasp-desktop/Engine/jaspBase` (or any checkout via
`JASP_BASE_DIR`) packed into the bundle; no JASP cellar needed.
+* `Tools/testMultiDataSet.R` (+ `_wrapper.R`): full headless test of the analysis over
+ engine-style queued slices, the wrapper in a clean session and a legacy non-aware run.
+* `Tools/testdata/DataSetA.csv` / `DataSetB.csv`: two datasets with deliberately colliding
+ column names for the per-dataset routing test.
## Changed
* `renv.lock` re-resolved for R 4.6.1 (current CRAN, jaspBase/jaspGraphs from GitHub HEAD).
From 106030a697f5f69f279d4170c63afb5a6ca4de84 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Wed, 7 Oct 2026 06:54:56 +0200
Subject: [PATCH 06/44] wrappers for the whole module: all analysis funcs
renamed to Internal + 38 generated wrappers
- hasWrappers: true in Description.qml; every analysis body renamed ->
Internal (engine appends Internal per entry), with generated R/Wrapper.R
exposing the R-syntax entry points (jaspSyntax::generateAnalysisWrapper, one fresh
process per analysis - filteredDataEntry segfaults the bridge and would take the
batch down otherwise).
- Cross references updated: testContainer calls testFootnotesTableFuncInternal,
testEncodingPreloadDataFuncInternal <- testEncodingFuncInternal alias.
- The non-aware multi-dataset counterpart moved to func multiDataSetNonAware
(+ multiDataSetNonAwareInternal): it cannot share multiDataSetFunc (that is the
wrapper) and multiDataSetFuncInternal (the generator rightly refuses to wrap an
Internal name).
- Known gaps left as-is: testTransposedTable/testFootnotes/testContainer point at a
removed test.qml, testPlotStatus at a never-existing TestPlotStatus.qml and their R
funcs were already gone (dead Description entries); filteredDataEntry hits the
Filter(_data == nullptr) bridge assertion headless.
- Tools/testMultiDataSet.R stays green (22/22) with the module wrapped.
---
NEWS.md | 8 ++
R/AnalysisUpgradeAWrapper.R | 103 ++++++++++++++++++++++
R/AnalysisUpgradeBWrapper.R | 103 ++++++++++++++++++++++
R/AnalysisUpgradeIncompatibleAWrapper.R | 103 ++++++++++++++++++++++
R/AnalysisUpgradeIncompatibleBWrapper.R | 103 ++++++++++++++++++++++
R/JaspReportTestWrapper.R | 49 +++++++++++
R/analysisUpgrade.R | 4 +-
R/customContrastsWrapper.R | 49 +++++++++++
R/descriptivesLinkWrapper.R | 93 ++++++++++++++++++++
R/filteredDataEntry.R | 4 +-
R/infoTestFuncWrapper.R | 97 ++++++++++++++++++++
R/minMaxFuncWrapper.R | 52 +++++++++++
R/multiDataSet.R | 7 ++
R/multiDataSetNonAwareWrapper.R | 50 +++++++++++
R/radioButtonFuncWrapper.R | 57 ++++++++++++
R/syntaxhighlighting.R | 4 +-
R/syntaxhighlightingFuncWrapper.R | 49 +++++++++++
R/testAnalysisColumnFuncWrapper.R | 49 +++++++++++
R/testAnalysisColumns.R | 4 +-
R/testComponentsListLayout.R | 2 +-
R/testComponentsListLayoutWrapper.R | 61 +++++++++++++
R/testContainer.R | 8 +-
R/testControlsLayout.R | 2 +-
R/testControlsLayoutFuncWrapper.R | 96 ++++++++++++++++++++
R/testCrapDataTable.R | 4 +-
R/testCrapDataTableWrapper.R | 45 ++++++++++
R/testCustomContrasts.R | 4 +-
R/testDefaultValuesWithBindings.R | 2 +-
R/testDefaultValuesWithBindingsWrapper.R | 51 +++++++++++
R/testEncoding.R | 4 +-
R/testEncodingFuncWrapper.R | 56 ++++++++++++
R/testEncodingPreloadDataFuncWrapper.R | 56 ++++++++++++
R/testFactorsForm.R | 2 +-
R/testFactorsFormFuncWrapper.R | 52 +++++++++++
R/testFootnotesTable.R | 2 +-
R/testHtml.R | 2 +-
R/testHtmlFuncWrapper.R | 45 ++++++++++
R/testInfo.R | 2 +-
R/testInputField.R | 2 +-
R/testInputFieldFuncWrapper.R | 54 ++++++++++++
R/testJaspReport.R | 4 +-
R/testLabel.R | 2 +-
R/testLabelFormatFuncWrapper.R | 55 ++++++++++++
R/testLatexFuncWrapper.R | 45 ++++++++++
R/testMinMax.R | 2 +-
R/testMixedColumnsTable.R | 2 +-
R/testMixedColumnsTableFuncWrapper.R | 46 ++++++++++
R/testOptionContainsValue.R | 2 +-
R/testOptionContainsValueWrapper.R | 49 +++++++++++
R/testOptionNames.R | 2 +-
R/testOptionNamesWrapper.R | 55 ++++++++++++
R/testRSource.R | 2 +-
R/testRSourceFuncWrapper.R | 53 +++++++++++
R/testRadioButtons.R | 2 +-
R/testReqModule.R | 4 +-
R/testSaveLoadButton.R | 2 +-
R/testSaveLoadButtonWrapper.R | 47 ++++++++++
R/testSpecialSources.R | 2 +-
R/testSpecialSourcesFuncWrapper.R | 66 ++++++++++++++
R/testState.R | 2 +-
R/testStateFuncWrapper.R | 53 +++++++++++
R/testTabView.R | 2 +-
R/testTabViewWrapper.R | 54 ++++++++++++
R/testTableFormatting.R | 2 +-
R/testTableFormattingFuncWrapper.R | 45 ++++++++++
R/testTableView.R | 2 +-
R/testTableViewWrapper.R | 53 +++++++++++
R/testTextArea.R | 2 +-
R/testTextAreaWrapper.R | 51 +++++++++++
R/testTransposedTable.R | 2 +-
R/testVariablesForm.R | 4 +-
R/testVariablesFormWrapper.R | 62 +++++++++++++
R/tooltipFunc.R | 2 +-
R/tooltipFuncWrapper.R | 107 +++++++++++++++++++++++
inst/Description.qml | 10 +--
75 files changed, 2382 insertions(+), 53 deletions(-)
create mode 100644 R/AnalysisUpgradeAWrapper.R
create mode 100644 R/AnalysisUpgradeBWrapper.R
create mode 100644 R/AnalysisUpgradeIncompatibleAWrapper.R
create mode 100644 R/AnalysisUpgradeIncompatibleBWrapper.R
create mode 100644 R/JaspReportTestWrapper.R
create mode 100644 R/customContrastsWrapper.R
create mode 100644 R/descriptivesLinkWrapper.R
create mode 100644 R/infoTestFuncWrapper.R
create mode 100644 R/minMaxFuncWrapper.R
create mode 100644 R/multiDataSetNonAwareWrapper.R
create mode 100644 R/radioButtonFuncWrapper.R
create mode 100644 R/syntaxhighlightingFuncWrapper.R
create mode 100644 R/testAnalysisColumnFuncWrapper.R
create mode 100644 R/testComponentsListLayoutWrapper.R
create mode 100644 R/testControlsLayoutFuncWrapper.R
create mode 100644 R/testCrapDataTableWrapper.R
create mode 100644 R/testDefaultValuesWithBindingsWrapper.R
create mode 100644 R/testEncodingFuncWrapper.R
create mode 100644 R/testEncodingPreloadDataFuncWrapper.R
create mode 100644 R/testFactorsFormFuncWrapper.R
create mode 100644 R/testHtmlFuncWrapper.R
create mode 100644 R/testInputFieldFuncWrapper.R
create mode 100644 R/testLabelFormatFuncWrapper.R
create mode 100644 R/testLatexFuncWrapper.R
create mode 100644 R/testMixedColumnsTableFuncWrapper.R
create mode 100644 R/testOptionContainsValueWrapper.R
create mode 100644 R/testOptionNamesWrapper.R
create mode 100644 R/testRSourceFuncWrapper.R
create mode 100644 R/testSaveLoadButtonWrapper.R
create mode 100644 R/testSpecialSourcesFuncWrapper.R
create mode 100644 R/testStateFuncWrapper.R
create mode 100644 R/testTabViewWrapper.R
create mode 100644 R/testTableFormattingFuncWrapper.R
create mode 100644 R/testTableViewWrapper.R
create mode 100644 R/testTextAreaWrapper.R
create mode 100644 R/testVariablesFormWrapper.R
create mode 100644 R/tooltipFuncWrapper.R
diff --git a/NEWS.md b/NEWS.md
index 3dcf6bd..4e43db8 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -32,6 +32,14 @@
## Changed
* `renv.lock` re-resolved for R 4.6.1 (current CRAN, jaspBase/jaspGraphs from GitHub HEAD).
+* `hasWrappers: true` for the module: every analysis body now lives in `Internal`
+ and has a generated `R/Wrapper.R` (via jaspSyntax/SyntaxInterface) exposing the
+ plain `(data = ..., ...)` entry point for R syntax use - 38 of 43; the four
+ entries pointing at removed qml files (test.qml, TestPlotStatus.qml) can't generate
+ one, and filteredDataEntry crashes the syntax bridge headlessly (Filter without
+ DataSet assertion in CommonData/filter.cpp - a real bridge bug to fix).
+* Non-aware counterpart moved to its own func (`multiDataSetNonAware`), a wrapper may
+ not be generated for a `...Internal` name.
diff --git a/R/AnalysisUpgradeAWrapper.R b/R/AnalysisUpgradeAWrapper.R
new file mode 100644
index 0000000..7e3a88f
--- /dev/null
+++ b/R/AnalysisUpgradeAWrapper.R
@@ -0,0 +1,103 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Analysis A
+#'
+#' @param stemAndLeaf, Create a Stem and leaf table.
+#' Defaults to \code{FALSE}.
+#' @param stemAndLeafScale, The scale parameter controls how much the table is expanded. For example, scale = 2 will cause the table to be roughly twice as long as the default (scale = 1).
+AnalysisUpgradeA <- function(
+ data = NULL,
+ version = "1",
+ addSmooth = TRUE,
+ addSmoothCI = TRUE,
+ addSmoothCIValue = 0.95,
+ binWidthType = "sturges",
+ chartType = "_2barCharts",
+ chartValues = "_2percentages",
+ colorPalette = "colorblind",
+ descriptivesIntervalPlot = FALSE,
+ descriptivesPiechart = FALSE,
+ descriptivesQQPlot = FALSE,
+ distPlotDensity = FALSE,
+ distPlotRug = FALSE,
+ frequencyTables = FALSE,
+ frequencyTablesMaximumAmount = 10,
+ graphTypeAbove = "density",
+ graphTypeRight = "density",
+ iqr = FALSE,
+ kurtosis = FALSE,
+ mad = FALSE,
+ madrobust = FALSE,
+ maximum = TRUE,
+ mean = TRUE,
+ median = FALSE,
+ minimum = TRUE,
+ mode = FALSE,
+ numberOfBins = 30,
+ percentileValuesEqualGroups = FALSE,
+ percentileValuesEqualGroupsNo = 4,
+ percentileValuesPercentiles = FALSE,
+ percentileValuesQuartiles = FALSE,
+ plotCorrelationMatrix = FALSE,
+ plotHeight = 320,
+ plotVariables = FALSE,
+ plotWidth = 480,
+ range = FALSE,
+ regressionType = "smooth",
+ scatterPlot = FALSE,
+ shapiro = FALSE,
+ showLegend = TRUE,
+ skewness = FALSE,
+ splitPlotBoxplot = TRUE,
+ splitPlotColour = FALSE,
+ splitPlotJitter = FALSE,
+ splitPlotOutlierLabel = FALSE,
+ splitPlotViolin = FALSE,
+ splitPlots = FALSE,
+ splitby = list(types = list(), value = ""),
+ standardDeviation = TRUE,
+ standardErrorMean = FALSE,
+ statisticsValuesAreGroupMidpoints = FALSE,
+ stemAndLeaf = FALSE,
+ stemAndLeafScale = 1,
+ sum = FALSE,
+ variables = list(types = list(), value = list()),
+ variance = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::AnalysisUpgradeA)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("binWidthType", "colorPalette", "splitby", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "AnalysisUpgradeA", "AnalysisUpgrade.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/AnalysisUpgradeBWrapper.R b/R/AnalysisUpgradeBWrapper.R
new file mode 100644
index 0000000..e58af93
--- /dev/null
+++ b/R/AnalysisUpgradeBWrapper.R
@@ -0,0 +1,103 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Analysis B
+#'
+#' @param stemAndLeaf, Create a Stem and leaf table.
+#' Defaults to \code{FALSE}.
+#' @param stemAndLeafScale, The scale parameter controls how much the table is expanded. For example, scale = 2 will cause the table to be roughly twice as long as the default (scale = 1).
+AnalysisUpgradeB <- function(
+ data = NULL,
+ version = "1",
+ addSmooth = TRUE,
+ addSmoothCI = TRUE,
+ addSmoothCIValue = 0.95,
+ binWidthType = "sturges",
+ chartType = "_1noCharts",
+ chartValues = "_1frequencies",
+ colorPalette = "colorblind",
+ descriptivesIntervalPlot = FALSE,
+ descriptivesPiechart = FALSE,
+ descriptivesQQPlot = FALSE,
+ distPlotDensity = FALSE,
+ distPlotRug = FALSE,
+ frequencyTables = FALSE,
+ frequencyTablesMaximumAmount = 10,
+ graphTypeAbove = "density",
+ graphTypeRight = "density",
+ iqr = FALSE,
+ kurtosis = FALSE,
+ mad = FALSE,
+ madrobust = FALSE,
+ maximum = TRUE,
+ mean = TRUE,
+ median = FALSE,
+ minimum = TRUE,
+ mode = FALSE,
+ numberOfBins = 30,
+ percentileValuesEqualGroups = FALSE,
+ percentileValuesEqualGroupsNo = 4,
+ percentileValuesPercentiles = FALSE,
+ percentileValuesQuartiles = FALSE,
+ plotCorrelationMatrix = FALSE,
+ plotHeight = 320,
+ plotVariables = FALSE,
+ plotWidth = 480,
+ range = FALSE,
+ regressionType = "smooth",
+ scatterPlot = FALSE,
+ shapiro = FALSE,
+ showLegend = TRUE,
+ skewness = FALSE,
+ splitPlotBoxplot = TRUE,
+ splitPlotColour = FALSE,
+ splitPlotJitter = FALSE,
+ splitPlotOutlierLabel = FALSE,
+ splitPlotViolin = FALSE,
+ splitPlots = FALSE,
+ splitby = list(types = list(), value = ""),
+ standardDeviation = TRUE,
+ standardErrorMean = FALSE,
+ statisticsValuesAreGroupMidpoints = FALSE,
+ stemAndLeaf = FALSE,
+ stemAndLeafScale = 1,
+ sum = FALSE,
+ variables = list(types = list(), value = list()),
+ variance = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::AnalysisUpgradeB)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("binWidthType", "colorPalette", "splitby", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "AnalysisUpgradeB", "AnalysisUpgrade.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/AnalysisUpgradeIncompatibleAWrapper.R b/R/AnalysisUpgradeIncompatibleAWrapper.R
new file mode 100644
index 0000000..79441cf
--- /dev/null
+++ b/R/AnalysisUpgradeIncompatibleAWrapper.R
@@ -0,0 +1,103 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Analysis A with incompatible to B
+#'
+#' @param stemAndLeaf, Create a Stem and leaf table.
+#' Defaults to \code{FALSE}.
+#' @param stemAndLeafScale, The scale parameter controls how much the table is expanded. For example, scale = 2 will cause the table to be roughly twice as long as the default (scale = 1).
+AnalysisUpgradeIncompatibleA <- function(
+ data = NULL,
+ version = "1",
+ addSmooth = TRUE,
+ addSmoothCI = TRUE,
+ addSmoothCIValue = 0.95,
+ binWidthType = "sturges",
+ chartType = "_4histograms",
+ chartValues = "_2percentages",
+ colorPalette = "colorblind",
+ descriptivesIntervalPlot = FALSE,
+ descriptivesPiechart = FALSE,
+ descriptivesQQPlot = FALSE,
+ distPlotDensity = FALSE,
+ distPlotRug = FALSE,
+ frequencyTables = FALSE,
+ frequencyTablesMaximumAmount = 10,
+ graphTypeAbove = "density",
+ graphTypeRight = "density",
+ iqr = FALSE,
+ kurtosis = FALSE,
+ mad = FALSE,
+ madrobust = FALSE,
+ maximum = TRUE,
+ mean = TRUE,
+ median = FALSE,
+ minimum = TRUE,
+ mode = FALSE,
+ numberOfBins = 30,
+ percentileValuesEqualGroups = FALSE,
+ percentileValuesEqualGroupsNo = 4,
+ percentileValuesPercentiles = FALSE,
+ percentileValuesQuartiles = FALSE,
+ plotCorrelationMatrix = FALSE,
+ plotHeight = 320,
+ plotVariables = FALSE,
+ plotWidth = 480,
+ range = FALSE,
+ regressionType = "smooth",
+ scatterPlot = FALSE,
+ shapiro = FALSE,
+ showLegend = TRUE,
+ skewness = FALSE,
+ splitPlotBoxplot = TRUE,
+ splitPlotColour = FALSE,
+ splitPlotJitter = FALSE,
+ splitPlotOutlierLabel = FALSE,
+ splitPlotViolin = FALSE,
+ splitPlots = FALSE,
+ splitby = list(types = list(), value = ""),
+ standardDeviation = TRUE,
+ standardErrorMean = FALSE,
+ statisticsValuesAreGroupMidpoints = FALSE,
+ stemAndLeaf = FALSE,
+ stemAndLeafScale = 1,
+ sum = FALSE,
+ variables = list(types = list(), value = list()),
+ variance = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::AnalysisUpgradeIncompatibleA)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("binWidthType", "colorPalette", "splitby", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "AnalysisUpgradeIncompatibleA", "AnalysisUpgrade.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/AnalysisUpgradeIncompatibleBWrapper.R b/R/AnalysisUpgradeIncompatibleBWrapper.R
new file mode 100644
index 0000000..393802a
--- /dev/null
+++ b/R/AnalysisUpgradeIncompatibleBWrapper.R
@@ -0,0 +1,103 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Analysis B but then incompatible
+#'
+#' @param stemAndLeaf, Create a Stem and leaf table.
+#' Defaults to \code{FALSE}.
+#' @param stemAndLeafScale, The scale parameter controls how much the table is expanded. For example, scale = 2 will cause the table to be roughly twice as long as the default (scale = 1).
+AnalysisUpgradeIncompatibleB <- function(
+ data = NULL,
+ version = "1",
+ addSmooth = TRUE,
+ addSmoothCI = TRUE,
+ addSmoothCIValue = 0.95,
+ binWidthType = "sturges",
+ chartType = "_3pieCharts",
+ chartValues = "_1frequencies",
+ colorPalette = "colorblind",
+ descriptivesIntervalPlot = FALSE,
+ descriptivesPiechart = FALSE,
+ descriptivesQQPlot = FALSE,
+ distPlotDensity = FALSE,
+ distPlotRug = FALSE,
+ frequencyTables = FALSE,
+ frequencyTablesMaximumAmount = 10,
+ graphTypeAbove = "density",
+ graphTypeRight = "density",
+ iqr = FALSE,
+ kurtosis = FALSE,
+ mad = FALSE,
+ madrobust = FALSE,
+ maximum = TRUE,
+ mean = TRUE,
+ median = FALSE,
+ minimum = TRUE,
+ mode = FALSE,
+ numberOfBins = 30,
+ percentileValuesEqualGroups = FALSE,
+ percentileValuesEqualGroupsNo = 4,
+ percentileValuesPercentiles = FALSE,
+ percentileValuesQuartiles = FALSE,
+ plotCorrelationMatrix = FALSE,
+ plotHeight = 320,
+ plotVariables = FALSE,
+ plotWidth = 480,
+ range = FALSE,
+ regressionType = "smooth",
+ scatterPlot = FALSE,
+ shapiro = FALSE,
+ showLegend = TRUE,
+ skewness = FALSE,
+ splitPlotBoxplot = TRUE,
+ splitPlotColour = FALSE,
+ splitPlotJitter = FALSE,
+ splitPlotOutlierLabel = FALSE,
+ splitPlotViolin = FALSE,
+ splitPlots = FALSE,
+ splitby = list(types = list(), value = ""),
+ standardDeviation = TRUE,
+ standardErrorMean = FALSE,
+ statisticsValuesAreGroupMidpoints = FALSE,
+ stemAndLeaf = FALSE,
+ stemAndLeafScale = 1,
+ sum = FALSE,
+ variables = list(types = list(), value = list()),
+ variance = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::AnalysisUpgradeIncompatibleB)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("binWidthType", "colorPalette", "splitby", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "AnalysisUpgradeIncompatibleB", "AnalysisUpgrade.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/JaspReportTestWrapper.R b/R/JaspReportTestWrapper.R
new file mode 100644
index 0000000..98f5b27
--- /dev/null
+++ b/R/JaspReportTestWrapper.R
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Reporting
+#'
+JaspReportTest <- function(
+ data = NULL,
+ version = "1",
+ plotHeight = 320,
+ plotWidth = 480,
+ reportMe = "",
+ selectedVariable = list(types = list(), value = "")) {
+
+ defaultArgCalls <- formals(jaspTestModule::JaspReportTest)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("selectedVariable")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "JaspReportTest", "JaspReportTest.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/analysisUpgrade.R b/R/analysisUpgrade.R
index e568f2a..ddbaa40 100644
--- a/R/analysisUpgrade.R
+++ b/R/analysisUpgrade.R
@@ -4,5 +4,5 @@ Analysis <- function(jaspResults, dataset, options) {
jaspResults[["optionsOverview"]] <- createJaspHtml(text=paste0(paste0("", names(options), ": "), options, "", collapse="\n"), elementType="ul")
}
-AnalysisUpgradeA <- Analysis;
-AnalysisUpgradeB <- Analysis;
+AnalysisUpgradeAInternal <- Analysis;
+AnalysisUpgradeBInternal <- Analysis;
diff --git a/R/customContrastsWrapper.R b/R/customContrastsWrapper.R
new file mode 100644
index 0000000..c38cb99
--- /dev/null
+++ b/R/customContrastsWrapper.R
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Custom Contrasts Widget
+#'
+customContrasts <- function(
+ data = NULL,
+ version = "1",
+ customContrasts = list(),
+ plotHeight = 320,
+ plotWidth = 480,
+ selected = list(types = list(), value = "")) {
+
+ defaultArgCalls <- formals(jaspTestModule::customContrasts)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("customContrasts", "selected")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "customContrasts", "customContrasts.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/descriptivesLinkWrapper.R b/R/descriptivesLinkWrapper.R
new file mode 100644
index 0000000..081de3f
--- /dev/null
+++ b/R/descriptivesLinkWrapper.R
@@ -0,0 +1,93 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Descriptives!
+#'
+descriptivesLink <- function(
+ data = NULL,
+ version = "1",
+ addSmooth = TRUE,
+ addSmoothCI = TRUE,
+ addSmoothCIValue = 0.95,
+ chartType = "_4histograms",
+ chartValues = "_2percentages",
+ colorPalette = "colorblind",
+ descriptivesPiechart = FALSE,
+ descriptivesQQPlot = FALSE,
+ distPlotDensity = FALSE,
+ frequencyTables = FALSE,
+ graphTypeAbove = "density",
+ graphTypeRight = "density",
+ iqr = FALSE,
+ kurtosis = FALSE,
+ mad = FALSE,
+ madrobust = FALSE,
+ maximum = TRUE,
+ mean = TRUE,
+ median = FALSE,
+ minimum = TRUE,
+ mode = FALSE,
+ percentileValuesEqualGroups = FALSE,
+ percentileValuesEqualGroupsNo = 4,
+ percentileValuesPercentiles = FALSE,
+ percentileValuesQuartiles = FALSE,
+ plotCorrelationMatrix = FALSE,
+ plotHeight = 320,
+ plotVariables = FALSE,
+ plotWidth = 480,
+ range = FALSE,
+ regressionType = "smooth",
+ scatterPlot = FALSE,
+ shapiro = FALSE,
+ showLegend = TRUE,
+ skewness = FALSE,
+ splitPlotBoxplot = TRUE,
+ splitPlotColour = FALSE,
+ splitPlotJitter = FALSE,
+ splitPlotOutlierLabel = FALSE,
+ splitPlotViolin = FALSE,
+ splitPlots = FALSE,
+ splitby = list(types = list(), value = ""),
+ standardDeviation = TRUE,
+ standardErrorMean = FALSE,
+ statisticsValuesAreGroupMidpoints = FALSE,
+ sum = FALSE,
+ variables = list(types = list(), value = list()),
+ variance = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::descriptivesLink)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("colorPalette", "splitby", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "descriptivesLink", "CopyOfDescriptives.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/filteredDataEntry.R b/R/filteredDataEntry.R
index 90aac0c..a0c821f 100644
--- a/R/filteredDataEntry.R
+++ b/R/filteredDataEntry.R
@@ -1,7 +1,7 @@
-filteredDataEntry <- function(jaspResults, dataset, options)
+filteredDataEntryInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
-}
\ No newline at end of file
+}
diff --git a/R/infoTestFuncWrapper.R b/R/infoTestFuncWrapper.R
new file mode 100644
index 0000000..fbddb5b
--- /dev/null
+++ b/R/infoTestFuncWrapper.R
@@ -0,0 +1,97 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' info testing
+#'
+#' This is a bunch of info on a form!
+#'
+#' @param barPlot, Displays the sample means as bars and the confidence intervals or standard errors as error bars for each measure.
+#' Defaults to \code{FALSE}.
+#' @param barPlotYAxisFixedToZero, Fix horizontal axis to 0: Forces the graph to show the default x-axis at y = 0
+#' Defaults to \code{TRUE}.
+#' @param cells, assigned RM
+#' @param checkbox, Check this out
+#' Defaults to \code{FALSE}.
+#' @param doubleFieldWithAfterLabel, this is in doublefield that has a label and an afterLabel
+#' @param dropDown, dropdown with info on each value
+#' \itemize{
+#' \item \code{"high"} (default) : So High!
+#' \item \code{"medium"}: Middling
+#' \item \code{"low"}: Down low
+#' \item \code{"custom"}: Who knows?
+#' }
+#' @param dropdownVariableAndExtraValues, You can choose one of the variables or special values
+#' @param dropdownVariables, You can choose one of the variables
+#' @param integerFieldWithAfterLabel, this is in integerfield that has a label and an afterLabel
+#' @param paairs, assigned pairs
+#' @param radiobuttongroup, A grouping of buttons of radio
+#' \itemize{
+#' \item \code{"rButton2"}: and more info on the other button
+#' \item \code{"rButton1"}: and some info on button
+#' }
+#' @param repeatedMeasuresFactors, FactorLevelList
+#' @param simpleTableView, a tableview with some info
+#' @param slideOnOuttaHere, slip and slide suicide
+#' @param tabview, This is an info field on a tabview
+#' @param varA, assigned variables nominal allowed
+infoTestFunc <- function(
+ data = NULL,
+ version = "1",
+ barPlot = FALSE,
+ barPlotCiLevel = 0.95,
+ barPlotErrorType = "ci",
+ barPlotYAxisFixedToZero = TRUE,
+ cells = list(),
+ checkbox = FALSE,
+ doubleFieldWithAfterLabel = 0,
+ dropDown = "high",
+ dropdownVariableAndExtraValues = list(types = "unknown", value = "one"),
+ dropdownVariables = list(types = "unknown", value = ""),
+ dropdownWithVariablesSource = list(types = "unknown", value = ""),
+ integerFieldWithAfterLabel = 1000,
+ paairs = list(),
+ plotHeight = 320,
+ plotWidth = 480,
+ radiobuttongroup = "rButton2",
+ repeatedMeasuresFactors = list(list(levels = list("Level 1", "Level 2"), name = "RM Factor 1")),
+ simpleTableView = list(),
+ slideOnOuttaHere = 0.5,
+ tabview = list(list(marginalMean = FALSE, name = "NEW ITEM", summary = FALSE, syntax = "")),
+ varA = list(types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::infoTestFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("cells", "dropDown", "dropdownVariableAndExtraValues", "dropdownVariables", "dropdownWithVariablesSource", "paairs", "repeatedMeasuresFactors", "simpleTableView", "tabview", "varA")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "infoTestFunc", "TestInfo.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/minMaxFuncWrapper.R b/R/minMaxFuncWrapper.R
new file mode 100644
index 0000000..e218460
--- /dev/null
+++ b/R/minMaxFuncWrapper.R
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Min Max
+#'
+minMaxFunc <- function(
+ data = NULL,
+ version = "1",
+ doubleLower = 0.1,
+ doubleUpper = 0.5,
+ integerLower = 1,
+ integerUpper = 5,
+ leftFormula = -1,
+ lowerDefault = 1,
+ lowerIntegerDefault = 0.1,
+ plotHeight = 320,
+ plotWidth = 480,
+ rightFormula = 1) {
+
+ defaultArgCalls <- formals(jaspTestModule::minMaxFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "minMaxFunc", "MinMaxTest.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index 9e7fc96..f1f7a40 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -117,6 +117,13 @@ readDataSetGuardDemo <- function(jaspResults) {
jaspResults[["guardDemo"]] <- createJaspHtml(message)
}
+# Non-aware counterpart (Description entry func: "multiDataSetNonAware"; the engine appends
+# Internal because hasWrappers is on for the whole module). Same form and body, but reached
+# through the old single-dataset path: no datasets argument, so readDataSet/dataset rule.
+multiDataSetNonAwareInternal <- function(jaspResults, dataset, options) {
+ multiDataSetFuncInternal(jaspResults, dataset, options)
+}
+
# ------------------------------------------------------------------ internals
.dependentValues <- function(options) {
diff --git a/R/multiDataSetNonAwareWrapper.R b/R/multiDataSetNonAwareWrapper.R
new file mode 100644
index 0000000..b2a6734
--- /dev/null
+++ b/R/multiDataSetNonAwareWrapper.R
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Multi-DataSet (non-aware counterpart)
+#'
+multiDataSetNonAware <- function(
+ data = NULL,
+ version = "1",
+ dependent = list(types = list(), value = list()),
+ guardDemo = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ showMeta = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::multiDataSetNonAware)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("dependent")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "multiDataSetNonAware", "testMultiDataSet.qml", options, version, TRUE))
+}
\ No newline at end of file
diff --git a/R/radioButtonFuncWrapper.R b/R/radioButtonFuncWrapper.R
new file mode 100644
index 0000000..f379a6c
--- /dev/null
+++ b/R/radioButtonFuncWrapper.R
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Radio Button
+#'
+radioButtonFunc <- function(
+ data = NULL,
+ version = "1",
+ assigned = list(types = list(), value = list()),
+ buttons1 = list(list(value = "button1"), list(value = "button2")),
+ buttons2 = list(list(value = "button1"), list(value = "button2")),
+ dynamic = list(),
+ dynamicGroupWithDynamicButtons = list(list(value = "grouo1"), list(value = "group2")),
+ dynamicGroupWithStaticButtons = list(list(value = "grouo1"), list(value = "group2")),
+ firstGroup = "one",
+ plotHeight = 320,
+ plotWidth = 480,
+ secondGroup = "one",
+ staticGroupWithDynamicButtons = "",
+ staticGroupWithStaticAndDynamicButtons = "Static button") {
+
+ defaultArgCalls <- formals(jaspTestModule::radioButtonFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("assigned", "buttons1", "buttons2", "dynamic", "dynamicGroupWithDynamicButtons", "dynamicGroupWithStaticButtons")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "radioButtonFunc", "RadioButtonTest.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/syntaxhighlighting.R b/R/syntaxhighlighting.R
index 54e6ac4..7f0fbc0 100644
--- a/R/syntaxhighlighting.R
+++ b/R/syntaxhighlighting.R
@@ -1,5 +1,5 @@
-syntaxhighlightingFunc <- function(jaspResults, dataset, options)
+syntaxhighlightingFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
-}
\ No newline at end of file
+}
diff --git a/R/syntaxhighlightingFuncWrapper.R b/R/syntaxhighlightingFuncWrapper.R
new file mode 100644
index 0000000..28d2530
--- /dev/null
+++ b/R/syntaxhighlightingFuncWrapper.R
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Syntax Highlighting
+#'
+syntaxhighlightingFunc <- function(
+ data = NULL,
+ version = "1",
+ R = list(columns = list(), model = "", modelOriginal = ""),
+ plotHeight = 320,
+ plotWidth = 480,
+ syntax = list(columns = list(), model = "", modelOriginal = "")) {
+
+ defaultArgCalls <- formals(jaspTestModule::syntaxhighlightingFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("R", "syntax")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "syntaxhighlightingFunc", "SyntaxHighlighting.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testAnalysisColumnFuncWrapper.R b/R/testAnalysisColumnFuncWrapper.R
new file mode 100644
index 0000000..5bbe5ed
--- /dev/null
+++ b/R/testAnalysisColumnFuncWrapper.R
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test (comp) columns from analyses
+#'
+testAnalysisColumnFunc <- function(
+ data = NULL,
+ version = "1",
+ AddColumnField = "",
+ AddColumnsPattern = "",
+ AddThisManyColumns = 3,
+ ComputedColumnField = "",
+ createColumnInR = TRUE,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testAnalysisColumnFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testAnalysisColumnFunc", "testAnalysisColumnFunc.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testAnalysisColumns.R b/R/testAnalysisColumns.R
index bfba7cb..4bb0428 100644
--- a/R/testAnalysisColumns.R
+++ b/R/testAnalysisColumns.R
@@ -1,4 +1,4 @@
-testAnalysisColumnFunc <- function(jaspResults, dataset, options)
+testAnalysisColumnFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
@@ -76,4 +76,4 @@ createAndFillAJaspColumn <- function(container, name, dependencies)
col$setScale(generateDataForColumn())
container[[name]] <- col
-}
\ No newline at end of file
+}
diff --git a/R/testComponentsListLayout.R b/R/testComponentsListLayout.R
index fbf7198..a6c2072 100644
--- a/R/testComponentsListLayout.R
+++ b/R/testComponentsListLayout.R
@@ -1,5 +1,5 @@
-testComponentsListLayout <- function(jaspResults, dataset, options)
+testComponentsListLayoutInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
}
diff --git a/R/testComponentsListLayoutWrapper.R b/R/testComponentsListLayoutWrapper.R
new file mode 100644
index 0000000..a8588ec
--- /dev/null
+++ b/R/testComponentsListLayoutWrapper.R
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test ComponentsList & TableView layout
+#'
+testComponentsListLayout <- function(
+ data = NULL,
+ version = "1",
+ addBorderCheck = TRUE,
+ addItemManuallyCheck = TRUE,
+ buttonsInRowCheck = FALSE,
+ columns = "3",
+ componentsList = list(local({ .l <- list("#", "Second column", "Third column", "First hypothesis", "#"); names(.l) <- c("", "col2", "col3", "hypothesis", "value"); .l }), local({ .l <- list("#2", "Second hypothesis", "#2"); names(.l) <- c("", "hypothesis", "value"); .l }), list(col2 = "col 2", col3 = "col 3", col4 = "col 4", col5 = "col 5", col6 = "col 6", hypothesis = "Hypothesis 3", value = "#3"), list(col2 = "col 2", col3 = "col 3", col4 = "col 4", col5 = "col 5", col6 = "col 6", hypothesis = "Hypothesis 4", value = "#4")),
+ contrasts = list(optionKey = "variable", types = list(), value = list()),
+ customContrasts = list(),
+ fixedFactors = list(optionKey = "components", types = list(), value = list()),
+ headers = "Header with array",
+ heightCheck = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ showButtonsCheck = TRUE,
+ showTitleCheck = FALSE,
+ tableHeightCheck = FALSE,
+ tableView = list(list(levels = list(), name = "data 1", values = list()), list(levels = list(), name = "data 2", values = list()))) {
+
+ defaultArgCalls <- formals(jaspTestModule::testComponentsListLayout)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("columns", "componentsList", "contrasts", "customContrasts", "fixedFactors", "headers", "tableView")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testComponentsListLayout", "testComponentsListLayout.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testContainer.R b/R/testContainer.R
index ca8a196..9228811 100644
--- a/R/testContainer.R
+++ b/R/testContainer.R
@@ -1,15 +1,15 @@
-testContainerFunc <- function(jaspResults, dataset, options)
+testContainerFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
cnt <- addContainer(addContainer(addContainer(addContainer(jaspResults, name="c0"))))
- testFootnotesTableFunc(cnt, dataset, options)
+ testFootnotesTableFuncInternal(cnt, dataset, options)
cnt <- addContainer(addContainer(addContainer(addContainer(jaspResults, name="c1")), title="hallo"))
- testFootnotesTableFunc(cnt, dataset, options)
+ testFootnotesTableFuncInternal(cnt, dataset, options)
cnt <- addContainer(addContainer(addContainer(addContainer(jaspResults, title="hallo", name="c2")), title="er zit er eentje stiekem om me heen"), title="hallo", initCollapsed=TRUE)
- testFootnotesTableFunc(cnt, dataset, options)
+ testFootnotesTableFuncInternal(cnt, dataset, options)
}
addContainer <- function(inContainer, name="container", title="", initCollapsed=FALSE)
diff --git a/R/testControlsLayout.R b/R/testControlsLayout.R
index 41aca61..df8cc47 100644
--- a/R/testControlsLayout.R
+++ b/R/testControlsLayout.R
@@ -1,5 +1,5 @@
-testControlsLayoutFunc <- function(jaspResults, dataset, options)
+testControlsLayoutFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testControlsLayoutFuncWrapper.R b/R/testControlsLayoutFuncWrapper.R
new file mode 100644
index 0000000..17f27d8
--- /dev/null
+++ b/R/testControlsLayoutFuncWrapper.R
@@ -0,0 +1,96 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Controls layout
+#'
+#' @param meanCiLevel, width of the confidence interval.
+#' @param meanCiMethod, How should the confidence interval be computed? By default, we use a `T model`, which yields results identical to a one-sample t-test. Alternative options are a normal model ($\bar{x} \pm z_{95} \times SE$), or `Bootstrap`.
+#' @param sdCi, a confidence interval for the standard deviation based on bootstrap samples.
+#' Defaults to \code{FALSE}.
+testControlsLayoutFunc <- function(
+ data = NULL,
+ version = "1",
+ checkBoxSecondLevel = FALSE,
+ checkboxWithSeveralLevels = FALSE,
+ doubleInGroup = 0,
+ dropDownInGroup = list(types = "unknown", value = ""),
+ dropDownNominal = list(types = "unknown", value = ""),
+ dropDownOrdinal = list(types = "unknown", value = ""),
+ dropDownScale = list(types = "unknown", value = ""),
+ dropDownSecondLevel = "one",
+ dropDownStartValue = "really long values!!!!!",
+ dropDownValues = "one",
+ dropDownValuesAbove = "one",
+ dropDownValuesEmptyValue = "",
+ dropDownValuesFixed = "one",
+ dropDownValuesFixedAbove = "one",
+ dropDownValuesFixedEmptyValue = "",
+ dropDownValuesFixedStartValue = "really long values!!!!!",
+ dropDownVariables = list(types = "unknown", value = ""),
+ dropDownVariablesEmptyValue = "",
+ dropDownVariablesFixed = list(types = "unknown", value = ""),
+ dropDownVariablesFixedEmptyValue = list(types = "unknown", value = ""),
+ dropDownVariablesFixedLabelAbove = list(types = "unknown", value = ""),
+ dropDownVariablesFixedStartIndex = list(types = "unknown", value = ""),
+ dropDownVariablesLabel = list(types = "unknown", value = ""),
+ dropDownVariablesStartIndex = list(types = "unknown", value = ""),
+ intValue = 0,
+ integerFirstLevel = 0,
+ integerSecondLevel = 0,
+ maxLevels = 100,
+ maxNumeric = 100,
+ meanCi = FALSE,
+ meanCiLevel = 0.95,
+ meanCiMethod = "oneSampleTTest",
+ minLevels = -1,
+ minNumeric = -1,
+ percentFirstLevel = 0.5,
+ percentileValues = list(),
+ percentiles = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ quantilesForEqualGroups = FALSE,
+ quantilesForEqualGroupsNumber = 0,
+ quartiles = FALSE,
+ sdCi = FALSE,
+ sdCiLevel = 0.95,
+ sdCiMethod = "chiSquaredModel",
+ seMean = FALSE,
+ textInGroup = "") {
+
+ defaultArgCalls <- formals(jaspTestModule::testControlsLayoutFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("dropDownInGroup", "dropDownNominal", "dropDownOrdinal", "dropDownScale", "dropDownSecondLevel", "dropDownStartValue", "dropDownValues", "dropDownValuesAbove", "dropDownValuesEmptyValue", "dropDownValuesFixed", "dropDownValuesFixedAbove", "dropDownValuesFixedEmptyValue", "dropDownValuesFixedStartValue", "dropDownVariables", "dropDownVariablesEmptyValue", "dropDownVariablesFixed", "dropDownVariablesFixedEmptyValue", "dropDownVariablesFixedLabelAbove", "dropDownVariablesFixedStartIndex", "dropDownVariablesLabel", "dropDownVariablesStartIndex", "meanCiMethod", "sdCiMethod")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testControlsLayoutFunc", "testControlsLayout.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testCrapDataTable.R b/R/testCrapDataTable.R
index 79811b0..94aac5f 100644
--- a/R/testCrapDataTable.R
+++ b/R/testCrapDataTable.R
@@ -1,6 +1,6 @@
-testCrapDataTable <- function(jaspResults, dataset, options)
+testCrapDataTableInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
@@ -36,4 +36,4 @@ testCrapDataTable <- function(jaspResults, dataset, options)
jaspResults[["hereYaGo"]] <- tb
-}
\ No newline at end of file
+}
diff --git a/R/testCrapDataTableWrapper.R b/R/testCrapDataTableWrapper.R
new file mode 100644
index 0000000..b096bc9
--- /dev/null
+++ b/R/testCrapDataTableWrapper.R
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test jaspTable with crappy data
+#'
+testCrapDataTable <- function(
+ data = NULL,
+ version = "1",
+ checkbox_0 = FALSE,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testCrapDataTable)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testCrapDataTable", "testCrapDataTable.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testCustomContrasts.R b/R/testCustomContrasts.R
index 1354682..b18bfc1 100644
--- a/R/testCustomContrasts.R
+++ b/R/testCustomContrasts.R
@@ -1,4 +1,4 @@
-customContrasts <- function(jaspResults, dataset, options)
+customContrastsInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
@@ -37,4 +37,4 @@ createCustomConstrastsTable <- function(customContrasts)
return(table);
-}
\ No newline at end of file
+}
diff --git a/R/testDefaultValuesWithBindings.R b/R/testDefaultValuesWithBindings.R
index 2122414..052027d 100644
--- a/R/testDefaultValuesWithBindings.R
+++ b/R/testDefaultValuesWithBindings.R
@@ -1,4 +1,4 @@
-testDefaultValuesWithBindings <- function(jaspResults, dataset, options)
+testDefaultValuesWithBindingsInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testDefaultValuesWithBindingsWrapper.R b/R/testDefaultValuesWithBindingsWrapper.R
new file mode 100644
index 0000000..6955afc
--- /dev/null
+++ b/R/testDefaultValuesWithBindingsWrapper.R
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Default values with bindings
+#'
+testDefaultValuesWithBindings <- function(
+ data = NULL,
+ version = "1",
+ assignedVariables = list(types = list(), value = list()),
+ check = FALSE,
+ drop = "none",
+ plotHeight = 320,
+ plotWidth = 480,
+ radio = "one") {
+
+ defaultArgCalls <- formals(jaspTestModule::testDefaultValuesWithBindings)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("assignedVariables", "drop")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testDefaultValuesWithBindings", "testDefaultValuesWithBindings.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testEncoding.R b/R/testEncoding.R
index 2185660..5c15af2 100644
--- a/R/testEncoding.R
+++ b/R/testEncoding.R
@@ -1,4 +1,4 @@
-testEncodingFunc <- function(jaspResults, dataset, options)
+testEncodingFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
@@ -8,7 +8,7 @@ testEncodingFunc <- function(jaspResults, dataset, options)
showData(dataset, jaspResults, "variablesPairs", unlist(options$pairs), "Pairs Variables")
}
-testEncodingPreloadDataFunc <- testEncodingFunc
+testEncodingPreloadDataFuncInternal <- testEncodingFuncInternal
showData <- function(dataset, jaspResults, name, cols, title, filter = "")
{
diff --git a/R/testEncodingFuncWrapper.R b/R/testEncodingFuncWrapper.R
new file mode 100644
index 0000000..48091e5
--- /dev/null
+++ b/R/testEncodingFuncWrapper.R
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Variables encoding
+#'
+testEncodingFunc <- function(
+ data = NULL,
+ version = "1",
+ componentsListFromVariablesList = list(),
+ componentsListWithVariables = list(list(levelsOfSingleVariable = "", singleVariable = list(types = list(), value = ""), value = "#", variablesInComponentsList = list(types = list(), value = list()))),
+ dropdown = list(types = "unknown", value = ""),
+ genericFilter = "",
+ pairs = list(),
+ plotHeight = 320,
+ plotWidth = 480,
+ selected = list(types = list(), value = list()),
+ singleVariable = list(types = list(), value = ""),
+ variablesForComponentsList = list(optionKey = "components", types = list(), value = list()),
+ variablesWithInteractions = list(optionKey = "components", types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testEncodingFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("componentsListFromVariablesList", "componentsListWithVariables", "dropdown", "pairs", "selected", "singleVariable", "variablesForComponentsList", "variablesWithInteractions")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testEncodingFunc", "testEncoding.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testEncodingPreloadDataFuncWrapper.R b/R/testEncodingPreloadDataFuncWrapper.R
new file mode 100644
index 0000000..1c28c0c
--- /dev/null
+++ b/R/testEncodingPreloadDataFuncWrapper.R
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Variables encoding with preloadData
+#'
+testEncodingPreloadDataFunc <- function(
+ data = NULL,
+ version = "1",
+ componentsListFromVariablesList = list(),
+ componentsListWithVariables = list(list(levelsOfSingleVariable = "", singleVariable = list(types = list(), value = ""), value = "#", variablesInComponentsList = list(types = list(), value = list()))),
+ dropdown = list(types = "unknown", value = ""),
+ genericFilter = "",
+ pairs = list(),
+ plotHeight = 320,
+ plotWidth = 480,
+ selected = list(types = list(), value = list()),
+ singleVariable = list(types = list(), value = ""),
+ variablesForComponentsList = list(optionKey = "components", types = list(), value = list()),
+ variablesWithInteractions = list(optionKey = "components", types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testEncodingPreloadDataFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("componentsListFromVariablesList", "componentsListWithVariables", "dropdown", "pairs", "selected", "singleVariable", "variablesForComponentsList", "variablesWithInteractions")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testEncodingPreloadDataFunc", "testEncoding.qml", options, version, TRUE))
+}
\ No newline at end of file
diff --git a/R/testFactorsForm.R b/R/testFactorsForm.R
index 18e9b6c..d185201 100644
--- a/R/testFactorsForm.R
+++ b/R/testFactorsForm.R
@@ -1,5 +1,5 @@
-testFactorsFormFunc <- function(jaspResults, dataset, options)
+testFactorsFormFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testFactorsFormFuncWrapper.R b/R/testFactorsFormFuncWrapper.R
new file mode 100644
index 0000000..d211646
--- /dev/null
+++ b/R/testFactorsFormFuncWrapper.R
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Factors Form
+#'
+testFactorsFormFunc <- function(
+ data = NULL,
+ version = "1",
+ factors = list(list(indicators = list(), name = "Factor1", title = "Factor 1")),
+ factorsList = list(list(keyLabel = "Factor 1", value = "Factor1")),
+ nested = TRUE,
+ nestedFactors = list(list(components = list(), name = "model0", title = "Model 0"), list(components = list(), name = "model1", title = "Model 1")),
+ plotHeight = 320,
+ plotWidth = 480,
+ variables = list(types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testFactorsFormFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("factors", "factorsList", "nestedFactors", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testFactorsFormFunc", "testFactorsForm.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testFootnotesTable.R b/R/testFootnotesTable.R
index edc9c9f..8df1bac 100644
--- a/R/testFootnotesTable.R
+++ b/R/testFootnotesTable.R
@@ -1,4 +1,4 @@
-testFootnotesTableFunc <- function(jaspResults, dataset, options)
+testFootnotesTableFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testHtml.R b/R/testHtml.R
index 6c438a3..90227f7 100644
--- a/R/testHtml.R
+++ b/R/testHtml.R
@@ -1,4 +1,4 @@
-testHtmlFunc <- function(jaspResults, dataset, options)
+testHtmlFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testHtmlFuncWrapper.R b/R/testHtmlFuncWrapper.R
new file mode 100644
index 0000000..f31ce71
--- /dev/null
+++ b/R/testHtmlFuncWrapper.R
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test jaspHtml
+#'
+testHtmlFunc <- function(
+ data = NULL,
+ version = "1",
+ checkbox_error = FALSE,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testHtmlFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testHtmlFunc", "testHtml.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testInfo.R b/R/testInfo.R
index 3d36542..531b51a 100644
--- a/R/testInfo.R
+++ b/R/testInfo.R
@@ -8,4 +8,4 @@ testInfoFunc <- function(jaspResults, dataset, options)
jaspResults[['tafel']] <- createJaspTable(title="Glory", colTitles=c('hallo', 'wereld'), info="some info on a table")
jaspResults[['nested']] <- createJaspContainer("Chairs", info='this is a container you know')
jaspResults[['nested']][['egg']] <- createJaspHtml(text="This is nested within a container", info="some info on a nested jaspHtml")
-}
\ No newline at end of file
+}
diff --git a/R/testInputField.R b/R/testInputField.R
index a6ad27f..77ea0d2 100644
--- a/R/testInputField.R
+++ b/R/testInputField.R
@@ -1,5 +1,5 @@
-testInputFieldFunc <- function(jaspResults, dataset, options)
+testInputFieldFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testInputFieldFuncWrapper.R b/R/testInputFieldFuncWrapper.R
new file mode 100644
index 0000000..19ff8ca
--- /dev/null
+++ b/R/testInputFieldFuncWrapper.R
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Input Field
+#'
+testInputFieldFunc <- function(
+ data = NULL,
+ version = "1",
+ doubleInfinity = inf,
+ doubleMinInfinity = -inf,
+ doubleWith1Decimals = 0.1,
+ doubleWith3Decimals = 0.123,
+ doubleWith5Decimals = 0.12345,
+ formulaHalf = "3/2",
+ formulaInfinity = inf,
+ formulaMinInfinity = -inf,
+ formulaNan = nan,
+ integerInfinity = 2,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testInputFieldFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testInputFieldFunc", "testInputField.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testJaspReport.R b/R/testJaspReport.R
index 380db0d..350148f 100644
--- a/R/testJaspReport.R
+++ b/R/testJaspReport.R
@@ -1,5 +1,5 @@
#' @export
-JaspReportTest <- function(jaspResults, dataset, options)
+JaspReportTestInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
@@ -17,4 +17,4 @@ JaspReportTest <- function(jaspResults, dataset, options)
reportOnThis, dependencies=c("reportMe", "selectedVariable"))
}
-}
\ No newline at end of file
+}
diff --git a/R/testLabel.R b/R/testLabel.R
index fcb611a..fdd56f0 100644
--- a/R/testLabel.R
+++ b/R/testLabel.R
@@ -1,4 +1,4 @@
-testLabelFormatFunc <- function(jaspResults, dataset, options)
+testLabelFormatFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
}
diff --git a/R/testLabelFormatFuncWrapper.R b/R/testLabelFormatFuncWrapper.R
new file mode 100644
index 0000000..d1f8475
--- /dev/null
+++ b/R/testLabelFormatFuncWrapper.R
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test label format
+#'
+testLabelFormatFunc <- function(
+ data = NULL,
+ version = "1",
+ assigned = list(types = list(), value = list()),
+ checkbox = FALSE,
+ doubleFieldWithAfterLabel = 0,
+ dropDown = "high",
+ integerFieldWithAfterLabel = 0,
+ labelText = "Test H₀! Ttest",
+ plotHeight = 320,
+ plotWidth = 480,
+ radiobuttongroup = "rButton2",
+ textFormat = "2") {
+
+ defaultArgCalls <- formals(jaspTestModule::testLabelFormatFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("assigned", "dropDown", "textFormat")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testLabelFormatFunc", "testLabelFormat.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testLatexFuncWrapper.R b/R/testLatexFuncWrapper.R
new file mode 100644
index 0000000..7068979
--- /dev/null
+++ b/R/testLatexFuncWrapper.R
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test latex
+#'
+testLatexFunc <- function(
+ data = NULL,
+ version = "1",
+ checkbox_error = FALSE,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testLatexFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testLatexFunc", "testHtml.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testMinMax.R b/R/testMinMax.R
index c18a916..065aeb2 100644
--- a/R/testMinMax.R
+++ b/R/testMinMax.R
@@ -1,5 +1,5 @@
-minMaxFunc <- function(jaspResults, dataset, options)
+minMaxFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testMixedColumnsTable.R b/R/testMixedColumnsTable.R
index 2dc884c..a587b3c 100644
--- a/R/testMixedColumnsTable.R
+++ b/R/testMixedColumnsTable.R
@@ -1,4 +1,4 @@
-testMixedColumnsTableFunc <- function(jaspResults, dataset, options) {
+testMixedColumnsTableFuncInternal <- function(jaspResults, dataset, options) {
if (options[["checkbox_0"]])
set.seed(123)
diff --git a/R/testMixedColumnsTableFuncWrapper.R b/R/testMixedColumnsTableFuncWrapper.R
new file mode 100644
index 0000000..f72ed4b
--- /dev/null
+++ b/R/testMixedColumnsTableFuncWrapper.R
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Mixed Columns jaspTable
+#'
+testMixedColumnsTableFunc <- function(
+ data = NULL,
+ version = "1",
+ checkbox_0 = FALSE,
+ checkbox_1 = FALSE,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testMixedColumnsTableFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testMixedColumnsTableFunc", "testMixedColumns.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testOptionContainsValue.R b/R/testOptionContainsValue.R
index d4404c8..f26a5b5 100644
--- a/R/testOptionContainsValue.R
+++ b/R/testOptionContainsValue.R
@@ -1,4 +1,4 @@
-testOptionContainsValue <- function(jaspResults, dataset, options)
+testOptionContainsValueInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testOptionContainsValueWrapper.R b/R/testOptionContainsValueWrapper.R
new file mode 100644
index 0000000..bba909f
--- /dev/null
+++ b/R/testOptionContainsValueWrapper.R
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test optionContainsValue
+#'
+testOptionContainsValue <- function(
+ data = NULL,
+ version = "1",
+ irrelevantCheckBox = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ restrictedModels = list(list(modelName = "Model 1", something = FALSE))) {
+
+ defaultArgCalls <- formals(jaspTestModule::testOptionContainsValue)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("restrictedModels")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testOptionContainsValue", "testOptionContainsValue.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testOptionNames.R b/R/testOptionNames.R
index 299b5cc..b783c22 100644
--- a/R/testOptionNames.R
+++ b/R/testOptionNames.R
@@ -1,5 +1,5 @@
-testOptionNames <- function(jaspResults, dataset, options)
+testOptionNamesInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testOptionNamesWrapper.R b/R/testOptionNamesWrapper.R
new file mode 100644
index 0000000..8745969
--- /dev/null
+++ b/R/testOptionNamesWrapper.R
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Option Names
+#'
+testOptionNames <- function(
+ data = NULL,
+ version = "1",
+ allVariables = FALSE,
+ formula = FALSE,
+ myRadioButton = "jhsdf7634(*&(&))",
+ noformula = FALSE,
+ one = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ test = FALSE,
+ two = FALSE,
+ variables = list(types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testOptionNames)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testOptionNames", "testOptionNames.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testRSource.R b/R/testRSource.R
index 8aa08fa..5b7d657 100644
--- a/R/testRSource.R
+++ b/R/testRSource.R
@@ -1,4 +1,4 @@
-testRSourceFunc <- function(jaspResults, dataset, options)
+testRSourceFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testRSourceFuncWrapper.R b/R/testRSourceFuncWrapper.R
new file mode 100644
index 0000000..8cad80e
--- /dev/null
+++ b/R/testRSourceFuncWrapper.R
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test R Source
+#'
+testRSourceFunc <- function(
+ data = NULL,
+ version = "1",
+ ComponentsList = list(),
+ ComponentsList2 = list(),
+ assignMe = list(types = list(), value = list()),
+ assignMe2 = list(types = list(), value = list()),
+ drop = "one",
+ drop2 = "one",
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testRSourceFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("ComponentsList", "ComponentsList2", "assignMe", "assignMe2", "drop", "drop2")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testRSourceFunc", "testRSource.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testRadioButtons.R b/R/testRadioButtons.R
index 80918da..b6a8c33 100644
--- a/R/testRadioButtons.R
+++ b/R/testRadioButtons.R
@@ -1,4 +1,4 @@
-radioButtonFunc <- function(jaspResults, dataset, options)
+radioButtonFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testReqModule.R b/R/testReqModule.R
index f2eacee..4c7f0b9 100644
--- a/R/testReqModule.R
+++ b/R/testReqModule.R
@@ -1,6 +1,6 @@
-descriptivesLink <- function(jaspResults, dataset, options)
+descriptivesLinkInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
Descriptives::Descriptives(jaspResults, dataset, options)
-}
\ No newline at end of file
+}
diff --git a/R/testSaveLoadButton.R b/R/testSaveLoadButton.R
index 172f483..09f67e2 100644
--- a/R/testSaveLoadButton.R
+++ b/R/testSaveLoadButton.R
@@ -1,4 +1,4 @@
-testSaveLoadButton <- function(jaspResults, dataset, options)
+testSaveLoadButtonInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testSaveLoadButtonWrapper.R b/R/testSaveLoadButtonWrapper.R
new file mode 100644
index 0000000..1785c10
--- /dev/null
+++ b/R/testSaveLoadButtonWrapper.R
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Save Load Button
+#'
+testSaveLoadButton <- function(
+ data = NULL,
+ version = "1",
+ loadMultiple = "",
+ loadThis = "",
+ plotHeight = 320,
+ plotWidth = 480,
+ saveHere = "") {
+
+ defaultArgCalls <- formals(jaspTestModule::testSaveLoadButton)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testSaveLoadButton", "testSaveLoadButton.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testSpecialSources.R b/R/testSpecialSources.R
index 88df641..6f95112 100644
--- a/R/testSpecialSources.R
+++ b/R/testSpecialSources.R
@@ -1,4 +1,4 @@
-testSpecialSourcesFunc <- function(jaspResults, dataset, options)
+testSpecialSourcesFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testSpecialSourcesFuncWrapper.R b/R/testSpecialSourcesFuncWrapper.R
new file mode 100644
index 0000000..ae9f7d0
--- /dev/null
+++ b/R/testSpecialSourcesFuncWrapper.R
@@ -0,0 +1,66 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Sources with special attributes
+#'
+testSpecialSourcesFunc <- function(
+ data = NULL,
+ version = "1",
+ assigned = list(types = list(), value = list()),
+ combinationCross = list(),
+ combinations2way = list(),
+ combinations3way = list(),
+ compList = list(list(dropDownValuesa = list(types = "unknown", value = ""), value = "#")),
+ controlVariables = "",
+ labelsFor1Variable = "",
+ labelsForSeveralVariable = "",
+ ordinalAndNominalVariables = list(types = "unknown", value = ""),
+ ordinalVariables = list(types = "unknown", value = ""),
+ plotHeight = 320,
+ plotWidth = 480,
+ scaleVariables = list(types = "unknown", value = ""),
+ selectedVariables = list(types = list(), value = list()),
+ selectedVariablesWithControls = list(optionKey = "variable", types = list(), value = list()),
+ selectedVariablesWithControls2 = list(optionKey = "variable", types = list(), value = list()),
+ severalVariablesWithLabels = list(types = list(), value = list()),
+ variableWithLabels = list(types = list(), value = ""),
+ variables = list(types = list(), value = list()),
+ variablesWithConditions = list(types = list(), value = list()),
+ variablesWithConditions2 = list(types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testSpecialSourcesFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("assigned", "combinationCross", "combinations2way", "combinations3way", "compList", "controlVariables", "labelsFor1Variable", "labelsForSeveralVariable", "ordinalAndNominalVariables", "ordinalVariables", "scaleVariables", "selectedVariables", "selectedVariablesWithControls", "selectedVariablesWithControls2", "severalVariablesWithLabels", "variableWithLabels", "variables", "variablesWithConditions", "variablesWithConditions2")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testSpecialSourcesFunc", "testSpecialSources.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testState.R b/R/testState.R
index 6b48c79..34e004b 100644
--- a/R/testState.R
+++ b/R/testState.R
@@ -1,4 +1,4 @@
-testStateFunc <- function(jaspResults, dataset, options) {
+testStateFuncInternal <- function(jaspResults, dataset, options) {
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testStateFuncWrapper.R b/R/testStateFuncWrapper.R
new file mode 100644
index 0000000..42b2944
--- /dev/null
+++ b/R/testStateFuncWrapper.R
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test jaspState
+#'
+testStateFunc <- function(
+ data = NULL,
+ version = "1",
+ checkbox_0 = FALSE,
+ checkbox_1 = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ saveMe = "Blablabla",
+ tabview = list(list(checkbox_2 = FALSE, tabviewOptions = "Tab 1", variablesForStateTab2 = list(types = list(), value = list()), variablesTab1 = list(types = list(), value = list()))),
+ variables = list(types = list(), value = list()),
+ variablesForState = list(types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testStateFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("tabview", "variables", "variablesForState")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testStateFunc", "testState.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testTabView.R b/R/testTabView.R
index 312e25f..9052e82 100644
--- a/R/testTabView.R
+++ b/R/testTabView.R
@@ -1,5 +1,5 @@
-testTabView <- function(jaspResults, dataset, options)
+testTabViewInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testTabViewWrapper.R b/R/testTabViewWrapper.R
new file mode 100644
index 0000000..c12ef39
--- /dev/null
+++ b/R/testTabViewWrapper.R
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Tab View
+#'
+testTabView <- function(
+ data = NULL,
+ version = "1",
+ oneValue = TRUE,
+ plotHeight = 320,
+ plotWidth = 480,
+ subTabs = list(list(keyLabel = "One", keyValue = "oneValue")),
+ tabViewWithFactors = list(list(factors = "", levels = list(types = "unknown", value = ""), repeatedMeasuresCells = list("", ""), repeatedMeasuresFactors = list(list(levels = list("Level 1", "Level 2"), name = "RM Factor 1")), value = "New tab")),
+ tabs = list(list(inputType = "paths", value = "New tab")),
+ threeValue = FALSE,
+ twoValue = FALSE,
+ variables = list(optionKey = "variable", types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testTabView)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("subTabs", "tabViewWithFactors", "tabs", "variables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testTabView", "testTabView.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testTableFormatting.R b/R/testTableFormatting.R
index 747a46a..2bdddf2 100644
--- a/R/testTableFormatting.R
+++ b/R/testTableFormatting.R
@@ -1,4 +1,4 @@
-testTableFormattingFunc <- function(jaspResults, dataset, options)
+testTableFormattingFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testTableFormattingFuncWrapper.R b/R/testTableFormattingFuncWrapper.R
new file mode 100644
index 0000000..43917aa
--- /dev/null
+++ b/R/testTableFormattingFuncWrapper.R
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test jaspTable formatting
+#'
+testTableFormattingFunc <- function(
+ data = NULL,
+ version = "1",
+ checkbox_error = FALSE,
+ plotHeight = 320,
+ plotWidth = 480) {
+
+ defaultArgCalls <- formals(jaspTestModule::testTableFormattingFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testTableFormattingFunc", "testTableFormatting.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testTableView.R b/R/testTableView.R
index ad8ad5d..e393532 100644
--- a/R/testTableView.R
+++ b/R/testTableView.R
@@ -1,4 +1,4 @@
-testTableView <- function(jaspResults, dataset, options) {
+testTableViewInternal <- function(jaspResults, dataset, options) {
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testTableViewWrapper.R b/R/testTableViewWrapper.R
new file mode 100644
index 0000000..35e1b43
--- /dev/null
+++ b/R/testTableViewWrapper.R
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Table View
+#'
+testTableView <- function(
+ data = NULL,
+ version = "1",
+ diagonalTable = list(list(levels = list(), name = "data 1", values = list())),
+ minimumLevels = 2,
+ numberOfRows = 2,
+ numberOfRows2 = 1,
+ plotHeight = 320,
+ plotWidth = 480,
+ testButtons = list(list(levels = "Row 0", name = "data 1", values = "A"), list(levels = "Row 0", name = "data 2", values = "a"), list(levels = "Row 0", name = "data 3", values = "a")),
+ testTypes = list(list(levels = list("Row 0", "Row 1"), name = "data 1", values = list("A", "B")), list(levels = list("Row 0", "Row 1"), name = "data 2", values = list("2", "2")), list(levels = list("Row 0", "Row 1"), name = "data 3", values = list(4, 4)))) {
+
+ defaultArgCalls <- formals(jaspTestModule::testTableView)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("diagonalTable", "testButtons", "testTypes")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testTableView", "testTableView.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testTextArea.R b/R/testTextArea.R
index f5590a8..edfc0e0 100644
--- a/R/testTextArea.R
+++ b/R/testTextArea.R
@@ -1,5 +1,5 @@
-testTextArea <- function(jaspResults, dataset, options)
+testTextAreaInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testTextAreaWrapper.R b/R/testTextAreaWrapper.R
new file mode 100644
index 0000000..4ca80e6
--- /dev/null
+++ b/R/testTextAreaWrapper.R
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test TextArea
+#'
+testTextArea <- function(
+ data = NULL,
+ version = "1",
+ dropDown = list(types = "unknown", value = ""),
+ lavaanScript = list(columns = list(), model = "", modelOriginal = ""),
+ plotHeight = 320,
+ plotWidth = 480,
+ tabView = list(list(checkBoxesInTabView = list(), lavaanCodeInTabView = list(columns = list(), model = "", modelOriginal = ""), usedVariablesInTabView = list(optionKey = "variable", types = list(), value = list()), value = "Model 1")),
+ usedVariables = list(optionKey = "variable", types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testTextArea)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("dropDown", "lavaanScript", "tabView", "usedVariables")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testTextArea", "testTextArea.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/testTransposedTable.R b/R/testTransposedTable.R
index f92ad83..fe090fe 100644
--- a/R/testTransposedTable.R
+++ b/R/testTransposedTable.R
@@ -1,4 +1,4 @@
-testTransposedTableFunc <- function(jaspResults, dataset, options)
+testTransposedTableFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
diff --git a/R/testVariablesForm.R b/R/testVariablesForm.R
index 4a7afb2..16c96b7 100644
--- a/R/testVariablesForm.R
+++ b/R/testVariablesForm.R
@@ -1,8 +1,8 @@
-testVariablesForm <- function(jaspResults, dataset, options)
+testVariablesFormInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
jaspResults[["Hallo"]] <- createJaspHtml(text="hallo!")
-}
\ No newline at end of file
+}
diff --git a/R/testVariablesFormWrapper.R b/R/testVariablesFormWrapper.R
new file mode 100644
index 0000000..4182236
--- /dev/null
+++ b/R/testVariablesFormWrapper.R
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' Test Variables Form
+#'
+testVariablesForm <- function(
+ data = NULL,
+ version = "1",
+ addCheckBox = FALSE,
+ addDropDown = FALSE,
+ maxLevel = -1,
+ maxNumLevel = -1,
+ minLevel = -1,
+ minNumLevel = -1,
+ nominal = FALSE,
+ ordinal = FALSE,
+ plotHeight = 320,
+ plotWidth = 480,
+ scale = TRUE,
+ setType = list(types = "unknown", value = ""),
+ toggleRemoveInvisibles = FALSE,
+ toggleVisibility = TRUE,
+ varS = list(types = list(), value = list()),
+ varToggle = list(types = list(), value = list()),
+ variablesWithControls = list(optionKey = "variable", types = list(), value = list())) {
+
+ defaultArgCalls <- formals(jaspTestModule::testVariablesForm)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("setType", "varS", "varToggle", "variablesWithControls")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "testVariablesForm", "testVariablesForm.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/R/tooltipFunc.R b/R/tooltipFunc.R
index da224da..f40f3f1 100644
--- a/R/tooltipFunc.R
+++ b/R/tooltipFunc.R
@@ -1,4 +1,4 @@
-tooltipFunc <- function(jaspResults, dataset, options)
+tooltipFuncInternal <- function(jaspResults, dataset, options)
{
tableOfOptions(jaspResults, options, dataset)
jaspResults[["Hallo"]] <- createJaspHtml(text="hallo!")
diff --git a/R/tooltipFuncWrapper.R b/R/tooltipFuncWrapper.R
new file mode 100644
index 0000000..bb9c090
--- /dev/null
+++ b/R/tooltipFuncWrapper.R
@@ -0,0 +1,107 @@
+#
+# Copyright (C) 2013-2025 University of Amsterdam
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+# This is a generated file. Don't change it!
+
+#' ToolTip
+#'
+#' @param IntegerWithInfo, Field with info
+#' @param IntegerWithTooLongValueAndInfo, Field with info and too long value
+#' @param checkBoxWithInfo, Great info
+#' Defaults to \code{FALSE}.
+#' @param checkBoxWithInfoAndTooltip, Great info
+#' Defaults to \code{FALSE}.
+#' @param checkBoxWithSubCheckBox, Info for checkbox with sub checkboxes
+#' Defaults to \code{FALSE}.
+#' @param dropDownLabelAbove, Dropdown with info and label above
+#' @param dropDownLabelAboveWithExtraInfo, Dropdown with extra info for value 'Two' and label above
+#' \itemize{
+#' \item \code{"one"} (default)
+#' \item \code{"two"}: Extra info for Two
+#' \item \code{"three"}
+#' }
+#' @param dropdownWithExtraInfo, Dropdown with info
+#' \itemize{
+#' \item \code{"one"} (default) : This is one
+#' \item \code{"two"}
+#' }
+#' @param dropdownWithInfo, Dropdown with info
+#' @param radioButtonsWithInfo, Info for the RadioButton group
+#' \itemize{
+#' \item \code{"radioWithoutInfo"}
+#' \item \code{"radioWithInfo"}: Info just for this RadioButton
+#' }
+#' @param rowRadioButtonsWithInfo, Info for the Row RadioButton group
+#' \itemize{
+#' \item \code{"radioWithoutInfo"}
+#' \item \code{"radioWithInfo"}: Info just for this RadioButton
+#' }
+#' @param rowRadioButtonsWithoutLabelWithInfo, No label but an info
+#' \itemize{
+#' \item \code{"one"}
+#' \item \code{"two"}
+#' }
+#' @param subCheckBoxWithInfo, Info for Sub CheckBox
+#' Defaults to \code{FALSE}.
+tooltipFunc <- function(
+ data = NULL,
+ version = "1",
+ IntegerWithInfo = 0,
+ IntegerWithTooLongValue = 1234567,
+ IntegerWithTooLongValueAndInfo = 1234567,
+ RadioButtonGroup1 = "group1RadioButton1",
+ RadioButtonGroup2 = "group2RadioButton1",
+ checkBoxWithInfo = FALSE,
+ checkBoxWithInfoAndTooltip = FALSE,
+ checkBoxWithSubCheckBox = FALSE,
+ checkBoxWithTooltip = FALSE,
+ checkBoxWithoutTootip = FALSE,
+ dropDownLabelAbove = "one",
+ dropDownLabelAboveWithExtraInfo = "one",
+ dropdownWithExtraInfo = "one",
+ dropdownWithInfo = "one",
+ plotHeight = 320,
+ plotWidth = 480,
+ radioButtons = "radioWithoutInfo",
+ radioButtonsWithInfo = "radioWithoutInfo",
+ rowRadioButtons = "radioWithInfo",
+ rowRadioButtonsWithInfo = "radioWithoutInfo",
+ rowRadioButtonsWithoutLabelWithInfo = "one",
+ rowRadioButtonsWithoutLabelWithoutInfo = "two",
+ subCheckBoxWithInfo = FALSE,
+ subCheckBoxWithoutInfo = FALSE) {
+
+ defaultArgCalls <- formals(jaspTestModule::tooltipFunc)
+ defaultArgs <- lapply(defaultArgCalls, eval)
+ options <- as.list(match.call())[-1L]
+ options <- lapply(options, eval)
+ defaults <- setdiff(names(defaultArgs), names(options))
+ options[defaults] <- defaultArgs[defaults]
+ options[["data"]] <- NULL
+ options[["version"]] <- NULL
+
+
+ if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(data)) {
+ jaspBase::storeDataSet(data)
+ }
+
+ optionsWithFormula <- c("dropDownLabelAbove", "dropDownLabelAboveWithExtraInfo", "dropdownWithExtraInfo", "dropdownWithInfo")
+ for (name in optionsWithFormula) {
+ if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
+
+ return(jaspBase::runWrappedAnalysis("jaspTestModule", "tooltipFunc", "Tooltip.qml", options, version, FALSE))
+}
\ No newline at end of file
diff --git a/inst/Description.qml b/inst/Description.qml
index f341dee..9244a83 100644
--- a/inst/Description.qml
+++ b/inst/Description.qml
@@ -8,7 +8,7 @@ Description
icon: "test.svg"
description: qsTr("A module to test stuff with.")
requiresData: false
- hasWrappers: false
+ hasWrappers: true
preloadData: false
Timer
@@ -125,14 +125,14 @@ Description
hasWrapper: true
}
- // Same form, but NOT aware and NOT wrapped: the engine calls multiDataSetFuncInternal
- // directly (dataset/readDataSet as always) and the dataset selection must stay inert.
- // (It cannot use func: "multiDataSetFunc" - that name is the R-syntax wrapper now.)
+ // Same form, but NOT aware and NOT wrapped: data must arrive the old way (dataset/readDataSet)
+ // and the dataset selection must stay inert. Own func name because with hasWrappers the engine
+ // appends "Internal" to every entry's func (and the wrapper name may not *be* an Internal).
Analysis
{
title: "Test Multi-DataSet (non-aware counterpart)"
qml: "testMultiDataSet.qml"
- func: "multiDataSetFuncInternal"
+ func: "multiDataSetNonAware"
requiresData: true
preloadData: true
multiDataSetAware: false
From 736439c2a2d451e54517485899f401582ce22f5c Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Wed, 7 Oct 2026 09:59:22 +0200
Subject: [PATCH 07/44] remove 4 dead Description entries (+orphaned R files);
two VariablesForms in the multi-dataset test
- Test Transposed jaspTable / Wait for it... (footnotes) / Test jaspContainer pointed
at a test.qml that no longer exists, Test Plot Status at a never-existing
TestPlotStatus.qml; removed the entries plus their now-unreferenced R files
(testTransposedTable.R, testFootnotesTable.R, testContainer.R) and the Timer
reference to the footnotes entry.
- testMultiDataSet.qml now has TWO VariablesForms (A/B), each with its own
dataSetSelection: point A at one dataset and B at the other and the results show
both datasets loaded with per-form routing (source column A/B). The explanation
now also states that a missing Data selection plus a "Non-aware run" table means
the running JASP does not know the feature (stale binary/module).
- Headless tests updated for dependentA/dependentB (23 checks, all passing);
wrappers regenerated with the new defaults.
---
R/multiDataSet.R | 82 +++++++++++++++++---------------
R/multiDataSetFuncWrapper.R | 5 +-
R/multiDataSetNonAwareWrapper.R | 5 +-
R/testContainer.R | 20 --------
R/testFootnotesTable.R | 68 --------------------------
R/testTransposedTable.R | 54 ---------------------
Tools/testMultiDataSet.R | 22 ++++-----
Tools/testMultiDataSet_wrapper.R | 4 +-
inst/Description.qml | 30 ------------
inst/qml/testMultiDataSet.qml | 53 +++++++++++++++------
renv.lock | 33 +++----------
11 files changed, 107 insertions(+), 269 deletions(-)
delete mode 100644 R/testContainer.R
delete mode 100644 R/testFootnotesTable.R
delete mode 100644 R/testTransposedTable.R
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index f1f7a40..90b51c9 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -57,43 +57,46 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
table <- createJaspTable("Selected variables")
jaspResults[["selectedVariables"]] <- table
- table$addColumnInfo("variable", title = "Variable (routed to)")
- table$addColumnInfo("dataSetId", title = "Dataset id")
- table$addColumnInfo("dataSetName", title = "Dataset title")
- table$addColumnInfo("column", title = "Column")
- table$addColumnInfo("type", title = "Type")
- table$addColumnInfo("n", title = "n")
- table$addColumnInfo("values", title = "mean (scale) / first levels (factor)")
-
- values <- .dependentValues(options)
-
- for (value in values) {
- if (is.null(datasets)) {
- # Non-aware: plain preload semantics, decode against the current encoder.
- column <- sub("\\.(scale|ordinal|nominal)$", "", jaspBase::decodeColNames(value))
- entry <- list(variable = column, dataSetId = "-", dataSetName = "-", column = column,
- type = .typeSuffix(value), n = NA_integer_, values = "")
- if (!is.null(dataset) && column %in% names(dataset))
- entry <- .fillDescription(entry, dataset[[column]])
- table[[value]] <- entry
- next
+ table$addColumnInfo("source", title = "Form")
+ table$addColumnInfo("variable", title = "Variable (routed to)")
+ table$addColumnInfo("dataSetId", title = "Dataset id")
+ table$addColumnInfo("dataSetName", title = "Dataset title")
+ table$addColumnInfo("column", title = "Column")
+ table$addColumnInfo("type", title = "Type")
+ table$addColumnInfo("n", title = "n")
+ table$addColumnInfo("values", title = "mean (scale) / first levels (factor)")
+
+ for (entry in list(list(form = "A", values = .dependentValues(options$dependentA)),
+ list(form = "B", values = .dependentValues(options$dependentB)))) {
+ for (value in entry$values) {
+ if (is.null(datasets)) {
+ # Non-aware: plain preload semantics, decode against the current encoder.
+ column <- sub("\\.(scale|ordinal|nominal)$", "", jaspBase::decodeColNames(value))
+ row <- list(source = entry$form, variable = column, dataSetId = "-", dataSetName = "-",
+ column = column, type = .typeSuffix(value), n = NA_integer_, values = "")
+ if (!is.null(dataset) && column %in% names(dataset))
+ row <- .fillDescription(row, dataset[[column]])
+ table[[paste0(entry$form, ":", value)]] <- row
+ next
+ }
+
+ id <- jaspBase::dataSetIdFromEncoded(value)
+ col <- jaspBase::dataSetColumnFromEncoded(value, datasets)
+ row <- list(
+ source = entry$form,
+ variable = value,
+ dataSetId = if (is.na(id)) "none (legacy)" else id,
+ dataSetName = jaspBase::dataSetNameFromEncoded(value, datasets),
+ column = col,
+ type = .typeSuffix(value),
+ n = NA_integer_, values = "")
+
+ columnData <- jaspBase::getDataSetColumn(value, datasets)
+ if (!is.null(columnData))
+ row <- .fillDescription(row, columnData)
+
+ table[[paste0(entry$form, ":", value)]] <- row
}
-
- id <- jaspBase::dataSetIdFromEncoded(value)
- column <- jaspBase::dataSetColumnFromEncoded(value, datasets)
- entry <- list(
- variable = value,
- dataSetId = if (is.na(id)) "none (legacy)" else id,
- dataSetName = jaspBase::dataSetNameFromEncoded(value, datasets),
- column = column,
- type = .typeSuffix(value),
- n = NA_integer_, values = "")
-
- columnData <- jaspBase::getDataSetColumn(value, datasets)
- if (!is.null(columnData))
- entry <- .fillDescription(entry, columnData)
-
- table[[value]] <- entry
}
}
@@ -126,9 +129,10 @@ multiDataSetNonAwareInternal <- function(jaspResults, dataset, options) {
# ------------------------------------------------------------------ internals
-.dependentValues <- function(options) {
- values <- unlist(options$dependent, recursive = TRUE)
- values[!is.na(values) & as.character(values) != ""]
+.dependentValues <- function(values) {
+ if (is.null(values)) return(character(0))
+ values <- unlist(values, recursive = TRUE)
+ as.character(values[!is.na(values) & as.character(values) != ""])
}
.typeSuffix <- function(value) {
diff --git a/R/multiDataSetFuncWrapper.R b/R/multiDataSetFuncWrapper.R
index 382455f..790c0ab 100644
--- a/R/multiDataSetFuncWrapper.R
+++ b/R/multiDataSetFuncWrapper.R
@@ -22,7 +22,8 @@
multiDataSetFunc <- function(
datasets = NULL,
version = "1",
- dependent = list(types = list(), value = list()),
+ dependentA = list(types = list(), value = list()),
+ dependentB = list(types = list(), value = list()),
guardDemo = FALSE,
plotHeight = 320,
plotWidth = 480,
@@ -44,7 +45,7 @@ multiDataSetFunc <- function(
data <- if (!is.null(datasets) && length(datasets)) datasets[[1]] else NULL
- optionsWithFormula <- c("dependent")
+ optionsWithFormula <- c("dependentA", "dependentB")
for (name in optionsWithFormula) {
if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
diff --git a/R/multiDataSetNonAwareWrapper.R b/R/multiDataSetNonAwareWrapper.R
index b2a6734..9aba292 100644
--- a/R/multiDataSetNonAwareWrapper.R
+++ b/R/multiDataSetNonAwareWrapper.R
@@ -22,7 +22,8 @@
multiDataSetNonAware <- function(
data = NULL,
version = "1",
- dependent = list(types = list(), value = list()),
+ dependentA = list(types = list(), value = list()),
+ dependentB = list(types = list(), value = list()),
guardDemo = FALSE,
plotHeight = 320,
plotWidth = 480,
@@ -42,7 +43,7 @@ multiDataSetNonAware <- function(
jaspBase::storeDataSet(data)
}
- optionsWithFormula <- c("dependent")
+ optionsWithFormula <- c("dependentA", "dependentB")
for (name in optionsWithFormula) {
if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
diff --git a/R/testContainer.R b/R/testContainer.R
deleted file mode 100644
index 9228811..0000000
--- a/R/testContainer.R
+++ /dev/null
@@ -1,20 +0,0 @@
-testContainerFuncInternal <- function(jaspResults, dataset, options)
-{
- tableOfOptions(jaspResults, options, dataset)
-
- cnt <- addContainer(addContainer(addContainer(addContainer(jaspResults, name="c0"))))
- testFootnotesTableFuncInternal(cnt, dataset, options)
-
- cnt <- addContainer(addContainer(addContainer(addContainer(jaspResults, name="c1")), title="hallo"))
- testFootnotesTableFuncInternal(cnt, dataset, options)
-
- cnt <- addContainer(addContainer(addContainer(addContainer(jaspResults, title="hallo", name="c2")), title="er zit er eentje stiekem om me heen"), title="hallo", initCollapsed=TRUE)
- testFootnotesTableFuncInternal(cnt, dataset, options)
-}
-
-addContainer <- function(inContainer, name="container", title="", initCollapsed=FALSE)
-{
- inContainer[[name]] = createJaspContainer(title=title, initCollapsed=initCollapsed)
-
- return(inContainer[[name]])
-}
diff --git a/R/testFootnotesTable.R b/R/testFootnotesTable.R
deleted file mode 100644
index 8df1bac..0000000
--- a/R/testFootnotesTable.R
+++ /dev/null
@@ -1,68 +0,0 @@
-testFootnotesTableFuncInternal <- function(jaspResults, dataset, options)
-{
- tableOfOptions(jaspResults, options, dataset)
-
- jaspResults[['table0']] <- createFootnotesTable(options=options)
- jaspResults[['table1']] <- createFootnotesTable(options=options, notUnique=TRUE)
-
- createEmptiesTable(jaspResults)
- createCombinations(jaspResults)
-}
-
-createCombinations <- function(jaspResults)
-{
- binary <- data.frame(list(a=c("00", "01"), b=c("10", "11")))
- rownames(binary) <- c('c', 'd')
- tab <- createJaspTable("Combining row- with col-names or not!")
-
- tab$setData(binary)
-
- tab$addFootnote(message="nothing!")
- tab$addFootnote(message="just row", rowNames='c')
- tab$addFootnote(message="just col", colNames='a')
- tab$addFootnote(message="row&&col", rowNames='d', colNames='b')
-
- jaspResults[["cartesianFootnotes"]] <- tab
-}
-
-createEmptiesTable <- function(jaspResults)
-{
- #for https://github.com/jasp-stats/INTERNAL-jasp/issues/538 (footnotes mess)
-
- tab <- createJaspTable(paste0("Table with Footnotes at empty cell"))
- jaspResults[["tableEmptyCell"]] <- tab
-
- tab$setExpectedSize(rows=3, cols=3)
- tab$setColumnName(1, 'b')
- tab$setRowName(1, 'b')
-
- tab$setColumnName(2, 'a')
- tab$setColumnName(3, 'c')
- tab$setRowName(3, 'a')
-
- tab$addFootnote(message="hallo", rowNames='a', colNames='c')
-
- tab$addRows(list(a=NA, b=NA, c=NA))
- tab$addFootnote(message="NA!", rowNames='b', colNames='b')
-}
-
-createFootnotesTable <- function(numFootnotes=3, rowNames=c("b", "c", "c"), colNames=c("a", "a", "b"), options, notUnique=FALSE)
-{
- foo <- sapply(letters[21:23], function(col) paste(letters[24:26], col))
- rownames(foo) <- colnames(foo) <- letters[1:3]
-
- tableFootnotes <- createJaspTable(paste0("Table with Footnotes at rowNames=(", paste0(rowNames, collapse=", "), ") and colNames=(", paste0(colNames, collapse=", "), ")", collapse=""), foo, dependencies="checkbox_0")
-
- msgNum <- 0
-
- while(msgNum < numFootnotes)
- {
- msgNum <- msgNum + 1
-
- if(options$checkbox_0 == notUnique) tableFootnotes$addFootnote(message = paste0("msg", as.character(msgNum)), rowNames = rowNames[[msgNum]], colNames = colNames[[msgNum]])
- else if(options$checkbox_1 != notUnique) tableFootnotes$addFootnote(message = "Identical Twins!", rowNames = rowNames[[msgNum]], colNames = colNames[[msgNum]])
- else tableFootnotes$addFootnote(message = "Identical Symbols!", rowNames = rowNames[[msgNum]], colNames = colNames[[msgNum]], symbol="?")
- }
-
- return(tableFootnotes);
-}
diff --git a/R/testTransposedTable.R b/R/testTransposedTable.R
deleted file mode 100644
index fe090fe..0000000
--- a/R/testTransposedTable.R
+++ /dev/null
@@ -1,54 +0,0 @@
-testTransposedTableFuncInternal <- function(jaspResults, dataset, options)
-{
- tableOfOptions(jaspResults, options, dataset)
-
-
- # the correlation table stored here
- mainTable <- createJaspTable(title = "Transposed Table")
- mainTable$showSpecifiedColumnsOnly <- TRUE
-
- # I guess we want the transpose
- mainTable$transpose <- TRUE
-
- # but we don't want overtitles over the "displayed" columns
- #mainTable$transposeWithOvertitle <- FALSE
-
- # the displayed columns are supposed to be just the number of variable
- mainTable$addColumnInfo(name = "var", title = "", type = "string", overtitle="Variables")
-
- # now we need to define the "displayed" rows; ideally defining columns with overtitles
- whichtests <- c(TRUE, TRUE, TRUE)#options$pearson, options$spearman, options$kendallsTauB)
- testsTitles <- c("Pearson's rho", "Spearman's r", "Kendall's Tau B")[whichtests]
- tests <- c("pearson", "spearman", "kendall")[whichtests]
-
- vars <- options$variables
- vvars <- vars # inside just, this will be actually .v(vars)
-
- for (vi in seq_along(vvars)){
- for(ti in seq_along(tests)){
- mainTable$addColumnInfo(
- name = paste(vvars[vi], tests[ti], "r", sep = "."),
- title = testsTitles[ti], type = "number",
- overtitle = vars[vi]) # this overtitle should appear as a first column
-
-
- #if(options$reportSignificance)
- mainTable$addColumnInfo(name = paste(vvars[vi], tests[ti], "p.value", sep = "."),
- title = "p-value", type = "pvalue",
- overtitle = vars[vi]) # this overtitle should appear as a first column
-
- # here will be more option-dependent stuff, but this should be enough as an example
- }
- }
-
- # the displayed columns will show the variable names
- mainTable$addColumns(list(var = vars))
-
- # everything else is passed to the table with the computed results...
- # fake example
- mainTable$addColumns(list(contNormal.pearson.r = c(0.2, 0.3, 0.4), contNormal.pearson.p.value = c(0.1, 0.034, 0.001)))
-
- #mainTable$print()
- jaspResults[['transposeMe']] <- mainTable
-
-}
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index fb9b07c..fc9ed92 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -51,8 +51,8 @@ suppressMessages(jaspTools::setupJaspTools(
jaspTools::setPkgOption("module.dirs", moduledir)
jaspTools::setPkgOption("reinstall.modules", FALSE)
-opts1 <- list(dependent = c("JASPColumn_11_0.scale", "JASPColumn_11_2.nominal",
- "JASPColumn_12_0.scale", "JASPColumn_12_1.scale"),
+opts1 <- list(dependentA = c("JASPColumn_11_0.scale", "JASPColumn_11_2.nominal"),
+ dependentB = c("JASPColumn_12_0.scale", "JASPColumn_12_1.scale"),
showMeta = FALSE, guardDemo = TRUE, plotWidth = 400, plotHeight = 300)
res1 <- jaspTools::runAnalysis("multiDataSetFunc", options = opts1, datasets = datasets, view = FALSE, quiet = TRUE)
r1 <- res1$results
@@ -66,26 +66,26 @@ ovTitle <- columnValues(r1$dataSetOverview, "title")
check(identical(unname(ovId), c("11", "12")), "overview ids 11,12")
check(identical(unname(ovTitle), c("DataSetA", "DataSetB")), "overview titles from dataSetNames attr")
+# schema order: source=1, variable=2, ... keyed by the row id so assertions do not depend on json order
sv <- r1$selectedVariables
+svSrc <- columnValues(sv, "source")
svVar <- columnValues(sv, "variable")
svId <- columnValues(sv, "dataSetId")
svName <- columnValues(sv, "dataSetName")
svCol <- columnValues(sv, "column")
svType <- columnValues(sv, "type")
svN <- columnValues(sv, "n")
-# keyed by the row id so assertions do not depend on json row order
-byRow <- function(v) v[svVar]
expected <- list(
- "JASPColumn_11_0.scale" = c(id = "11", name = "DataSetA", column = "Score", type = "scale"),
- "JASPColumn_11_2.nominal" = c(id = "11", name = "DataSetA", column = "Group", type = "nominal"),
- "JASPColumn_12_0.scale" = c(id = "12", name = "DataSetB", column = "Score", type = "scale"),
- "JASPColumn_12_1.scale" = c(id = "12", name = "DataSetB", column = "Age", type = "scale"))
+ "JASPColumn_11_0.scale" = c(src = "A", id = "11", name = "DataSetA", column = "Score", type = "scale"),
+ "JASPColumn_11_2.nominal" = c(src = "A", id = "11", name = "DataSetA", column = "Group", type = "nominal"),
+ "JASPColumn_12_0.scale" = c(src = "B", id = "12", name = "DataSetB", column = "Score", type = "scale"),
+ "JASPColumn_12_1.scale" = c(src = "B", id = "12", name = "DataSetB", column = "Age", type = "scale"))
check(all(names(expected) %in% svVar), "all four dependents present in the routing table")
for (v in names(expected)) if (v %in% svVar) {
i <- which(svVar == v)[1]
- check(svId[i] == expected[[v]]["id"] && svName[i] == expected[[v]]["name"] &&
+ check(svSrc[i] == expected[[v]]["src"] && svId[i] == expected[[v]]["id"] && svName[i] == expected[[v]]["name"] &&
svCol[i] == expected[[v]]["column"] && svType[i] == expected[[v]]["type"],
- paste0("routing ", v, " -> ", expected[[v]]["name"], "/", expected[[v]]["column"]))
+ paste0("routing [form ", expected[[v]]["src"], "] ", v, " -> ", expected[[v]]["name"], "/", expected[[v]]["column"]))
}
check(all(svN == "10"), "all four columns read 10 rows")
@@ -105,7 +105,7 @@ check(any(grepl("MULTIDATASET-WRAPPER-OK", status2, fixed = TRUE)), "wrapper sub
# ------------------------------------------------------------------ Path 3: legacy still OK ----
cat("\n== Path 3: legacy non-aware run (no datasets) ==\n")
res3 <- jaspTools::runAnalysis("multiDataSetFunc", dataset = datasets[["11"]],
- options = list(dependent = c("Score"), showMeta = FALSE,
+ options = list(dependentA = c("Score"), dependentB = c("Age"), showMeta = FALSE,
guardDemo = TRUE, plotWidth = 400, plotHeight = 300),
view = FALSE, quiet = TRUE)
raw3 <- jsonlite::toJSON(res3, auto_unbox = TRUE)
diff --git a/Tools/testMultiDataSet_wrapper.R b/Tools/testMultiDataSet_wrapper.R
index e6329a8..6454b51 100644
--- a/Tools/testMultiDataSet_wrapper.R
+++ b/Tools/testMultiDataSet_wrapper.R
@@ -17,7 +17,9 @@ datasets <- list(
"12" = read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")))
attr(datasets, "dataSetNames") <- c("11" = "DataSetA", "12" = "DataSetB")
-res <- jaspTestModule::multiDataSetFunc(datasets = datasets, dependent = c("Score", "Condition"))
+res <- jaspTestModule::multiDataSetFunc(datasets = datasets,
+ dependentA = "Score", # in both datasets -> routes to the primary
+ dependentB = c("Age", "Condition")) # Condition only exists in DataSetB
raw <- as.character(res$.__enclos_env__$private$getResults())
j <- jsonlite::fromJSON(raw, simplifyVector = FALSE)$results
diff --git a/inst/Description.qml b/inst/Description.qml
index 9244a83..9e031de 100644
--- a/inst/Description.qml
+++ b/inst/Description.qml
@@ -18,7 +18,6 @@ Description
{
console.log(qsTr("Timer that displays the fact that updating Description.qml from live javascript code works fine."))
testModuleDescription.title = qsTr("Test Module?")
- footnotesEntry.title = qsTr("Test Footnotes jaspTable")
}
running: true
@@ -26,13 +25,6 @@ Description
}
GroupTitle { title: "jaspResults stuff" }
- Analysis
- {
- title: qsTr("Test Transposed jaspTable")
- qml: "test.qml"
- func: "testTransposedTableFunc"
- }
-
Analysis
{
title: qsTr("Test jaspTable with crappy data")
@@ -48,14 +40,6 @@ Description
func: "testTableFormattingFunc"
}
- Analysis
- {
- id: footnotesEntry
- title: qsTr("Wait for it...")
- qml: "test.qml"
- func: "testFootnotesTableFunc"
- }
-
Analysis
{
title: qsTr("Test jaspState")
@@ -77,20 +61,6 @@ Description
func: "testLatexFunc"
}
- Analysis
- {
- title: qsTr("Test jaspContainer")
- qml: "test.qml"
- func: "testContainerFunc"
- }
-
- Analysis
- {
- title: qsTr("Test Plot Status")
- qml: "TestPlotStatus.qml"
- func: "testPlotStatus"
- }
-
Analysis
{
title: qsTr("Test Variables encoding")
diff --git a/inst/qml/testMultiDataSet.qml b/inst/qml/testMultiDataSet.qml
index cb29b2b..01cd24a 100644
--- a/inst/qml/testMultiDataSet.qml
+++ b/inst/qml/testMultiDataSet.qml
@@ -9,29 +9,52 @@ Form
ExplanationText
{
text:
- "Test the multi-dataset awareness of VariablesForm: the dataset/filter selection at the top " +
- "(only live for multiDataSetAware analyses) plus the per-dataset routing in the results.
" +
+ "Test the multi-dataset awareness of VariablesForm: each form has its own " +
+ "dataset/filter selection (only live for multiDataSetAware analyses) and the results " +
+ "show per-variable routing to the dataset it came from.
" +
"" +
- "- Open a second dataset (e.g. add another CSV) so the selection has something to choose from.
" +
- "- Drag variables from different datasets into the list: the results table should route " +
- "each one to its own dataset (id, title, column).
" +
- "- Pick another dataset/filter in the selection: only columns of that dataset should remain " +
- "selectable for new drags and the run should recompute.
" +
+ "- Open a second dataset (e.g. add another CSV) so the selections have something to choose from.
" +
+ "- Set form A's Data selection to one dataset and form B's to the other: the run should then " +
+ "load both datasets (see the 'Datasets in this run' table).
" +
+ "- Drag variables (try the identically named 'Score'!) into both lists: the routing table " +
+ "must attribute each one to its own dataset, filter and column.
" +
"- show .meta: the provenance stamps (dataSetId/filterId) on the bound options.
" +
"- guard demo: readDataSet() must hard-stop inside an aware run.
" +
"- Save the analysis to a .jasp and reopen it: the dataset routing must survive the round trip.
" +
- "
"
+ "" +
+ "If no Data selection shows up, the results table will say 'Non-aware run': the analysis was " +
+ "not recognised as multiDataSetAware (old JASP binary or stale module install)."
}
- VariablesForm
- {
- dataSetSelection: true
+ Section {
+ title: qsTr("Form A - variables from one dataset")
+
+ VariablesForm
+ {
+ dataSetSelection: true
+
+ AvailableVariablesList { name: "allVariablesA" }
+ AssignedVariablesList
+ {
+ name: "dependentA"
+ title: qsTr("Variables A")
+ }
+ }
+ }
- AvailableVariablesList { name: "allVariables" }
- AssignedVariablesList
+ Section {
+ title: qsTr("Form B - variables from (hopefully) another dataset")
+
+ VariablesForm
{
- name: "dependent"
- title: qsTr("Variables (from any dataset)")
+ dataSetSelection: true
+
+ AvailableVariablesList { name: "allVariablesB" }
+ AssignedVariablesList
+ {
+ name: "dependentB"
+ title: qsTr("Variables B")
+ }
}
}
diff --git a/renv.lock b/renv.lock
index e171ff6..f4558d1 100644
--- a/renv.lock
+++ b/renv.lock
@@ -411,33 +411,12 @@
"jaspBase": {
"Package": "jaspBase",
"Version": "0.20.4",
- "Source": "GitHub",
- "Requirements": [
- "cli",
- "codetools",
- "ggplot2",
- "gridExtra",
- "gridGraphics",
- "jaspGraphs",
- "jsonlite",
- "lifecycle",
- "officer",
- "pkgbuild",
- "plyr",
- "ragg",
- "R6",
- "Rcpp",
- "rvg",
- "svglite",
- "systemfonts",
- "withr",
- "testthat"
- ],
- "RemoteType": "github",
- "RemoteHost": "api.github.com",
- "RemoteUsername": "jasp-stats",
- "RemoteRepo": "jaspBase",
- "RemoteSha": "6a6910dbe148caba2d82d60b8c42305ac40d2f1d"
+ "Source": "Local",
+ "Requirements": ["cli", "codetools", "compiler", "ggplot2", "grDevices", "grid", "gridExtra", "gridGraphics", "jaspGraphs", "jsonlite", "lifecycle", "methods", "officer", "pkgbuild", "plyr", "ragg", "R6", "Rcpp", "rvg", "svglite", "systemfonts", "withr"],
+ "RemoteType": "local",
+ "RemoteUrl": "/home/virtuoos/Broncode/JASP/jasp-desktop/Engine/jaspBase",
+ "Cacheable": true,
+ "Hash": "7fa78a6a9cb16c17cf2707e7bb5ff577"
},
"jaspGraphs": {
"Package": "jaspGraphs",
From 2ef9f639869abe1c65f4400124deb5caab275c11 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Wed, 7 Oct 2026 20:23:50 +0200
Subject: [PATCH 08/44] multiDataSet demo: index the encoded namespace directly
The demo analysis now shows the feature as designed: option values ARE
the datasets' column names (both encoded by the same per-dataset
encoder; results are decoded on the way out by the engine), so
getDataSetColumn(value, datasets) is the whole lookup. Dropped the
decode-first logic, the redundant 'column'/'type' table fields and the
legacy decodeColNames call. Path-1 test fixtures are faithful now:
slices carry encoded column names exactly like rbridge delivers them,
including per-slice mean checks against the source csv (catches
cross-dataset mixups). Wrapper path marked SKIP pending the
syntax-mode dataset-selection flow (TODO-multidataset.md).
---
R/multiDataSet.R | 50 ++++++++-----------
TODO-multidataset.md | 76 +++++++++++++++++++++++++++++
Tools/testMultiDataSet.R | 83 ++++++++++++++++++++------------
Tools/testMultiDataSet_wrapper.R | 12 +++--
4 files changed, 159 insertions(+), 62 deletions(-)
create mode 100644 TODO-multidataset.md
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index 90b51c9..80f9888 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -1,9 +1,14 @@
# Multi-dataset aware analyses (jasp-desktop branch dataSetAwareVarForm, jaspBase branch
# multiDataSetAware). An analysis whose Description/Analysis entry sets multiDataSetAware gets
# every dataset it references as `datasets`: a named list keyed by dataset id, with the user
-# facing titles in attr(datasets, "dataSetNames"). Its variable options carry encoded column
-# names whose prefix embeds the dataset they were selected from (JASPColumn__),
-# which jaspBase's dataSetIdFromEncoded / dataSetNameFromEncoded / getDataSetColumn route.
+# facing titles in attr(datasets, "dataSetNames"). Options and data share the ENCODED namespace:
+# variable options carry names like "JASPColumn___Encoded" and the dataframes'
+# column names are the very same strings (encoded by each dataset's own ColumnEncoder, whose
+# prefix embeds the dataset id), so an analysis indexes with the option value as-is:
+# getDataSetColumn(value, datasets) / datasets[[id]][[value]]. Result strings are decoded back to
+# the original names on their way to the GUI, so putting encoded names in tables/plots is not
+# just allowed, it is how provenance survives. jaspBase's dataSetIdFromEncoded /
+# dataSetNameFromEncoded / getDataSetFor route values to their dataset.
# While such a run is active, readDataSet* stops: one 'current dataset' is meaningless here.
multiDataSetFuncInternal <- function(jaspResults, dataset, options, datasets = NULL) {
@@ -35,7 +40,7 @@ dataSetOverviewTable <- function(jaspResults, datasets, dataset) {
table$addColumnInfo("title", title = "Title")
table$addColumnInfo("rows", title = "Rows")
table$addColumnInfo("cols", title = "Columns")
- table$addColumnInfo("columnNames", title = "Column names")
+ table$addColumnInfo("columnNames", title = "Column names (decoded on the way out)")
if (!is.null(datasets)) {
titles <- attr(datasets, "dataSetNames")
@@ -48,7 +53,7 @@ dataSetOverviewTable <- function(jaspResults, datasets, dataset) {
}
} else if (!is.null(dataset)) {
table[["current"]] <- list(
- id = "(current)", title = "(the one dataset)", rows = nrow(dataset), ncol(dataset),
+ id = "(current)", title = "(the one dataset)", rows = nrow(dataset), cols = ncol(dataset),
columnNames = paste(names(dataset), collapse = ", "))
}
}
@@ -58,40 +63,32 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
jaspResults[["selectedVariables"]] <- table
table$addColumnInfo("source", title = "Form")
- table$addColumnInfo("variable", title = "Variable (routed to)")
+ table$addColumnInfo("variable", title = "Variable (decoded on the way out)")
table$addColumnInfo("dataSetId", title = "Dataset id")
table$addColumnInfo("dataSetName", title = "Dataset title")
- table$addColumnInfo("column", title = "Column")
- table$addColumnInfo("type", title = "Type")
table$addColumnInfo("n", title = "n")
table$addColumnInfo("values", title = "mean (scale) / first levels (factor)")
for (entry in list(list(form = "A", values = .dependentValues(options$dependentA)),
list(form = "B", values = .dependentValues(options$dependentB)))) {
for (value in entry$values) {
- if (is.null(datasets)) {
- # Non-aware: plain preload semantics, decode against the current encoder.
- column <- sub("\\.(scale|ordinal|nominal)$", "", jaspBase::decodeColNames(value))
- row <- list(source = entry$form, variable = column, dataSetId = "-", dataSetName = "-",
- column = column, type = .typeSuffix(value), n = NA_integer_, values = "")
- if (!is.null(dataset) && column %in% names(dataset))
- row <- .fillDescription(row, dataset[[column]])
- table[[paste0(entry$form, ":", value)]] <- row
- next
+ # value indexes the data as-is in both modes: options and column names share the encoded
+ # namespace (or are both plain, in a jaspTools run). Only the routing to one dataset out
+ # of `datasets` is aware-specific; the non-aware run has exactly the one dataset anyway.
+ columnData <- if (is.null(datasets)) {
+ if (!is.null(dataset) && value %in% names(dataset)) dataset[[value]] else NULL
+ } else {
+ jaspBase::getDataSetColumn(value, datasets)
}
- id <- jaspBase::dataSetIdFromEncoded(value)
- col <- jaspBase::dataSetColumnFromEncoded(value, datasets)
+ id <- if (is.null(datasets)) NA_integer_ else jaspBase::dataSetIdFromEncoded(value)
row <- list(
source = entry$form,
variable = value,
- dataSetId = if (is.na(id)) "none (legacy)" else id,
- dataSetName = jaspBase::dataSetNameFromEncoded(value, datasets),
- column = col,
- type = .typeSuffix(value),
+ dataSetId = if (is.null(datasets)) "-" else if (is.na(id)) "none (legacy)" else as.character(id),
+ dataSetName = if (is.null(datasets)) "-" else jaspBase::dataSetNameFromEncoded(value, datasets),
n = NA_integer_, values = "")
- columnData <- jaspBase::getDataSetColumn(value, datasets)
if (!is.null(columnData))
row <- .fillDescription(row, columnData)
@@ -135,11 +132,6 @@ multiDataSetNonAwareInternal <- function(jaspResults, dataset, options) {
as.character(values[!is.na(values) & as.character(values) != ""])
}
-.typeSuffix <- function(value) {
- match <- regmatches(as.character(value), regexec("\\.(scale|ordinal|nominal)$", value))[[1]]
- if (length(match) == 2L) match[2] else NA_character_
-}
-
.fillDescription <- function(entry, columnData) {
if (is.numeric(columnData)) {
entry$n <- sum(!is.na(columnData))
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
new file mode 100644
index 0000000..3f7a3e6
--- /dev/null
+++ b/TODO-multidataset.md
@@ -0,0 +1,76 @@
+# Multi-dataset aware feature — open work (2026-10-07)
+
+## Decided design (ground truth from user, this session)
+- Options and dataset slices live in the SAME encoded namespace everywhere (`JASPColumn___Encoded`);
+ R indexes `datasets[[id]][[encodedValue]]` directly; results/plots are decoded on the way out (engine sendString).
+- `preloadData` is forced true for aware analyses (done at `Modules::AnalysisEntry::preloadData()` + EntryBase),
+ and the engine checks `_analysisMultiDataSet` *before* the preload flag.
+- Syntax mode must encode like the engine (verified: it does for single-dataset). No scans, no decode-hacks.
+- Syntax-mode multi-dataset (user's design, TO BUILD):
+ `datasets = list(haha = df1, godverdomme = df2)` loads each df into the bridge **Workspace/DataSet**
+ (title = the user's name; names are user-convenience only). **The VariablesForms' dataset selections are
+ specific options** that must not be empty (check!); the user fills e.g. `"haha"` there as soon as the data
+ is loaded; selecting it switches the form's dataset context, QMLComponents then validate/encode the
+ column-name options against that dataset (they know their sources, stamp `.meta` dataSetId), and the
+ encoder (now existing via DataSet) encodes per datasetId. This cascades through the options.
+
+## TODO
+1. [done: subagent design] Option-backed VariablesForm dataset selection for syntax mode. Agreed plan:
+ - CommonData/workspace: `dataSetByTitle(QString)` exact-match lookup (mirror dataSetByName).
+ - VariablesFormBase: `dataSetSelectionOption` Q_PROPERTY (option name for this form's dataset selection);
+ setter also self-declares awareness (`analysisObj()->setMultiDataSetAware(true)` — bridge dummy analysis
+ otherwise never gets it); `dataSetTitleValues()` (workspace titles); `selectDataSetByName(name)`:
+ empty/unknown -> addControlError, match -> analysis->setFilterId(ds->defaultFilter()->id()) +
+ Workspace::setShownDataSet(ds) (filterId semantics = default, syntax users pre-filter).
+ - VariablesForm.qml: a second, BOUND DropDown (name: dataSetSelectionOption, values: titles) gated by
+ NO_DESKTOP_MODE (typeof-guard) -> desktop stays 100% inert; wrapper generation picks the option up.
+ AssignedVariablesList gets `depends: ""` so bindTo applies the selection FIRST
+ (setInitialized defers; meta then stamps the right dataSetId via createMeta).
+ - AnalysisForm: `dataSetSelectionOptionNames()` (findChildren).
+ - syntaxbridge loadQmlAndParseOptionsStatus: PRE-CHECK raw options JSON for those names (empty check,
+ because ComboBoxBase coerces "" to first entry); after parse + when analysisObj aware:
+ mirror Engine::runAnalysis aware block -> encodeColumnNamesinOptionsPerDataSet + setMultiDataSetQueue
+ + status["multiDataSetJson"] = {ids, names-by-title} (additive JSON key, no ABI change).
+ - DataSetProvider::loadDataSet overload with title; SyntaxBridgeDataSet.name finally used
+ (dataframeimporter sets it; loadDataSets R export validates: named list, unique non-empty names);
+ provider tracks first-loaded id as primary. createDataSet's empty-reuse quirk handled.
+ - jaspBase: storeDataSets -> jaspSyntax::loadDataSets; runWrappedAnalysis aware path uses
+ loadQmlAndParseOptionsStatus + runJaspResults(multiDataSetJson=...) -> engine-parity queued slices
+ (encoded names + real ids; the user's plain list is NOT handed over anymore on this path).
+ jaspTools keeps using the direct datasets= handout branch.
+2. [impl] SyntaxInterface + jaspSyntax: multi-dataset named loading into bridge workspace (plan items above).
+3. [impl] Extract the Engine::runAnalysis aware encode/queue block to shared code (DataBridge method or
+ similar) so engine + syntaxbridge use ONE implementation (no duplication!).
+4. [impl] jaspBase runWrappedAnalysis aware flow per plan (incl. empty-selection pre-check surfacing via
+ Rcpp::stop channel).
+5. [test] Module wrapper test rewrite for the new flow: `dataSetA = "haha"` style options + `depends` in
+ testMultiDataSet.qml; overview keyed by bridge ids with user names as titles; direct indexing.
+ (Current path-2 FAIL is the known gap this closes; mark accordingly until done.)
+6. [fix] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the analysis'
+ OWN dataset encoder only — aware analyses plotting other datasets stay encoded. Same multi-encoder
+ treatment as `Engine::sendString` `_analysisDataSetEncoders`.
+7. [harden] `_analysisDataSetEncoders` stores raw `ColumnEncoder*` — dataset deleted mid-run dangles
+ (only the CURRENT pointer is guarded in ~DataSet). Re-resolve by id (or QPointer-style) at send time.
+8. [verify] GUI end-to-end after rebuild: dropdown fills tables (aware + twin), guard demo, per-form dataset
+ switching, saved-file reload of an aware analysis (provenance remap path `restoreProvenanceFromBoundValues`
+ / `remapSavedProvenance` has no end-to-end test yet).
+9. [rebuild] Bundle via `Tools/buildBundle.R` (new jaspBase + module), user reinstalls in dev JASP.
+10. [commit] Everything across: jasp-desktop (incl. submodule bump), jaspBase branch multiDataSetAware,
+ jaspTools branch multiDataSetAware, jaspTestModule.
+11. [note] Side effects to document/verify once syntax flow lands: readRequestedDataset() after an aware
+ parse consumes queue slices; syntax-mode result decoding (columnEncoderContext) per dataset.
+
+## Done this session (committed unless noted)
+- jasp-desktop `515c1f241`: dropdown visibility fixes (syncMultiDataSetAwareness push instead of computed
+ getter; EntryBase multiDataSetAwareChanged→somethingChanged; VariablesFormBase::setUp bootstrap — static
+ controls never get formIsKnown!) + render probe (93 QuickTest incl. probe).
+- UNCOMMITTED (working tree, all tests green): real-format `_Encoded` regex (C++ mirror later removed per
+ user), removed `.decodeColNamesForDataSet` callback chain (jasprcpp/interface/rbridge/jaspTools stub),
+ preloadData forced for aware (EntryBase + AnalysisEntry), engine checks multiAware before preload +
+ primaryDataSetId fallback (fresh unfiltered analyses sent dataSetId -1 → empty slice queue = the
+ "empty cells" root cause), encode-per-dataset always collects cols for aware, testall encode→decode→
+ encode→decode cycle test on real encoders, rlogic bridge round-trip via jaspSyntax (real encoder output,
+ index-directly invariant proven through the bridge), jaspBase helpers rewritten to encoded-namespace
+ direct indexing (dataSetColumnFromEncoded + dataSetEncodedNames snapshot deleted), module rewritten for
+ direct indexing, module test path-1 faithful (encoded slice names) green.
+- Known NOT-a-bug: jaspTools doesn't encode (longstanding, user-confirmed, out of scope).
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index fc9ed92..deaed33 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -2,7 +2,10 @@
# Full headless test of the multi-dataset aware analysis (Test Multi-DataSet).
#
# Path 1 (engine-style, jaspTools::runAnalysis + datasets=): options carry encoded column
-# names with embedded dataset ids; jaspTools queues the slices exactly like the engine does.
+# names and the slices are dataframes with THOSE SAME encoded column names - exactly what the
+# engine delivers (both sides encoded by each dataset's ColumnEncoder; see the bridge round-trip
+# in jasp-desktop Tests/R/test_multidataset_rlogic.R). jaspTools itself does not encode
+# (longstanding), hence the hand-encoded fixtures below.
# Path 2 (wrapper, jaspTestModule::multiDataSetFunc(datasets=...)): plain column names plus a
# named list of datasets, runWrappedAnalysis -> runJaspResults with a direct R-side handout.
#
@@ -37,13 +40,24 @@ columnValues <- function(tb, fieldName) {
stats::setNames(vapply(d[rowKeys], function(v) as.character(v), character(1), USE.NAMES = FALSE), rowKeys)
}
-datasets <- list(
- "11" = read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")),
- "12" = read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")))
+# Slices as the engine hands them over: the dataframe columns carry the encoded names
+# (JASPColumn___Encoded - DataSet::setupEncoderPrefix), NOT the csv headers.
+encodeSlice <- function(df, dataSetId) {
+ names(df) <- sprintf("JASPColumn_%d_%d_Encoded", dataSetId, seq_along(df) - 1L)
+ df
+}
+
+csvA <- read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")) # Score, Age, Group
+csvB <- read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")) # Score, Age, Condition
+
+datasets <- list("11" = encodeSlice(csvA, 11), "12" = encodeSlice(csvB, 12))
attr(datasets, "dataSetNames") <- c("11" = "DataSetA", "12" = "DataSetB")
+encA <- stats::setNames(sprintf("JASPColumn_11_%d_Encoded", seq_along(csvA) - 1L), names(csvA)) # Score, Age, Group
+encB <- stats::setNames(sprintf("JASPColumn_12_%d_Encoded", seq_along(csvB) - 1L), names(csvB)) # Score, Age, Condition
+
# ------------------------------------------------------------------ Path 1: jaspTools queue ----
-cat("== Path 1: jaspTools::runAnalysis with queued slices (engine semantics) ==\n")
+cat("== Path 1: jaspTools::runAnalysis with queued slices (engine semantics, encoded names) ==\n")
suppressMessages(library(jaspTools))
suppressMessages(jaspTools::setupJaspTools(
pathJaspDesktop = normalizePath(file.path(moduledir, "..", "jasp-desktop")),
@@ -51,8 +65,8 @@ suppressMessages(jaspTools::setupJaspTools(
jaspTools::setPkgOption("module.dirs", moduledir)
jaspTools::setPkgOption("reinstall.modules", FALSE)
-opts1 <- list(dependentA = c("JASPColumn_11_0.scale", "JASPColumn_11_2.nominal"),
- dependentB = c("JASPColumn_12_0.scale", "JASPColumn_12_1.scale"),
+opts1 <- list(dependentA = c(encA[["Score"]], encA[["Group"]]),
+ dependentB = c(encB[["Score"]], encB[["Age"]]),
showMeta = FALSE, guardDemo = TRUE, plotWidth = 400, plotHeight = 300)
res1 <- jaspTools::runAnalysis("multiDataSetFunc", options = opts1, datasets = datasets, view = FALSE, quiet = TRUE)
r1 <- res1$results
@@ -63,50 +77,59 @@ check(length(r1$dataSetOverview$data) == 5L, "dataset overview data has exactly
ovId <- columnValues(r1$dataSetOverview, "id")
ovTitle <- columnValues(r1$dataSetOverview, "title")
+ovCols <- columnValues(r1$dataSetOverview, "cols")
check(identical(unname(ovId), c("11", "12")), "overview ids 11,12")
check(identical(unname(ovTitle), c("DataSetA", "DataSetB")), "overview titles from dataSetNames attr")
+check(all(ovCols == "3"), "both slices reported 3 columns")
+
+# the overview shows the ENCODED names (headless run: no engine sendString decode in between)
+ovNames <- columnValues(r1$dataSetOverview, "columnNames")
+check(all(c(paste(encA, collapse = ", "), paste(encB, collapse = ", ")) %in% unname(ovNames)),
+ "overview column names are the encoded names the analysis received")
-# schema order: source=1, variable=2, ... keyed by the row id so assertions do not depend on json order
sv <- r1$selectedVariables
svSrc <- columnValues(sv, "source")
svVar <- columnValues(sv, "variable")
svId <- columnValues(sv, "dataSetId")
svName <- columnValues(sv, "dataSetName")
-svCol <- columnValues(sv, "column")
-svType <- columnValues(sv, "type")
svN <- columnValues(sv, "n")
-expected <- list(
- "JASPColumn_11_0.scale" = c(src = "A", id = "11", name = "DataSetA", column = "Score", type = "scale"),
- "JASPColumn_11_2.nominal" = c(src = "A", id = "11", name = "DataSetA", column = "Group", type = "nominal"),
- "JASPColumn_12_0.scale" = c(src = "B", id = "12", name = "DataSetB", column = "Score", type = "scale"),
- "JASPColumn_12_1.scale" = c(src = "B", id = "12", name = "DataSetB", column = "Age", type = "scale"))
-check(all(names(expected) %in% svVar), "all four dependents present in the routing table")
-for (v in names(expected)) if (v %in% svVar) {
+svValues <- columnValues(sv, "values")
+check(all(c(encA[["Score"]], encA[["Group"]], encB[["Score"]], encB[["Age"]]) %in% svVar),
+ "all four encoded dependents present in the routing table")
+for (v in c(encA[["Score"]], encA[["Group"]], encB[["Score"]], encB[["Age"]])) if (v %in% svVar) {
i <- which(svVar == v)[1]
- check(svSrc[i] == expected[[v]]["src"] && svId[i] == expected[[v]]["id"] && svName[i] == expected[[v]]["name"] &&
- svCol[i] == expected[[v]]["column"] && svType[i] == expected[[v]]["type"],
- paste0("routing [form ", expected[[v]]["src"], "] ", v, " -> ", expected[[v]]["name"], "/", expected[[v]]["column"]))
+ expId <- if (v %in% encA) "11" else "12"
+ expNm <- if (v %in% encA) "DataSetA" else "DataSetB"
+ check(svId[i] == expId && svName[i] == expNm && svN[i] == "10" && nzchar(svValues[i]),
+ paste0("routing ", v, " -> ", expNm, ", 10 rows, values computed (", svValues[i], ")"))
}
-check(all(svN == "10"), "all four columns read 10 rows")
+
+# numeric stats must correspond to the right slice: A/Score mean vs csv
+iScoreA <- which(svVar == encA[["Score"]])[1]
+check(grepl(sprintf("mean %.2f", mean(csvA$Score)), svValues[[iScoreA]], fixed = TRUE),
+ "form A mean matches DataSetA's Score column")
+iScoreB <- which(svVar == encB[["Score"]])[1]
+check(grepl(sprintf("mean %.2f", mean(csvB$Score)), svValues[[iScoreB]], fixed = TRUE),
+ "form B mean matches DataSetB's Score column (no cross-slice mixup)")
raw1 <- jsonlite::toJSON(res1, auto_unbox = TRUE)
check(grepl("not available in multi-dataset aware analyses", raw1, fixed = TRUE),
"guard demo: readDataSet() hard-stopped during the aware run")
# ------------------------------------------------------------------ Path 2: wrapper call -------
-# The wrapper path is run in a clean Rscript subprocess (no jaspTools runtime in the way),
-# which is exactly the RStudio/syntax-mode scenario the wrapper is made for.
-cat("\n== Path 2: wrapper (datasets= named list, plain column names; clean subprocess) ==\n")
-path2Script <- file.path(moduledir, "Tools", "testMultiDataSet_wrapper.R")
-status2 <- system2("Rscript", c(shQuote(path2Script)), stdout = TRUE, stderr = FALSE)
-writeLines(status2)
-check(any(grepl("MULTIDATASET-WRAPPER-OK", status2, fixed = TRUE)), "wrapper subprocess succeeded")
+# The syntax-mode wrapper flow (loadQmlAndParseOptions) still encodes option values against the
+# bridge's single dataset view while the handed-over list keeps plain names: the dataset-selection
+# design (TODO-multidataset.md items 1-5: selection options + multi-dataset workspace + shared
+# per-dataset encode/queue) replaces this path. Tools/testMultiDataSet_wrapper.R stays ready to
+# assert the new semantics once that lands.
+cat("\n== Path 2: wrapper (datasets= named list) ==\n")
+cat("SKIP : wrapper path awaits the syntax-mode dataset-selection flow (TODO-multidataset.md #1-#5)\n")
# ------------------------------------------------------------------ Path 3: legacy still OK ----
cat("\n== Path 3: legacy non-aware run (no datasets) ==\n")
res3 <- jaspTools::runAnalysis("multiDataSetFunc", dataset = datasets[["11"]],
- options = list(dependentA = c("Score"), dependentB = c("Age"), showMeta = FALSE,
- guardDemo = TRUE, plotWidth = 400, plotHeight = 300),
+ options = list(dependentA = encA[c("Score")], dependentB = encA[c("Age")],
+ showMeta = FALSE, guardDemo = TRUE, plotWidth = 400, plotHeight = 300),
view = FALSE, quiet = TRUE)
raw3 <- jsonlite::toJSON(res3, auto_unbox = TRUE)
check(identical(res3$status, "complete"), "legacy run completed")
diff --git a/Tools/testMultiDataSet_wrapper.R b/Tools/testMultiDataSet_wrapper.R
index 6454b51..fb7f4ff 100644
--- a/Tools/testMultiDataSet_wrapper.R
+++ b/Tools/testMultiDataSet_wrapper.R
@@ -2,6 +2,10 @@
# Wrapper-path check of the multi-dataset analysis: no jaspTools, no JASP - just
# jaspTestModule::multiDataSetFunc(datasets = , ...) like an R user would call it.
# Run by Tools/testMultiDataSet.R, but standalone-runnable too.
+#
+# Also reports (via the raw `variable` cells) whether the syntax-mode option parsing encoded
+# the values or left them plain - the module indexes whatever arrives directly, so both
+# namespaces must line up with the handed-over dataframes for the n/values cells to fill.
moduledir <- normalizePath(file.path(dirname(sub("^--file=", "", grep("^--file=", commandArgs(FALSE), value = TRUE)[[1]])), ".."))
pkglib <- Sys.getenv("JASP_TEST_PKGLIB", file.path(moduledir, "ModuleBundleBuildDir", "build_dir", "jaspTestModule"))
@@ -42,11 +46,13 @@ check(identical(columnValues(j$dataSetOverview, "id"), c("11", "12")), "wrapper
check(identical(columnValues(j$dataSetOverview, "title"), c("DataSetA", "DataSetB")), "wrapper overview lists both titles")
sv <- j$selectedVariables
-svCol <- columnValues(sv, "column")
+svVar <- columnValues(sv, "variable")
svN <- columnValues(sv, "n")
svValues <- columnValues(sv, "values")
-check(any(svCol == "Score") && any(svCol == "Condition"), "Score and Condition resolved to original column names")
-check(all(svN == "10"), "both columns computed over 10 rows (scan-all found Condition in DataSetB)")
+cat("info : raw option values seen by the analysis:", paste(svVar, collapse = ", "), "\n")
+
+check(all(c("Score", "Age", "Condition") %in% basename(svVar)), "all three dependents reached the table")
+check(all(svN == "10"), "all columns computed over 10 rows (direct indexing found each one)")
check(any(grepl("mean", svValues, fixed = TRUE)), "numeric stats computed for Score")
cat(if (ok) "MULTIDATASET-WRAPPER-OK\n" else "MULTIDATASET-WRAPPER-FAILED\n")
From 5b983c9c22e1452ce4193c837d061a2f8b197c2c Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Wed, 7 Oct 2026 23:52:14 +0200
Subject: [PATCH 09/44] demo the syntax-mode dataset selection; twin gets its
own form
- testMultiDataSet.qml: dataSetSelectionOption 'dataSetA'/'dataSetB' + depends, so a
syntax call selects each form's dataset by name (multiDataSetFunc(datasets =
list(haha = dfA, godverdomme = dfB), dataSetA = 'haha', dataSetB = 'godverdomme',
dependentA = 'Score', ...) routes every column to its own dataset).
- non-aware twin now has testMultiDataSetNonAware.qml (no selection options - a
non-aware entry neither has nor needs them, and the bridge would demand them).
- wrapper test asserts the new semantics end-to-end (bridge ids + user-name titles,
encoded slices + encoded options, per-form routing of identically named columns);
path 2 re-enabled in the suite (29 checks green).
- buildBundle jaspBase check: markers match the current exports (dataSetColumnFromEncoded
is gone) and actually print the missing names (bare %in% has no names).
- TODO-multidataset.md tracks the remaining work.
---
R/multiDataSetFuncWrapper.R | 4 +-
R/multiDataSetNonAwareWrapper.R | 4 +-
TODO-multidataset.md | 126 +++++++++++---------------
Tools/buildBundle.R | 8 +-
Tools/testMultiDataSet.R | 16 ++--
Tools/testMultiDataSet_wrapper.R | 75 ++++++++++-----
inst/Description.qml | 10 +-
inst/qml/testMultiDataSet.qml | 6 ++
inst/qml/testMultiDataSetNonAware.qml | 63 +++++++++++++
9 files changed, 201 insertions(+), 111 deletions(-)
create mode 100644 inst/qml/testMultiDataSetNonAware.qml
diff --git a/R/multiDataSetFuncWrapper.R b/R/multiDataSetFuncWrapper.R
index 790c0ab..69bf3ac 100644
--- a/R/multiDataSetFuncWrapper.R
+++ b/R/multiDataSetFuncWrapper.R
@@ -22,6 +22,8 @@
multiDataSetFunc <- function(
datasets = NULL,
version = "1",
+ dataSetA = list(types = "unknown", value = ""),
+ dataSetB = list(types = "unknown", value = ""),
dependentA = list(types = list(), value = list()),
dependentB = list(types = list(), value = list()),
guardDemo = FALSE,
@@ -45,7 +47,7 @@ multiDataSetFunc <- function(
data <- if (!is.null(datasets) && length(datasets)) datasets[[1]] else NULL
- optionsWithFormula <- c("dependentA", "dependentB")
+ optionsWithFormula <- c("dataSetA", "dataSetB", "dependentA", "dependentB")
for (name in optionsWithFormula) {
if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
diff --git a/R/multiDataSetNonAwareWrapper.R b/R/multiDataSetNonAwareWrapper.R
index 9aba292..fe9000d 100644
--- a/R/multiDataSetNonAwareWrapper.R
+++ b/R/multiDataSetNonAwareWrapper.R
@@ -22,6 +22,8 @@
multiDataSetNonAware <- function(
data = NULL,
version = "1",
+ dataSetA = list(types = "unknown", value = ""),
+ dataSetB = list(types = "unknown", value = ""),
dependentA = list(types = list(), value = list()),
dependentB = list(types = list(), value = list()),
guardDemo = FALSE,
@@ -43,7 +45,7 @@ multiDataSetNonAware <- function(
jaspBase::storeDataSet(data)
}
- optionsWithFormula <- c("dependentA", "dependentB")
+ optionsWithFormula <- c("dataSetA", "dataSetB", "dependentA", "dependentB")
for (name in optionsWithFormula) {
if ((name %in% optionsWithFormula) && inherits(options[[name]], "formula")) options[[name]] = jaspBase::jaspFormula(options[[name]], data) }
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index 3f7a3e6..248430c 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -1,76 +1,60 @@
-# Multi-dataset aware feature — open work (2026-10-07)
+# Multi-dataset aware feature — open work (2026-10-07, post syntax-mode-selection)
-## Decided design (ground truth from user, this session)
-- Options and dataset slices live in the SAME encoded namespace everywhere (`JASPColumn___Encoded`);
- R indexes `datasets[[id]][[encodedValue]]` directly; results/plots are decoded on the way out (engine sendString).
-- `preloadData` is forced true for aware analyses (done at `Modules::AnalysisEntry::preloadData()` + EntryBase),
- and the engine checks `_analysisMultiDataSet` *before* the preload flag.
-- Syntax mode must encode like the engine (verified: it does for single-dataset). No scans, no decode-hacks.
-- Syntax-mode multi-dataset (user's design, TO BUILD):
- `datasets = list(haha = df1, godverdomme = df2)` loads each df into the bridge **Workspace/DataSet**
- (title = the user's name; names are user-convenience only). **The VariablesForms' dataset selections are
- specific options** that must not be empty (check!); the user fills e.g. `"haha"` there as soon as the data
- is loaded; selecting it switches the form's dataset context, QMLComponents then validate/encode the
- column-name options against that dataset (they know their sources, stamp `.meta` dataSetId), and the
- encoder (now existing via DataSet) encodes per datasetId. This cascades through the options.
+## Decided design (ground truth from user)
+- Options and dataset slices share the ENCODED namespace (`JASPColumn___Encoded`);
+ R indexes `datasets[[id]][[encodedValue]]` directly; results/plots are decoded on the way out
+ (engine sendString loops every encoder the analysis references).
+- `preloadData` forced true for aware analyses (Modules::AnalysisEntry + EntryBase getters);
+ the engine checks multiAware BEFORE the preload flag.
+- Syntax mode: `datasets = list(name = df, ...)` loads each df into the bridge Workspace/DataSet
+ (title = list name, real ids + encoders). Each VariablesForm has a dataset-selection OPTION
+ (dataSetSelectionOption names it; NO_DESKTOP_MODE-gated bound DropDown); the user fills the
+ dataset NAME there; JASPControl::_setInitialized re-applies the owning form's selection before
+ every child binds (order-proof), QML validates + stamps .meta, the bridge then encodes
+ per-dataset and queues slices via the SHARED DataBridge::prepareMultiDataSetRun (same code as
+ Engine::runAnalysis). Empty/missing selection options fail with a clear R error (bridge
+ pre-check; ComboBoxBase coerces "" to first entry). No filters in syntax mode (pre-filtered
+ data); default filter queued per slice. Names are user-convenience only (DataSet title).
## TODO
-1. [done: subagent design] Option-backed VariablesForm dataset selection for syntax mode. Agreed plan:
- - CommonData/workspace: `dataSetByTitle(QString)` exact-match lookup (mirror dataSetByName).
- - VariablesFormBase: `dataSetSelectionOption` Q_PROPERTY (option name for this form's dataset selection);
- setter also self-declares awareness (`analysisObj()->setMultiDataSetAware(true)` — bridge dummy analysis
- otherwise never gets it); `dataSetTitleValues()` (workspace titles); `selectDataSetByName(name)`:
- empty/unknown -> addControlError, match -> analysis->setFilterId(ds->defaultFilter()->id()) +
- Workspace::setShownDataSet(ds) (filterId semantics = default, syntax users pre-filter).
- - VariablesForm.qml: a second, BOUND DropDown (name: dataSetSelectionOption, values: titles) gated by
- NO_DESKTOP_MODE (typeof-guard) -> desktop stays 100% inert; wrapper generation picks the option up.
- AssignedVariablesList gets `depends: ""` so bindTo applies the selection FIRST
- (setInitialized defers; meta then stamps the right dataSetId via createMeta).
- - AnalysisForm: `dataSetSelectionOptionNames()` (findChildren).
- - syntaxbridge loadQmlAndParseOptionsStatus: PRE-CHECK raw options JSON for those names (empty check,
- because ComboBoxBase coerces "" to first entry); after parse + when analysisObj aware:
- mirror Engine::runAnalysis aware block -> encodeColumnNamesinOptionsPerDataSet + setMultiDataSetQueue
- + status["multiDataSetJson"] = {ids, names-by-title} (additive JSON key, no ABI change).
- - DataSetProvider::loadDataSet overload with title; SyntaxBridgeDataSet.name finally used
- (dataframeimporter sets it; loadDataSets R export validates: named list, unique non-empty names);
- provider tracks first-loaded id as primary. createDataSet's empty-reuse quirk handled.
- - jaspBase: storeDataSets -> jaspSyntax::loadDataSets; runWrappedAnalysis aware path uses
- loadQmlAndParseOptionsStatus + runJaspResults(multiDataSetJson=...) -> engine-parity queued slices
- (encoded names + real ids; the user's plain list is NOT handed over anymore on this path).
- jaspTools keeps using the direct datasets= handout branch.
-2. [impl] SyntaxInterface + jaspSyntax: multi-dataset named loading into bridge workspace (plan items above).
-3. [impl] Extract the Engine::runAnalysis aware encode/queue block to shared code (DataBridge method or
- similar) so engine + syntaxbridge use ONE implementation (no duplication!).
-4. [impl] jaspBase runWrappedAnalysis aware flow per plan (incl. empty-selection pre-check surfacing via
- Rcpp::stop channel).
-5. [test] Module wrapper test rewrite for the new flow: `dataSetA = "haha"` style options + `depends` in
- testMultiDataSet.qml; overview keyed by bridge ids with user names as titles; direct indexing.
- (Current path-2 FAIL is the known gap this closes; mark accordingly until done.)
-6. [fix] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the analysis'
- OWN dataset encoder only — aware analyses plotting other datasets stay encoded. Same multi-encoder
- treatment as `Engine::sendString` `_analysisDataSetEncoders`.
-7. [harden] `_analysisDataSetEncoders` stores raw `ColumnEncoder*` — dataset deleted mid-run dangles
- (only the CURRENT pointer is guarded in ~DataSet). Re-resolve by id (or QPointer-style) at send time.
-8. [verify] GUI end-to-end after rebuild: dropdown fills tables (aware + twin), guard demo, per-form dataset
- switching, saved-file reload of an aware analysis (provenance remap path `restoreProvenanceFromBoundValues`
- / `remapSavedProvenance` has no end-to-end test yet).
-9. [rebuild] Bundle via `Tools/buildBundle.R` (new jaspBase + module), user reinstalls in dev JASP.
-10. [commit] Everything across: jasp-desktop (incl. submodule bump), jaspBase branch multiDataSetAware,
- jaspTools branch multiDataSetAware, jaspTestModule.
-11. [note] Side effects to document/verify once syntax flow lands: readRequestedDataset() after an aware
- parse consumes queue slices; syntax-mode result decoding (columnEncoderContext) per dataset.
+1. [fix] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the
+ analysis' OWN dataset encoder only — aware analyses plotting other datasets stay encoded.
+ Same multi-encoder treatment as `Engine::sendString` `_analysisDataSetEncoders`.
+2. [harden] `_analysisDataSetEncoders` stores raw `ColumnEncoder*` — dataset deleted mid-run
+ dangles (only the CURRENT pointer is guarded in ~DataSet). Re-resolve by id at send time.
+3. [verify] GUI end-to-end after bundle rebuild: dropdown fills tables (aware + twin), guard
+ demo, per-form dataset switching in the GUI, and saved-file reload of an aware analysis
+ (`restoreProvenanceFromBoundValues` / `remapSavedProvenance` still lack an end-to-end test).
+4. [rebuild] Bundle via `Tools/buildBundle.R` (new jaspBase + module + qmls); user reinstalls.
+5. [note] Syntax-mode side effects to watch: readRequestedDataset() after an aware parse consumes
+ queue slices; jaspSyntax result decoding (columnEncoderContext) is per current dataset —
+ multi-dataset result decoding in pure syntax output may need the same multi-encoder care.
+6. [ops] jaspSyntax installs MUST pass `JASPSYNTAX_LIB_PATH=`
+ (configure otherwise downloads release binaries needing mysql/pq/icu74, absent here);
+ after each SyntaxInterface rebuild copy the .so to BOTH `jaspSyntax/src/` and
+ `.toolLib/jaspSyntax/libs/`.
-## Done this session (committed unless noted)
-- jasp-desktop `515c1f241`: dropdown visibility fixes (syncMultiDataSetAwareness push instead of computed
- getter; EntryBase multiDataSetAwareChanged→somethingChanged; VariablesFormBase::setUp bootstrap — static
- controls never get formIsKnown!) + render probe (93 QuickTest incl. probe).
-- UNCOMMITTED (working tree, all tests green): real-format `_Encoded` regex (C++ mirror later removed per
- user), removed `.decodeColNamesForDataSet` callback chain (jasprcpp/interface/rbridge/jaspTools stub),
- preloadData forced for aware (EntryBase + AnalysisEntry), engine checks multiAware before preload +
- primaryDataSetId fallback (fresh unfiltered analyses sent dataSetId -1 → empty slice queue = the
- "empty cells" root cause), encode-per-dataset always collects cols for aware, testall encode→decode→
- encode→decode cycle test on real encoders, rlogic bridge round-trip via jaspSyntax (real encoder output,
- index-directly invariant proven through the bridge), jaspBase helpers rewritten to encoded-namespace
- direct indexing (dataSetColumnFromEncoded + dataSetEncodedNames snapshot deleted), module rewritten for
- direct indexing, module test path-1 faithful (encoded slice names) green.
+## Done (this session)
+- jasp-desktop `515c1f241` (dropdown visibility: syncMultiDataSetAwareness push, EntryBase notify,
+ VariablesFormBase::setUp bootstrap — static controls never get formIsKnown — + render probe).
+- jasp-desktop `a8cd23e5d` dead dataset-aware decode plumbing removed (C++ dataSetIdFromEncoded
+ mirror, .decodeColNamesForDataSet callback chain), encode->decode->encode cycle test on real
+ encoders (pins the `_Encoded` format).
+- jasp-desktop `b87a8bbbe` empty-cells fix (primaryDataSetId for unfiltered analyses; aware
+ checked before preload; cols always collected; rlogic bridge round-trip through jaspSyntax
+ proving the index-directly invariant against real encoder output) + submodule bumps.
+- jaspBase `edc73fe` helpers operate in the encoded namespace (dataSetColumnFromEncoded +
+ dataSetEncodedNames snapshot deleted; real `_Encoded` parsing; direct indexing; faithful fixtures).
+- jaspTools `0d621f3` dead stub + maps removed.
+- jaspTestModule `6f6cec1` demo indexes directly; path-1 fixtures carry real encoded names.
+- UNCOMMITTED (all suites green: JASPTest 109, QuickTest 93, rlogic incl bridge, jaspBase 46,
+ module 29 incl wrapper): syntax-mode dataset selection across jasp-desktop (workspace
+ dataSetByTitle, DataSetProvider titled loads + firstLoadedDataSetId + named loads skip reset,
+ VariablesFormBase dataSetSelectionOption/dataSetTitleValues/selectDataSetByName/
+ applyDataSetSelection, JASPControl _setInitialized apply-hook, AnalysisForm
+ dataSetSelectionOptionNames, syntaxbridge pre-check + aware prepare branch + shared
+ DataBridge::prepareMultiDataSetRun extraction), jaspSyntax (loadDataSets,
+ loadQmlAndParseOptionsStatus, importer name), jaspBase (storeDataSets -> loadDataSets,
+ runWrappedAnalysis aware flow with string parts), jaspTestModule (selection options + depends
+ in testMultiDataSet.qml, twin's own qml, wrapper test rewritten, buildBundle check fixed).
- Known NOT-a-bug: jaspTools doesn't encode (longstanding, user-confirmed, out of scope).
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index 9e07d2d..e55f9b2 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -196,10 +196,12 @@ archive::archive_extract(file.path(checkdir, jaspBaseHash), dir = pkgdir)
suppressPackageStartupMessages(library(jaspBase, lib.loc = file.path(checkdir, "lib")))
if (localJaspBase) {
- markers <- c("dataSetColumnFromEncoded", "dataSetIdFromEncoded", "getDataSetColumn", "storeDataSets") %in% getNamespaceExports("jaspBase")
- runBody <- any(grepl("multiDataSet|dataSetEncodedNames", deparse(body(jaspBase::runJaspResults))))
+ expected <- c("dataSetIdFromEncoded", "dataSetNameFromEncoded", "getDataSetFor",
+ "getDataSetColumn", "storeDataSets")
+ markers <- stats::setNames(expected %in% getNamespaceExports("jaspBase"), expected)
+ runBody <- any(grepl("multiDataSet", deparse(body(jaspBase::runJaspResults))))
if (!all(markers) || !runBody)
- stop("bundled jaspBase is MISSING the local multiDataSetAware code (exports: ",
+ stop("bundled jaspBase is MISSING the local multiDataSetAware code (missing exports: ",
paste(names(markers)[!markers], collapse = ", "), if (runBody) "" else " + runJaspResults body", ")")
message("VERIFIED: bundled jaspBase loads and carries the local multiDataSetAware code.")
} else {
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index deaed33..b71b020 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -117,13 +117,15 @@ check(grepl("not available in multi-dataset aware analyses", raw1, fixed = TRUE)
"guard demo: readDataSet() hard-stopped during the aware run")
# ------------------------------------------------------------------ Path 2: wrapper call -------
-# The syntax-mode wrapper flow (loadQmlAndParseOptions) still encodes option values against the
-# bridge's single dataset view while the handed-over list keeps plain names: the dataset-selection
-# design (TODO-multidataset.md items 1-5: selection options + multi-dataset workspace + shared
-# per-dataset encode/queue) replaces this path. Tools/testMultiDataSet_wrapper.R stays ready to
-# assert the new semantics once that lands.
-cat("\n== Path 2: wrapper (datasets= named list) ==\n")
-cat("SKIP : wrapper path awaits the syntax-mode dataset-selection flow (TODO-multidataset.md #1-#5)\n")
+# The wrapper path is run in a clean Rscript subprocess (no jaspTools runtime in the way):
+# datasets= loads into the bridge workspace, the dataSetA/dataSetB options select each form's
+# dataset, the bridge encodes per dataset and queues slices - engine parity via the shared
+# DataBridge preparation. Exactly the RStudio/syntax-mode scenario the wrapper is made for.
+cat("\n== Path 2: wrapper (datasets= named list + dataset selection options) ==\n")
+path2Script <- file.path(moduledir, "Tools", "testMultiDataSet_wrapper.R")
+status2 <- system2("Rscript", c(shQuote(path2Script)), stdout = TRUE, stderr = FALSE)
+writeLines(status2)
+check(any(grepl("MULTIDATASET-WRAPPER-OK", status2, fixed = TRUE)), "wrapper subprocess succeeded")
# ------------------------------------------------------------------ Path 3: legacy still OK ----
cat("\n== Path 3: legacy non-aware run (no datasets) ==\n")
diff --git a/Tools/testMultiDataSet_wrapper.R b/Tools/testMultiDataSet_wrapper.R
index fb7f4ff..e730abe 100644
--- a/Tools/testMultiDataSet_wrapper.R
+++ b/Tools/testMultiDataSet_wrapper.R
@@ -1,11 +1,13 @@
#!/usr/bin/env Rscript
# Wrapper-path check of the multi-dataset analysis: no jaspTools, no JASP - just
-# jaspTestModule::multiDataSetFunc(datasets = , ...) like an R user would call it.
+# jaspTestModule::multiDataSetFunc(datasets = , ...) like an R user would call it,
+# with the dataset-selection options naming which dataset each variables-form uses.
# Run by Tools/testMultiDataSet.R, but standalone-runnable too.
#
-# Also reports (via the raw `variable` cells) whether the syntax-mode option parsing encoded
-# the values or left them plain - the module indexes whatever arrives directly, so both
-# namespaces must line up with the handed-over dataframes for the n/values cells to fill.
+# Flow under test: loadDataSets -> workspace (titles, ids, encoders) -> QML binds the selection
+# options first (depends), switching each form; column options then encode per dataset and the
+# bridge queues one slice per dataset; runJaspResults hands the analysis encoded options +
+# encoded slices keyed by (bridge) dataset id, with the user names as titles.
moduledir <- normalizePath(file.path(dirname(sub("^--file=", "", grep("^--file=", commandArgs(FALSE), value = TRUE)[[1]])), ".."))
pkglib <- Sys.getenv("JASP_TEST_PKGLIB", file.path(moduledir, "ModuleBundleBuildDir", "build_dir", "jaspTestModule"))
@@ -16,23 +18,23 @@ Sys.setenv(QT_QPA_PLATFORM = "offscreen")
suppressMessages(library(jaspTestModule))
-datasets <- list(
- "11" = read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")),
- "12" = read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")))
-attr(datasets, "dataSetNames") <- c("11" = "DataSetA", "12" = "DataSetB")
+csvA <- read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")) # Score, Age, Group
+csvB <- read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")) # Score, Age, Condition
-res <- jaspTestModule::multiDataSetFunc(datasets = datasets,
- dependentA = "Score", # in both datasets -> routes to the primary
- dependentB = c("Age", "Condition")) # Condition only exists in DataSetB
+res <- jaspTestModule::multiDataSetFunc(
+ datasets = list(haha = csvA, godverdomme = csvB),
+ dataSetA = "haha",
+ dataSetB = "godverdomme",
+ dependentA = "Score", # Score exists in both: form A picked haha
+ dependentB = c("Age", "Condition")) # Condition only in godverdomme
raw <- as.character(res$.__enclos_env__$private$getResults())
j <- jsonlite::fromJSON(raw, simplifyVector = FALSE)$results
-# jaspTable json is transposed: data[[j]] = column j (schema order), cells keyed by row id
columnValues <- function(tb, fieldName) {
idx <- which(vapply(tb$schema$fields, function(f) identical(f$name, fieldName), logical(1)))[1]
d <- tb$data[[idx]]
rowKeys <- names(d)[vapply(d, length, integer(1)) > 0L]
- vapply(d[rowKeys], function(v) as.character(v), character(1), USE.NAMES = FALSE)
+ stats::setNames(vapply(d[rowKeys], function(v) paste(as.character(v), collapse = ", "), character(1), USE.NAMES = FALSE), rowKeys)
}
ok <- TRUE
@@ -41,19 +43,44 @@ check <- function(cond, label) {
if (!isTRUE(cond)) ok <<- FALSE
}
-check(grepl("Aware run", raw, fixed = TRUE), "analysis ran in aware mode (datasets= arrived)")
-check(identical(columnValues(j$dataSetOverview, "id"), c("11", "12")), "wrapper overview lists both dataset ids")
-check(identical(columnValues(j$dataSetOverview, "title"), c("DataSetA", "DataSetB")), "wrapper overview lists both titles")
+check(grepl("Aware run", raw, fixed = TRUE), "analysis ran in aware mode")
-sv <- j$selectedVariables
-svVar <- columnValues(sv, "variable")
-svN <- columnValues(sv, "n")
-svValues <- columnValues(sv, "values")
-cat("info : raw option values seen by the analysis:", paste(svVar, collapse = ", "), "\n")
+ovTitle <- unname(columnValues(j$dataSetOverview, "title"))
+ovId <- unname(columnValues(j$dataSetOverview, "id"))
+ovNames <- unname(columnValues(j$dataSetOverview, "columnNames"))
+check(setequal(ovTitle, c("haha", "godverdomme")), "both datasets handed over, user names as titles")
+check(length(ovId) == 2L && all(grepl("^[0-9]+$", ovId)), "datasets keyed by (bridge) numeric dataset ids")
+check(all(grepl("JASPColumn_", ovNames)), "slices arrive with encoded column names")
-check(all(c("Score", "Age", "Condition") %in% basename(svVar)), "all three dependents reached the table")
-check(all(svN == "10"), "all columns computed over 10 rows (direct indexing found each one)")
-check(any(grepl("mean", svValues, fixed = TRUE)), "numeric stats computed for Score")
+# the bridge dataset ids behind each title, so routing can be asserted exactly
+idByTitle <- stats::setNames(ovId, ovTitle)
+
+sv <- j$selectedVariables
+svSrc <- columnValues(sv, "source")
+svVar <- columnValues(sv, "variable")
+svId <- columnValues(sv, "dataSetId")
+svN <- columnValues(sv, "n")
+svValues <- columnValues(sv, "values")
+
+check(all(grepl("^JASPColumn_[0-9]+_[0-9]+_Encoded$", svVar)),
+ "option values arrive in the encoded namespace (not the plain user names)")
+
+rowFor <- function(src, dsTitle) {
+ which(svSrc == src & svId == idByTitle[[dsTitle]])
+}
+
+iA <- rowFor("A", "haha"); iB1 <- rowFor("B", "godverdomme")
+check(length(iA) == 1L && length(iB1) == 2L, "three rows routed: A->haha once, B->godverdomme twice")
+check(all(svN == "10"), "every column computed over 10 rows (encoded names indexed directly)")
+check(grepl(sprintf("mean %.2f", mean(csvA$Score)), svValues[[iA]], fixed = TRUE),
+ "form A Score = haha's Score (per-form dataset selection)")
+# integer columns arrive from the syntax bridge as ordinal -> the demo shows first levels, not mean;
+# the level list itself proves it is GODVERDOMME'S Age (31/45/28... would be haha's)
+ageLevelsB <- paste(utils::head(unique(as.character(csvB$Age)), 5), collapse = ", ")
+check(any(grepl(ageLevelsB, svValues[iB1], fixed = TRUE)),
+ "form B Age = godverdomme's Age (identically named column, different dataset)")
+check(any(grepl("X, Y, Z", svValues[iB1], fixed = TRUE)),
+ "form B Condition found in godverdomme (only exists there)")
cat(if (ok) "MULTIDATASET-WRAPPER-OK\n" else "MULTIDATASET-WRAPPER-FAILED\n")
quit(status = if (ok) 0L else 1L)
diff --git a/inst/Description.qml b/inst/Description.qml
index 9e031de..eebcdec 100644
--- a/inst/Description.qml
+++ b/inst/Description.qml
@@ -95,13 +95,15 @@ Description
hasWrapper: true
}
- // Same form, but NOT aware and NOT wrapped: data must arrive the old way (dataset/readDataSet)
- // and the dataset selection must stay inert. Own func name because with hasWrappers the engine
- // appends "Internal" to every entry's func (and the wrapper name may not *be* an Internal).
+ // Same forms, but NOT aware: data must arrive the old way (dataset/readDataSet) and the dataset
+ // selection must stay inert. Own func name because with hasWrappers the engine appends
+ // "Internal" to every entry's func (and the wrapper name may not *be* an Internal). Own qml too:
+ // the aware form's datasetSelectionOptions would (rightly) demand selections in syntax mode,
+ // which a non-aware analysis neither has nor needs.
Analysis
{
title: "Test Multi-DataSet (non-aware counterpart)"
- qml: "testMultiDataSet.qml"
+ qml: "testMultiDataSetNonAware.qml"
func: "multiDataSetNonAware"
requiresData: true
preloadData: true
diff --git a/inst/qml/testMultiDataSet.qml b/inst/qml/testMultiDataSet.qml
index 01cd24a..6a52ec0 100644
--- a/inst/qml/testMultiDataSet.qml
+++ b/inst/qml/testMultiDataSet.qml
@@ -32,12 +32,16 @@ Form
VariablesForm
{
dataSetSelection: true
+ //syntax mode: an option carrying the dataset name to select for this form
+ //(jaspSyntax gates the bound dropdown on it; desktop never sees it)
+ dataSetSelectionOption: "dataSetA"
AvailableVariablesList { name: "allVariablesA" }
AssignedVariablesList
{
name: "dependentA"
title: qsTr("Variables A")
+ depends: "dataSetA" //bind the dataset selection first, then the columns
}
}
}
@@ -48,12 +52,14 @@ Form
VariablesForm
{
dataSetSelection: true
+ dataSetSelectionOption: "dataSetB"
AvailableVariablesList { name: "allVariablesB" }
AssignedVariablesList
{
name: "dependentB"
title: qsTr("Variables B")
+ depends: "dataSetB"
}
}
}
diff --git a/inst/qml/testMultiDataSetNonAware.qml b/inst/qml/testMultiDataSetNonAware.qml
new file mode 100644
index 0000000..2f9a9b6
--- /dev/null
+++ b/inst/qml/testMultiDataSetNonAware.qml
@@ -0,0 +1,63 @@
+import QtQuick
+import JASP.Controls
+import "./common"
+
+// Twin of testMultiDataSet.qml for the NON-aware entry (multiDataSetNonAware): same forms and
+// checkboxes, but no dataSetSelectionOption - a non-aware analysis has exactly one (shown)
+// dataset, in the GUI as well as in syntax mode. The dataSetSelection: true stays to demo that
+// the dropdown remains inert when the analysis is not multiDataSetAware.
+Form
+{
+ columns: 1
+
+ ExplanationText
+ {
+ text:
+ "Non-aware twin: identical form, but the analysis entry lacks multiDataSetAware, so " +
+ "the Data selections stay inert and data comes in through the classic dataset/readDataSet path."
+ }
+
+ Section {
+ title: qsTr("Form A - variables from one dataset")
+
+ VariablesForm
+ {
+ dataSetSelection: true
+
+ AvailableVariablesList { name: "allVariablesA" }
+ AssignedVariablesList
+ {
+ name: "dependentA"
+ title: qsTr("Variables A")
+ }
+ }
+ }
+
+ Section {
+ title: qsTr("Form B - variables from another dataset")
+
+ VariablesForm
+ {
+ dataSetSelection: true
+
+ AvailableVariablesList { name: "allVariablesB" }
+ AssignedVariablesList
+ {
+ name: "dependentB"
+ title: qsTr("Variables B")
+ }
+ }
+ }
+
+ CheckBox
+ {
+ name: "showMeta"
+ label: qsTr("Show options .meta (dataSetId/filterId provenance)")
+ }
+
+ CheckBox
+ {
+ name: "guardDemo"
+ label: qsTr("Call readDataSet() anyway (should not error: non-aware run)")
+ }
+}
From 2bc37b87eef9f9ee04993518bfde8ce426bcdc0b Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 00:00:50 +0200
Subject: [PATCH 10/44] buildBundle QML gate: parse forms in-process with a
dummy dataset selection
The aware form's dataSetSelectionOptions now (rightly) demand a loaded dataset to name,
which broke the smoke check. The gate loads a one-column dummy via loadDataSets and
parses with isolated = FALSE (the subprocess would not see it), pointing every detected
dataSetSelectionOption at it; the non-aware twin is checked without selections.
---
Tools/buildBundle.R | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index e55f9b2..0deda97 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -163,10 +163,28 @@ if (requireNamespace("jaspSyntax", quietly = TRUE)) {
suppressPackageStartupMessages(library(jaspSyntax))
desc <- readModuleDescription(moduledir)
stopifnot(!is.null(desc))
- for (analysisFunc in c("multiDataSetFunc")) {
- opts <- readDefaultAnalysisOptions(moduledir, analysisFunc)
- stopifnot(is.list(opts), !is.null(attr(opts, "qmlFile")))
- message(" ", analysisFunc, " -> ", basename(attr(opts, "qmlFile")), " loads OK")
+ for (check in list(
+ list(func = "multiDataSetFunc", qml = "testMultiDataSet.qml", aware = TRUE),
+ list(func = "multiDataSetNonAware", qml = "testMultiDataSetNonAware.qml", aware = FALSE))) {
+ qmlFile <- file.path(moduledir, "inst", "qml", check$qml)
+ stopifnot(file.exists(qmlFile))
+ parseOptions <- NULL
+ if (check$aware) {
+ # The aware forms declare dataSetSelectionOptions; the bridge (rightly) demands every one
+ # of them names a loaded dataset - give the smoke check one dummy to point them all at.
+ jaspSyntax::loadDataSets(list(bundleCheck = data.frame(ok = 1)))
+ hits <- Filter(function(h) length(h) == 2L,
+ regmatches(readLines(qmlFile, warn = FALSE),
+ regexec('dataSetSelectionOption[[:space:]]*:[[:space:]]*"([^"]+)"',
+ readLines(qmlFile, warn = FALSE))))
+ sels <- vapply(hits, function(h) h[[2]], character(1))
+ stopifnot(length(sels) > 0L)
+ parseOptions <- stats::setNames(as.list(rep("bundleCheck", length(sels))), sels)
+ }
+ parsed <- jaspSyntax::parseQmlOptions(qmlFile, options = parseOptions, moduleName = "jaspTestModule",
+ analysisName = check$func, isolated = FALSE)
+ stopifnot(!is.null(parsed))
+ message(" ", check$func, " -> ", check$qml, " loads OK")
}
} else {
message("NOTE: jaspSyntax not installed (see github.com/jasp-stats/jaspSyntax) - QML not checked.")
From 08cc56ad6eae7c13d3a4e35b4d641731028cb38c Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 00:09:40 +0200
Subject: [PATCH 11/44] TODO: mark plot decode + encoder-id hardening done
(jasp-desktop d8ed73558, 0bf83f920)
---
TODO-multidataset.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index 248430c..6da8f14 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -17,10 +17,10 @@
data); default filter queued per slice. Names are user-convenience only (DataSet title).
## TODO
-1. [fix] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the
+1. [DONE jasp-desktop d8ed73558] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the
analysis' OWN dataset encoder only — aware analyses plotting other datasets stay encoded.
Same multi-encoder treatment as `Engine::sendString` `_analysisDataSetEncoders`.
-2. [harden] `_analysisDataSetEncoders` stores raw `ColumnEncoder*` — dataset deleted mid-run
+2. [DONE jasp-desktop 0bf83f920] `_analysisDataSetEncoders` stored raw `ColumnEncoder*` — dataset deleted mid-run
dangles (only the CURRENT pointer is guarded in ~DataSet). Re-resolve by id at send time.
3. [verify] GUI end-to-end after bundle rebuild: dropdown fills tables (aware + twin), guard
demo, per-form dataset switching in the GUI, and saved-file reload of an aware analysis
@@ -47,8 +47,8 @@
dataSetEncodedNames snapshot deleted; real `_Encoded` parsing; direct indexing; faithful fixtures).
- jaspTools `0d621f3` dead stub + maps removed.
- jaspTestModule `6f6cec1` demo indexes directly; path-1 fixtures carry real encoded names.
-- UNCOMMITTED (all suites green: JASPTest 109, QuickTest 93, rlogic incl bridge, jaspBase 46,
- module 29 incl wrapper): syntax-mode dataset selection across jasp-desktop (workspace
+- COMMITTED `2bc37b8`+jasp-desktop `3e09b7b31` etc. (all suites green: JASPTest 109, QuickTest 93, rlogic incl bridge, jaspBase 46,
+X dataset selection across jasp-desktop (workspace
dataSetByTitle, DataSetProvider titled loads + firstLoadedDataSetId + named loads skip reset,
VariablesFormBase dataSetSelectionOption/dataSetTitleValues/selectDataSetByName/
applyDataSetSelection, JASPControl _setInitialized apply-hook, AnalysisForm
From 631a92be5f32e4c97939a7b26f521ffab28485bb Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 01:58:56 +0200
Subject: [PATCH 12/44] buildBundle installs the result into the local dev JASP
automatically
No more manual 'Add module -> From file' per iteration: the build ends with
Tools/installModuleLocal.sh (JASP's own jaspModuleBundleManager install +
manifest version normalisation + developerMode/modulesRemembered prefs).
--no-install-local / SKIP_MODULE_LOCAL_INSTALL=1 to opt out; failure is a
warning (bundle itself is fine, usually JASP still running).
TODO records the parseModuleInfo-vs-array-version bug worth reporting upstream.
---
TODO-multidataset.md | 13 +++-
Tools/buildBundle.R | 18 ++++-
Tools/installModuleLocal.sh | 144 ++++++++++++++++++++++++++++++++++++
3 files changed, 172 insertions(+), 3 deletions(-)
create mode 100755 Tools/installModuleLocal.sh
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index 6da8f14..8940977 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -25,8 +25,17 @@
3. [verify] GUI end-to-end after bundle rebuild: dropdown fills tables (aware + twin), guard
demo, per-form dataset switching in the GUI, and saved-file reload of an aware analysis
(`restoreProvenanceFromBoundValues` / `remapSavedProvenance` still lack an end-to-end test).
-4. [rebuild] Bundle via `Tools/buildBundle.R` (new jaspBase + module + qmls); user reinstalls.
-5. [note] Syntax-mode side effects to watch: readRequestedDataset() after an aware parse consumes
+4. [DONE] Bundle + local install: `Tools/buildBundle.R` now ends by installing the bundle into
+ the local dev JASP automatically (Tools/installModuleLocal.sh: jaspModuleBundleManager
+ install + manifest version normalization + developerMode/modulesRemembered prefs).
+ Skip with `--no-install-local` / SKIP_MODULE_LOCAL_INSTALL=1; JASP must not be running.
+5. [upstream] JASP bug candidate: bundle tooling writes manifest `"version":[[0,96,2]]` but
+ `InstalledModules::parseModuleInfo` (installedmodules.cpp:28) throws on arrays via
+ `version.isMember("Version")` → "Could not parse module manifest" → module silently skipped
+ at every restart after a perfectly fine GUI install. Fix belongs in jasp-desktop
+ (accept arrays) and/or jaspModuleBundleManager (write strings). installModuleLocal.sh
+ works around it by rewriting the manifest field.
+6. [note] Syntax-mode side effects to watch: readRequestedDataset() after an aware parse consumes
queue slices; jaspSyntax result decoding (columnEncoderContext) is per current dataset —
multi-dataset result decoding in pure syntax output may need the same multi-encoder care.
6. [ops] jaspSyntax installs MUST pass `JASPSYNTAX_LIB_PATH=`
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index 0deda97..dae512a 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -227,4 +227,20 @@ if (localJaspBase) {
}
message("Bundle: ", bundle, " (size: ", format(file.size(bundle) / 2^20, digits = 1), " MiB)")
-message("Install in JASP: + menu -> Add module -> From file, pick that .JASPModule.")
+
+# ---------------------------------------------------------------------------------------------
+# Install into the local developer JASP so the module is simply THERE after every build
+# (same result as "Add module -> From file", through JASP's own installer - see
+# Tools/installModuleLocal.sh for the mechanism). Skipped with --check-only,
+# --no-install-local or SKIP_MODULE_LOCAL_INSTALL=1; a failure here is a warning only:
+# the bundle itself is fine (most often JASP is still running).
+if (!("--check-only" %in% args) && !("--no-install-local" %in% args) && !nzchar(Sys.getenv("SKIP_MODULE_LOCAL_INSTALL"))) {
+ installer <- file.path(moduledir, "Tools", "installModuleLocal.sh")
+ status <- system2(installer, shQuote(bundle))
+ if (identical(as.integer(status), 0L))
+ message("installed into the local JASP (module_libs + manifest + dev prefs) - restart ./build/Desktop/JASP to pick it up.")
+ else
+ warning("bundle built OK, but the local install failed (is JASP running?) - run Tools/installModuleLocal.sh manually.")
+} else {
+ message("Install in JASP: + menu -> Add module -> From file, pick that .JASPModule (or run Tools/installModuleLocal.sh).")
+}
diff --git a/Tools/installModuleLocal.sh b/Tools/installModuleLocal.sh
new file mode 100755
index 0000000..8f99115
--- /dev/null
+++ b/Tools/installModuleLocal.sh
@@ -0,0 +1,144 @@
+#!/usr/bin/env bash
+# installModuleLocal.sh - (re)install the built jaspTestModule bundle into JASP's
+# user module library WITHOUT the GUI "Add module -> From file" click.
+#
+# What it does (all via JASP's own mechanism, see references below):
+# 1. Runs jaspModuleBundleManager::installJaspModuleBundle(installPath, bundlePath) -
+# exactly the R call JASP's "Add module -> From file" makes
+# (jasp-desktop/Desktop/modules/dynamicmodules.cpp:310-345, getJsonForBundleInstallRequest).
+# It untars the bundle's L0 package archives into
+# ~/.local/share/JASP/JASP/Modules/binary_pkgs//, writes
+# Modules/manifests/jaspTestModule_manifest.json and creates the module's private
+# R library Modules/module_libs/jaspTestModule/ -> ../../binary_pkgs/.
+# On reinstall it first uninstalls the previous version (removes only binary_pkgs
+# not referenced by any remaining manifest).
+# 2. Rewrites the installed manifest's "version" field to a plain string ("0.96.2").
+# Reason: JASP scans Modules/manifests/jasp*.json at startup to (re)load installed
+# modules (Desktop/modules/installedmodules.cpp, getAllAvailableModules -> parseModuleInfo).
+# parseModuleInfo() calls version.isMember("Version") which, with the jsoncpp in this
+# build, THROWS on the array format [[0,96,2]] that the bundle tooling emits
+# ("Could not parse module manifest ... requires objectValue or nullValue") ->
+# the module is silently skipped on every restart. The string format is one of the
+# formats parseModuleInfo explicitly supports (root["version"].isString() branch).
+# 3. Makes sure the two JASP preferences needed for a *dev* module are set
+# (Qt QSettings INI at ~/.config/JASP/JASP.conf - there is no preferences.json):
+# developerMode=true - without it getModules() erases jaspTestModule
+# (installedmodules.cpp:86-87)
+# modulesRemembered=...jaspTestModule... - modulesRemember defaults to true, so a
+# remembered module is enabled (ribbon button shown)
+# at startup (ribbonmodel.cpp, loadModules()).
+#
+# Usage:
+# Tools/installModuleLocal.sh [path-to-bundle] [--verify]
+# bundle default: /bundles_out/jaspTestModule.JASPModule
+# --verify afterwards run the dev JASP headless (offscreen) and grep the log
+# for proof that the module loads at startup.
+# Env overrides: JASP_MODULES_DIR, JASP_CONF, JASP_MODULE_TOOLLIB, JASP_DESKTOP_DIR, JASP_BIN
+#
+# After this script, every "jasp-desktop/build/Desktop/JASP" start shows jaspTestModule;
+# rerun it after each rebuild of the bundle. JASP must not be running.
+set -euo pipefail
+
+MODULE_NAME=jaspTestModule
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+MODULE_DIR="$(dirname "$SCRIPT_DIR")"
+ROOT_DIR="$(dirname "$MODULE_DIR")"
+
+BUNDLE="$MODULE_DIR/bundles_out/$MODULE_NAME.JASPModule"
+VERIFY=0
+for a in "$@"; do
+ case "$a" in
+ --verify) VERIFY=1 ;;
+ *) BUNDLE="$a" ;;
+ esac
+done
+
+MODULES_DIR="${JASP_MODULES_DIR:-$HOME/.local/share/JASP/JASP/Modules}"
+CONF="${JASP_CONF:-$HOME/.config/JASP/JASP.conf}"
+JASP_BIN="${JASP_BIN:-${JASP_DESKTOP_DIR:-$ROOT_DIR/jasp-desktop}/build/Desktop/JASP}"
+
+[ -f "$BUNDLE" ] || { echo "ERROR: bundle not found: $BUNDLE (build it with Tools/buildBundle.R)" >&2; exit 1; }
+command -v Rscript >/dev/null || { echo "ERROR: Rscript not on PATH" >&2; exit 1; }
+if pgrep -f "build/Desktop/JASP( |$)" >/dev/null 2>&1; then
+ echo "ERROR: JASP appears to be running; quit it first (install replaces module_libs/manifests)." >&2; exit 1
+fi
+
+# --- find a library containing jaspModuleBundleManager (+ fs/rjson/stringr/archive) --------
+find_tool_lib() {
+ local c
+ for c in "${JASP_MODULE_TOOLLIB:-}" \
+ "$ROOT_DIR/jasp-desktop/build/Modules/Tools/jaspModuleBundleManager_library" \
+ "$ROOT_DIR/.toolLib"; do
+ [ -n "$c" ] && [ -d "$c/jaspModuleBundleManager" ] && [ -d "$c/archive" ] && { echo "$c"; return; }
+ done
+ return 1
+}
+TOOL_LIB="$(find_tool_lib)" || { echo "ERROR: no R library with jaspModuleBundleManager found (set JASP_MODULE_TOOLLIB)" >&2; exit 1; }
+echo "==> tool lib : $TOOL_LIB"
+echo "==> bundle : $BUNDLE"
+echo "==> install : $MODULES_DIR"
+
+# --- 1. install the bundle exactly like the GUI does ---------------------------------------
+Rscript --vanilla -e "
+ .libPaths(c('$TOOL_LIB', .libPaths()))
+ p <- jaspModuleBundleManager::installJaspModuleBundle(
+ installPath = '$MODULES_DIR',
+ bundlePath = '$BUNDLE')
+ cat('installed module lib:', as.character(p), '\n')
+"
+
+# --- 2. normalize manifest version to the string format JASP's startup parser accepts ------
+MANIFEST="$MODULES_DIR/manifests/${MODULE_NAME}_manifest.json"
+[ -f "$MANIFEST" ] || { echo "ERROR: expected manifest not written: $MANIFEST" >&2; exit 1; }
+Rscript --vanilla -e "
+ .libPaths(c('$TOOL_LIB', .libPaths()))
+ m <- rjson::fromJSON(file = '$MANIFEST')
+ if (!is.character(m\$version)) {
+ v <- unlist(m\$version)
+ m\$version <- paste(v, collapse = '.')
+ writeLines(rjson::toJSON(m, indent = 1), '$MANIFEST')
+ cat('manifest version normalized ->', m\$version, '\n')
+ } else cat('manifest version already a string:', m\$version, '\n')
+"
+
+# --- 3. preferences (Qt QSettings INI): developerMode + remembered/enabled module ----------
+if [ -f "$CONF" ]; then
+ cp -f "$CONF" "$CONF.bak-lastinstall"
+else
+ mkdir -p "$(dirname "$CONF")"; printf '[General]\n' > "$CONF"
+fi
+awk -v mod="$MODULE_NAME" '
+ BEGIN { dev=0; rem=0; remHas=0; out="" }
+ /^[[:space:]]*developerMode[[:space:]]*=/ { dev=1; sub(/=.*/,"=true"); print; next }
+ /^[[:space:]]*modulesRemembered[[:space:]]*=/ {
+ rem=1
+ if ($0 ~ ("(^|\\|)[[:space:]]*" mod "([[:space:]]*\\||[[:space:]]*$)")) { print; remHas=1; next }
+ sub(/[[:space:]]*$/, "")
+ if ($0 ~ /=$/) print $0 mod; else print $0 "|" mod
+ next
+ }
+ { print }
+ END {
+ if (!dev) print "developerMode=true"
+ if (!rem) print "modulesRemembered=" mod
+ }
+' "$CONF" > "$CONF.tmp" && mv "$CONF.tmp" "$CONF"
+echo "==> prefs : $CONF (developerMode=true, modulesRemembered includes $MODULE_NAME)"
+
+echo "==> installed tree:"
+ls -ld "$MODULES_DIR/module_libs/$MODULE_NAME" >/dev/null && \
+ echo " $MODULES_DIR/module_libs/$MODULE_NAME ($(ls "$MODULES_DIR/module_libs/$MODULE_NAME" | wc -l) pkgs)"
+grep -o '"version": *"[^"]*"' "$MANIFEST" | sed 's/^/ manifest /'
+
+# --- 4. optional offscreen verification -----------------------------------------------------
+if [ "$VERIFY" = 1 ]; then
+ [ -x "$JASP_BIN" ] || { echo "ERROR: JASP binary not found: $JASP_BIN (set JASP_BIN)" >&2; exit 1; }
+ LOG=/tmp/opencode/jasp_load.log; mkdir -p /tmp/opencode
+ echo "==> starting $JASP_BIN (offscreen, 25s) -> $LOG"
+ timeout 25 env QT_QPA_PLATFORM=offscreen "$JASP_BIN" --newData >"$LOG" 2>&1 || true
+ echo "==> proof:"
+ grep -in "could not parse module manifest" "$LOG" && { echo "FAIL: manifest still rejected"; exit 1; }
+ grep -in "jaspTestModule" "$LOG" | head -5
+ grep -in "Modules::EntryBase\|RibbonButton.*is ready" "$LOG" | head -3
+ echo "==> OK: no manifest parse error and $MODULE_NAME activity present in $LOG"
+fi
From 2f66030fdbbe641234d44cf8779ed8989f33f4b0 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 03:24:12 +0200
Subject: [PATCH 13/44] Crash 2026-10-08: root cause + fix + scripted RPC
repro/verify
SEGV opening the multi-dataset test form was a null entry in _depends: the form's
depends: "dataSetA"/"dataSetB" cannot resolve on desktop (the syntax-mode DropDown is
unnamed there) and JASPControl::_addExplicitDependency inserted the null, which
AnalysisForm::sortControls dereferenced. Fixed in jasp-desktop 785afe486.
Tools/verifyMultiDataSetRpc.py drives the whole flow over JASP's RPC server
(load both CSVs, create form, mixed-provenance runs, assert routed results).
---
TODO-multidataset.md | 34 ++++++
Tools/verifyMultiDataSetRpc.py | 183 +++++++++++++++++++++++++++++++++
2 files changed, 217 insertions(+)
create mode 100644 Tools/verifyMultiDataSetRpc.py
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index 8940977..ed61137 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -67,3 +67,37 @@ X dataset selection across jasp-desktop (workspace
runWrappedAnalysis aware flow with string parts), jaspTestModule (selection options + depends
in testMultiDataSet.qml, twin's own qml, wrapper test rewritten, buildBundle check fixed).
- Known NOT-a-bug: jaspTools doesn't encode (longstanding, user-confirmed, out of scope).
+
+## Crash 2026-10-08
+SEGV opening Test Multi-DataSet on desktop with two CSVs loaded: log ended at
+`AnalysisForm::setAnalysisUp() for 0x...` and JASP died.
+
+**Root cause** (jasp-desktop): `testMultiDataSet.qml` carries `depends: "dataSetA"` /
+`depends: "dataSetB"` on the AssignedVariablesLists (bind the syntax-mode dataset-selection
+option before the lists, 3e09b7b31/5b983c9). On desktop that option's bound DropDown is
+deliberately unnamed (`name: syntaxMode ? variablesForm.dataSetSelectionOption : ""`) so it is
+never registered in `AnalysisForm::_controls`; `JASPControl::_addExplicitDependency` resolved
+the name to `nullptr` and inserted it into `_depends` unconditionally. `AnalysisForm::sortControls`
+then dereferenced it (`depend->depends()` at this=0x20). Backtrace: setAnalysisUp -> _setUpControls
+-> _setUp -> sortControls -> std::set::begin(this=0x20).
+
+**Fix** jasp-desktop `785afe486`: _addExplicitDependency only inserts resolved, non-self controls
+(an unresolvable `depends` name imposes no binding order; desktop stays 100% functional, the
+syntax-mode DropDown stays inert there); sortControls skips nulls defensively. No module changes.
+
+**Repro + verify recipe (scripted, no GUI):**
+1. `rpcServerEnabled=true` in ~/.config/JASP/JASP.conf; nothing else running.
+2. `cd /build && QT_QPA_PLATFORM=offscreen gdb -batch -ex run -ex bt --args ./Desktop/JASP > /tmp/jasp_run.log 2>&1 &`
+3. `python3 Tools/verifyMultiDataSetRpc.py` — loads DataSetA+DataSetB via RPC (two datasets in
+ one workspace), creates the analysis (this is where the pre-fix build SEGVs), binds
+ dependentA=Score@ds1 and dependentB=Score+Condition@ds2 (Score exists in both; mixed
+ provenance via analysis_setFilter + the unchanged-value early return in
+ BoundControlBase::setBoundValue), runs and asserts the results: 'Datasets in this run' has
+ both datasets (titles, 10 rows each), 'Selected variables' routes each value to its own
+ dataset with n=10 and mean/levels (A:Score mean 12.50 -> DataSet 1, B:Score mean 17.73 +
+ B:Condition X,Y,Z -> DataSet 2), all decoded (no JASPColumn_* left).
+Pre-fix the script dies at analysis_create with the backtrace above; post-fix ALL CHECKS PASSED.
+Suites green with the fix: JASPTest 109 PASS, JASPQuickTest 93 PASS.
+Note: RPC `analysis_create` cannot carry options, and per-control drops are not exposed; the
+script works around that with setFilter-then-run (unchanged values keep their .meta), so no
+new RPC surface was needed.
diff --git a/Tools/verifyMultiDataSetRpc.py b/Tools/verifyMultiDataSetRpc.py
new file mode 100644
index 0000000..034e89c
--- /dev/null
+++ b/Tools/verifyMultiDataSetRpc.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+"""Verify jaspTestModule::multiDataSetFunc end-to-end through JASP's RPC server.
+
+Precondition: JASP (dev build) already running offscreen with RPC enabled, NO datasets.
+Steps: load DataSetA + DataSetB (2 datasets in the workspace), create the multi-dataset
+test analysis, bind dependentA to a column of dataset 1 and dependentB to a column that
+exists in BOTH datasets plus one that exists only in dataset 2, run, fetch results and
+assert:
+ - 'Datasets in this run' has 2 rows with titles + row/col counts
+ - 'Selected variables' rows have n=10 and mean/levels values (not empty, not JASPColumn_*)
+Exit 0 = all good, 1 = failure (details printed).
+
+Run recipe (scripted crash-repro + verify loop):
+ 1. ~/.config/JASP/JASP.conf has rpcServerEnabled=true (and no JASP running).
+ 2. cd /build && QT_QPA_PLATFORM=offscreen ./Desktop/JASP
+ (under gdb to capture a backtrace if it dies:
+ gdb -batch -ex run -ex bt --args ./Desktop/JASP > /tmp/jasp_run.log 2>&1 &)
+ 3. python3 Tools/verifyMultiDataSetRpc.py
+Before the jasp-desktop fix 785afe486 this died at analysis_create: the SEGV is
+reproduced when JASP exits mid-script, backtrace in the gdb log.
+"""
+
+# ----------------------------------------------------------------------------
+# Minimal JSON-RPC 2.0 client for JASP's RPC server (enabled by the preference
+# rpcServerEnabled=true in ~/.config/JASP/JASP.conf; listens on port 48164,
+# path /rpc by default).
+# ----------------------------------------------------------------------------
+import json as _json, time as _time, urllib.request as _urllib
+
+URL = "http://127.0.0.1:48164/rpc"
+_id = 0
+
+def _rpc(method, params=None, timeout=60):
+ global _id
+ _id += 1
+ body = _json.dumps({"jsonrpc": "2.0", "id": _id, "method": method,
+ "params": params or {}}).encode()
+ req = _urllib.Request(URL, data=body, headers={"Content-Type": "application/json"})
+ with _urllib.urlopen(req, timeout=timeout) as r:
+ return _json.loads(r.read().decode())
+
+def wait_up(max_wait=120):
+ start = _time.time()
+ while _time.time() - start < max_wait:
+ try:
+ r = _rpc("ping", timeout=2)
+ if "result" in r:
+ return r
+ except Exception:
+ _time.sleep(0.5)
+ raise RuntimeError("RPC server did not come up")
+
+call = _rpc
+
+import sys, json, time
+
+A_CSV = "/home/virtuoos/Broncode/JASP/jaspTestModule/Tools/testdata/DataSetA.csv"
+B_CSV = "/home/virtuoos/Broncode/JASP/jaspTestModule/Tools/testdata/DataSetB.csv"
+
+fails = []
+def check(name, cond, extra=""):
+ print(("PASS " if cond else "FAIL ") + name + (f" {extra}" if extra else ""))
+ if not cond:
+ fails.append(name)
+
+def call(method, params=None, timeout=90):
+ r = _rpc(method, params, timeout=timeout)
+ if "error" in r:
+ print(f"RPC error on {method}: {json.dumps(r['error'])[:600]}")
+ return r.get("result", r)
+
+wait_up(120)
+print("== RPC up ==")
+
+da = call("data_load", {"path": A_CSV, "wait": True, "timeoutMs": 60000})
+db = call("data_load", {"path": B_CSV, "wait": True, "timeoutMs": 60000})
+check("two datasets loaded (ids 1 and 2)", da.get("dataSetId") == 1 and db.get("dataSetId") == 2,
+ f"ids {da.get('dataSetId')}, {db.get('dataSetId')}")
+i1 = call("data_info", {"dataSetId": 1})
+check("dataset 1 has Group (only in A)", any(c["name"] == "Group" for c in i1.get("columns", [])))
+
+an = call("analysis_create", {"module": "jaspTestModule", "analysis": "multiDataSetFunc"})
+check("form created without SEGV, analysis multiDataSetAware", an.get("status") == "success" and an.get("multiDataSetAware") is True)
+aid = an.get("analysisId")
+
+# bind form A's variable while the analysis runs on dataset 1 (filter 1)
+print(call("analysis_setFilter", {"analysisId": aid, "filterId": 1}).get("status"))
+r1 = call("analysis_run", {"analysisId": aid, "wait": True, "timeoutMs": 60000, "options": {
+ "dependentA": {"types": [], "value": ["Score"]}}})
+check("first run (dependentA=Score @dataset1) complete", r1.get("status") == "complete",
+ str(r1.get("status")))
+
+# switch to dataset 2 and add form B's variables: dependentA is unchanged so its ds1
+# provenance survives the rebind (BoundControlBase::setBoundValue early-returns)
+print(call("analysis_setFilter", {"analysisId": aid, "filterId": 2}).get("status"))
+r2 = call("analysis_run", {"analysisId": aid, "wait": True, "timeoutMs": 120000, "options": {
+ "dependentA": {"types": [], "value": ["Score"]},
+ "dependentB": {"types": [], "value": ["Score", "Condition"]},
+ "showMeta": True}})
+check("second run complete", r2.get("status") == "complete", str(r2.get("status")))
+
+# poll for completion
+for _ in range(30):
+ st = call("get_analyses_state", {"analysisIds": [aid], "include_options": True, "include_results": False})
+ a = (st.get("analyses") or [{}])[0]
+ if a.get("status") in ("complete", "empty", "noData", "running"):
+ if a.get("status") != "running":
+ break
+ time.sleep(1)
+check("analysis status complete", a.get("status") == "complete", f"status={a.get('status')} errors={str(a.get('errors'))[:300]}")
+
+res = call("analysis_results", {"analysisId": aid, "wait": True, "timeoutMs": 60000})
+open("results_multidataset.json", "w").write(json.dumps(res, indent=1))
+import shutil, os
+rds = res.get("jaspResultsRds")
+if rds and os.path.exists(rds):
+ shutil.copy(rds, "jaspResults_copied.rds")
+results = res.get("results", res)
+
+def tables(node, path=""):
+ out = {}
+ if isinstance(node, dict):
+ if "schema" in node and "data" in node:
+ out[path] = node
+ for k, v in node.items():
+ out.update(tables(v, f"{path}/{k}"))
+ elif isinstance(node, list):
+ for i, v in enumerate(node):
+ out.update(tables(v, f"{path}[{i}]"))
+ return out
+
+tabs = tables(results)
+print("tables found:", [(k, t.get("title")) for k, t in tabs.items()][:20])
+
+def field_maps(t):
+ """jaspBase json: data[i] is a {rowKey: value} map for schema field i."""
+ fields = [f["name"] for f in t["schema"]["fields"]]
+ rowkeys = set()
+ for entry in t["data"]:
+ for key, val in entry.items():
+ if val is not None and key not in fields:
+ rowkeys.add(key)
+ return fields, {f: t["data"][i] for i, f in enumerate(fields)}, sorted(rowkeys)
+
+ds = next((t for t in tabs.values() if t.get("title") == "Datasets in this run"), None)
+check("'Datasets in this run' table present", ds is not None)
+if ds:
+ fields, fm, rks = field_maps(ds)
+ dump = json.dumps([fm[f].get(r) for r in rks for f in fields])
+ check("2 dataset rows", len(rks) == 2, str(rks))
+ titles = sorted(str(fm["title"].get(r)) for r in rks)
+ check("both dataset titles present (non-empty)", len(titles) == 2 and all(t not in ("None", "") for t in titles), str(titles))
+ check("row counts 10/10", all(fm["rows"].get(r) == 10 for r in rks), str([fm["rows"].get(r) for r in rks]))
+ check("col counts present", all(isinstance(fm["cols"].get(r), int) for r in rks), str([fm["cols"].get(r) for r in rks]))
+ check("no raw JASPColumn_* in overview", "JASPColumn" not in dump, dump[:300])
+ print("Datasets-in-this-run rows:", json.dumps([{f: fm[f].get(r) for f in fields} for r in rks]))
+
+sv = next((t for t in tabs.values() if t.get("title") == "Selected variables"), None)
+check("'Selected variables' table present", sv is not None)
+if sv:
+ fields, fm, rks = field_maps(sv)
+ dump = json.dumps({r: {f: fm[f].get(r) for f in fields} for r in rks})
+ rows = [{f: fm[f].get(r) for f in fields} for r in rks]
+ def row(src, var): return next((x for x in rows if x["source"] == src and x["variable"] == var), None)
+ check("3 selected-variable rows (A:Score, B:Score, B:Condition)", len(rows) == 3, dump[:500])
+ a_score = row("A", "Score")
+ b_score = row("B", "Score")
+ b_cond = row("B", "Condition")
+ check("A:Score routed to dataset 1", a_score and a_score["dataSetId"] in (1, "1") and a_score["dataSetName"] == "DataSet 1", json.dumps(a_score))
+ check("B:Score (name in BOTH datasets) routed to dataset 2", b_score and b_score["dataSetId"] in (2, "2") and b_score["dataSetName"] == "DataSet 2", json.dumps(b_score))
+ check("B:Condition (only in dataset 2) routed there", b_cond and b_cond["dataSetId"] in (2, "2"), json.dumps(b_cond))
+ check("n=10 on every row", all(r["n"] == 10 for r in rows), str([r["n"] for r in rows]))
+ print("Selected variables rows:")
+ for r in rows: print(" ", json.dumps(r))
+ check("scale rows show mean, factor row shows levels",
+ a_score and str(a_score["values"]).startswith("mean") and b_cond and str(b_cond["values"]) == "X, Y, Z",
+ f"{a_score['values'] if a_score else None!r} / {b_cond['values'] if b_cond else None!r}")
+ check("decoded names, no raw JASPColumn_*", "JASPColumn" not in dump, dump[:300])
+
+check("analysis references both datasets (dataSetIds in run response)", sorted(r2.get("dataSetIds", [])) == [1, 2], str(r2.get("dataSetIds")))
+
+print("\n" + ("ALL CHECKS PASSED" if not fails else f"{len(fails)} FAILURES: {fails}"))
+sys.exit(0 if not fails else 1)
From 92d3795470042ced7b638f0a7f47fd61ba0921a0 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 11:36:40 +0200
Subject: [PATCH 14/44] TODO: pointer to the per-host FilterSelect refactor
plan (linked-dropdown fix)
---
TODO-multidataset.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index ed61137..32bed4b 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -16,6 +16,12 @@
pre-check; ComboBoxBase coerces "" to first entry). No filters in syntax mode (pre-filtered
data); default filter queued per slice. Names are user-convenience only (DataSet title).
+## ACTIVE PLAN
+The per-host FilterSelect refactor (independent per-form selection, filter-id options,
+VariableInfo provider chain) is planned in full at:
+`/home/virtuoos/.opencode/plan/multidataset-filterselect.md` — READ IT, red-tests-first.
+It replaces the linked-dropdown design (both dropdowns mirrored analysis->filterId = the bug).
+
## TODO
1. [DONE jasp-desktop d8ed73558] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the
analysis' OWN dataset encoder only — aware analyses plotting other datasets stay encoded.
From c2d59ebbb9fbb527622be422e2461ab55c05a647 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 13:39:47 +0200
Subject: [PATCH 15/44] module: route selected variables through the FORM'S OWN
selection slice (filter id), qmls drop the removed dataSetSelection bool
---
R/multiDataSet.R | 53 ++++++++++++++++++++-------
inst/qml/testMultiDataSet.qml | 2 -
inst/qml/testMultiDataSetNonAware.qml | 4 +-
3 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index 80f9888..9544799 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -1,7 +1,10 @@
# Multi-dataset aware analyses (jasp-desktop branch dataSetAwareVarForm, jaspBase branch
# multiDataSetAware). An analysis whose Description/Analysis entry sets multiDataSetAware gets
-# every dataset it references as `datasets`: a named list keyed by dataset id, with the user
-# facing titles in attr(datasets, "dataSetNames"). Options and data share the ENCODED namespace:
+# every dataset it references as `datasets`: a named list keyed by SLICE id - the resolved
+# filter id of each queued (dataset, filter) pair - with the user facing titles in
+# attr(datasets, "dataSetNames") and each slice's dataset id in attr(datasets, "dataSetIds").
+# A per-form selection option indexes its own slice directly: datasets[[as.character(
+# as.integer(options$dataSetA))]]. jaspTools handouts stay keyed by dataset id. Options and data share the ENCODED namespace:
# variable options carry names like "JASPColumn___Encoded" and the dataframes'
# column names are the very same strings (encoded by each dataset's own ColumnEncoder, whose
# prefix embeds the dataset id), so an analysis indexes with the option value as-is:
@@ -69,24 +72,30 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
table$addColumnInfo("n", title = "n")
table$addColumnInfo("values", title = "mean (scale) / first levels (factor)")
- for (entry in list(list(form = "A", values = .dependentValues(options$dependentA)),
- list(form = "B", values = .dependentValues(options$dependentB)))) {
+ for (entry in list(list(form = "A", sel = "dataSetA", values = .dependentValues(options$dependentA)),
+ list(form = "B", sel = "dataSetB", values = .dependentValues(options$dependentB)))) {
+
+ # The form's own selection (a filter id) indexes its slice directly - that is the whole point
+ # of per-form selection: two forms can run on two filters of the same dataset.
+ selKey <- .selectionKey(options, datasets, entry$sel)
+ selSlice <- if (!is.null(selKey)) datasets[[selKey]] else NULL
+
for (value in entry$values) {
# value indexes the data as-is in both modes: options and column names share the encoded
- # namespace (or are both plain, in a jaspTools run). Only the routing to one dataset out
- # of `datasets` is aware-specific; the non-aware run has exactly the one dataset anyway.
- columnData <- if (is.null(datasets)) {
- if (!is.null(dataset) && value %in% names(dataset)) dataset[[value]] else NULL
- } else {
- jaspBase::getDataSetColumn(value, datasets)
- }
+ # namespace (or are both plain, in a jaspTools run). Routing prefers the form's own
+ # selection slice, falling back to the dataset embedded in the name (handout runs carry no
+ # filter-keyed slices); the non-aware run has exactly the one dataset anyway.
+ slice <- if (is.null(datasets)) dataset else if (!is.null(selSlice)) selSlice else jaspBase::getDataSetFor(value, datasets)
+ columnData <- if (!is.null(slice) && value %in% names(slice)) slice[[value]] else NULL
id <- if (is.null(datasets)) NA_integer_ else jaspBase::dataSetIdFromEncoded(value)
row <- list(
source = entry$form,
variable = value,
- dataSetId = if (is.null(datasets)) "-" else if (is.na(id)) "none (legacy)" else as.character(id),
- dataSetName = if (is.null(datasets)) "-" else jaspBase::dataSetNameFromEncoded(value, datasets),
+ dataSetId = if (!is.null(selKey)) as.character(attr(datasets, "dataSetIds")[[selKey]])
+ else if (is.null(datasets)) "-" else if (is.na(id)) "none (legacy)" else as.character(id),
+ dataSetName = if (!is.null(selKey)) as.character(attr(datasets, "dataSetNames")[[selKey]])
+ else if (is.null(datasets)) "-" else jaspBase::dataSetNameFromEncoded(value, datasets),
n = NA_integer_, values = "")
if (!is.null(columnData))
@@ -132,6 +141,24 @@ multiDataSetNonAwareInternal <- function(jaspResults, dataset, options) {
as.character(values[!is.na(values) & as.character(values) != ""])
}
+# The slice key (a filter id as string) behind a per-form dataset selection option. Options
+# arrive either plain ("42") or in the wrapper default shape list(types="unknown", value="");
+# "" / absent / not-a-listed-slice yields NULL (route by the dataset id embedded in the name).
+.selectionKey <- function(options, datasets, selOption) {
+ selVal <- utils::tail(unlist(options[[selOption]]), 1L)
+
+ if (is.null(selVal) || is.na(selVal))
+ return(NULL)
+
+ selVal <- trimws(as.character(selVal))
+ filterId <- suppressWarnings(as.integer(selVal))
+
+ if (is.na(filterId) || !selVal %in% names(datasets))
+ return(NULL)
+
+ selVal
+}
+
.fillDescription <- function(entry, columnData) {
if (is.numeric(columnData)) {
entry$n <- sum(!is.na(columnData))
diff --git a/inst/qml/testMultiDataSet.qml b/inst/qml/testMultiDataSet.qml
index 6a52ec0..892dce0 100644
--- a/inst/qml/testMultiDataSet.qml
+++ b/inst/qml/testMultiDataSet.qml
@@ -31,7 +31,6 @@ Form
VariablesForm
{
- dataSetSelection: true
//syntax mode: an option carrying the dataset name to select for this form
//(jaspSyntax gates the bound dropdown on it; desktop never sees it)
dataSetSelectionOption: "dataSetA"
@@ -51,7 +50,6 @@ Form
VariablesForm
{
- dataSetSelection: true
dataSetSelectionOption: "dataSetB"
AvailableVariablesList { name: "allVariablesB" }
diff --git a/inst/qml/testMultiDataSetNonAware.qml b/inst/qml/testMultiDataSetNonAware.qml
index 2f9a9b6..04875a9 100644
--- a/inst/qml/testMultiDataSetNonAware.qml
+++ b/inst/qml/testMultiDataSetNonAware.qml
@@ -4,7 +4,7 @@ import "./common"
// Twin of testMultiDataSet.qml for the NON-aware entry (multiDataSetNonAware): same forms and
// checkboxes, but no dataSetSelectionOption - a non-aware analysis has exactly one (shown)
-// dataset, in the GUI as well as in syntax mode. The dataSetSelection: true stays to demo that
+// dataset, in the GUI as well as in syntax mode. Without a selection option the forms show no
// the dropdown remains inert when the analysis is not multiDataSetAware.
Form
{
@@ -22,7 +22,6 @@ Form
VariablesForm
{
- dataSetSelection: true
AvailableVariablesList { name: "allVariablesA" }
AssignedVariablesList
@@ -38,7 +37,6 @@ Form
VariablesForm
{
- dataSetSelection: true
AvailableVariablesList { name: "allVariablesB" }
AssignedVariablesList
From 13a207ab97189fb135fa47eaa334be1cc54d7d65 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 14:21:45 +0200
Subject: [PATCH 16/44] RPC verifier drives the dropdown contract itself
(filter-id options, no setFilter); TODO rewritten for the FilterSelect
architecture + pre-existing testDbMigration failure noted
---
TODO-multidataset.md | 190 +++++++++++------------
Tools/verifyMultiDataSetRpc.py | 52 +++++--
results_multidataset.json | 266 +++++++++++++++++++++++++++++++++
3 files changed, 396 insertions(+), 112 deletions(-)
create mode 100644 results_multidataset.json
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index 32bed4b..b021823 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -1,109 +1,99 @@
-# Multi-dataset aware feature — open work (2026-10-07, post syntax-mode-selection)
+# Multi-dataset aware feature — status (2026-10-08, post FilterSelect refactor)
-## Decided design (ground truth from user)
+## Decided design (ground truth, v2 — supersedes the linked-dropdown v1)
- Options and dataset slices share the ENCODED namespace (`JASPColumn___Encoded`);
- R indexes `datasets[[id]][[encodedValue]]` directly; results/plots are decoded on the way out
- (engine sendString loops every encoder the analysis references).
-- `preloadData` forced true for aware analyses (Modules::AnalysisEntry + EntryBase getters);
- the engine checks multiAware BEFORE the preload flag.
-- Syntax mode: `datasets = list(name = df, ...)` loads each df into the bridge Workspace/DataSet
- (title = list name, real ids + encoders). Each VariablesForm has a dataset-selection OPTION
- (dataSetSelectionOption names it; NO_DESKTOP_MODE-gated bound DropDown); the user fills the
- dataset NAME there; JASPControl::_setInitialized re-applies the owning form's selection before
- every child binds (order-proof), QML validates + stamps .meta, the bridge then encodes
- per-dataset and queues slices via the SHARED DataBridge::prepareMultiDataSetRun (same code as
- Engine::runAnalysis). Empty/missing selection options fail with a clear R error (bridge
- pre-check; ComboBoxBase coerces "" to first entry). No filters in syntax mode (pre-filtered
- data); default filter queued per slice. Names are user-convenience only (DataSet title).
-
-## ACTIVE PLAN
-The per-host FilterSelect refactor (independent per-form selection, filter-id options,
-VariableInfo provider chain) is planned in full at:
-`/home/virtuoos/.opencode/plan/multidataset-filterselect.md` — READ IT, red-tests-first.
-It replaces the linked-dropdown design (both dropdowns mirrored analysis->filterId = the bug).
+ R indexes the slice's columns by option value directly; results/plots are decoded on the way
+ out (engine sendString loops every workspace encoder; plotly decode loops referenced datasets).
+- **Selection state is per-HOST, not per-analysis.** Any component consuming variable info for
+ itself declares `dataSetSelectionOption` (a `HostFilterSelection` member): VariablesFormBase
+ and TextAreaBase do so today. The option's value is a **FILTER ID** (a filter implies its
+ dataset; ids survive renames), written in BOTH modes by one reusable `FilterSelect.qml`
+ (a bound DropDown, `values:` = workspace filter list "DataSet - Filter", created behind
+ `Loader { active: selectionAvailable }` so an unnamed bound control can never exist).
+- **Provider chain follows the component chain:** each selecting host owns a `VariableInfo`
+ whose provider is the selected `Filter` (Filter *is* a VariableInfoProvider: per-dataset
+ columns/types/levels, rows filtered, `Filter::columnEncoder()` gives the dataset encoder).
+ `JASPControl::effectiveVarInfo()` / `effectiveSelectionFilter()` resolve nearest-selecting-host
+ (self included), else `AnalysisForm::varInfo()` (analysis filter / shownFilter — today's
+ behavior for everything non-aware). Non-JASPControl pieces (Formula) use the static
+ `JASPControl::varInfoForItem()`.
+- **Selection code never touches** `analysis->setFilterId` / `workspace->setShownDataSet` —
+ those belong to the analysis-GLOBAL FilterMenuButton (the true legacy widget, untouched).
+- `.meta` provenance is stamped with the filter the value was selected THROUGH (host's, else
+ analysis'), so per-form datasets survive save/restore and reach the engine per control.
+- **Slice queue keyed by filter id:** `prepareMultiDataSetRun` collects every distinct
+ (dataSetId, filterId) from `.meta`; one slice per pair (two forms on one dataset with
+ different filters → two differently-filtered dataframes). R-side `datasets` keys = resolved
+ filter id, `attr "dataSetIds"`/`"dataSetNames"` map back; a selection option indexes its own
+ slice directly: `datasets[[as.character(options$dataSetA)]]`. jaspTools handouts stay keyed by
+ dataset id; `.sliceKeyForDataSet` bridges both.
+- **Syntax deviation confined to the wrapper layer:** bridge translates a selection option that
+ names a loaded dataset ("haha") into that DataSet's default filter id before binding (unknown
+ names fail loudly with the list of loaded datasets; "" too). `datasets = list(haha = df, ...)`
+ stays the user-facing API (names become DataSet titles). Forms are mode-blind.
+- Single-dataset API on AnalysisBase **refuses** for aware analyses instead of silently answering
+ about one arbitrary dataset: `Analysis::dataSet()`, `isColumnFreeOrMine()`,
+ `isOwnComputedColumn()`, computed-column request handlers (log + safe default);
+ `usesDataSet()` consults `referencedDataSets()` when aware.
+- `preloadData` forced true for aware analyses; engine checks multiAware BEFORE preload.
+- Vanished filter/dataset while selected: selection falls back to the analysis/current filter
+ (same spirit as the analysis-global behavior), never dangles (HostFilterSelection validates on
+ dataSetRemoved/filtersCountChanged).
## TODO
-1. [DONE jasp-desktop d8ed73558] Desktop plot gap: `Analysis::loadPlotlyJsonInResults` decodes plotly JSON against the
- analysis' OWN dataset encoder only — aware analyses plotting other datasets stay encoded.
- Same multi-encoder treatment as `Engine::sendString` `_analysisDataSetEncoders`.
-2. [DONE jasp-desktop 0bf83f920] `_analysisDataSetEncoders` stored raw `ColumnEncoder*` — dataset deleted mid-run
- dangles (only the CURRENT pointer is guarded in ~DataSet). Re-resolve by id at send time.
-3. [verify] GUI end-to-end after bundle rebuild: dropdown fills tables (aware + twin), guard
- demo, per-form dataset switching in the GUI, and saved-file reload of an aware analysis
- (`restoreProvenanceFromBoundValues` / `remapSavedProvenance` still lack an end-to-end test).
-4. [DONE] Bundle + local install: `Tools/buildBundle.R` now ends by installing the bundle into
- the local dev JASP automatically (Tools/installModuleLocal.sh: jaspModuleBundleManager
- install + manifest version normalization + developerMode/modulesRemembered prefs).
- Skip with `--no-install-local` / SKIP_MODULE_LOCAL_INSTALL=1; JASP must not be running.
-5. [upstream] JASP bug candidate: bundle tooling writes manifest `"version":[[0,96,2]]` but
- `InstalledModules::parseModuleInfo` (installedmodules.cpp:28) throws on arrays via
- `version.isMember("Version")` → "Could not parse module manifest" → module silently skipped
- at every restart after a perfectly fine GUI install. Fix belongs in jasp-desktop
- (accept arrays) and/or jaspModuleBundleManager (write strings). installModuleLocal.sh
- works around it by rewriting the manifest field.
+1. [verify-manual] GUI smoke test (last resort, everything else is scripted): two CSVs, open
+ Test Multi-DataSet, flip BOTH "Data" dropdowns independently, watch tables stay filled and
+ unlinked; R/JAGS text areas with an option show their own dropdown.
+2. [open] Saved-file reload of an aware analysis end-to-end: per-form filter-id selections
+ restored through `bindTo` (+ `restoreProvenanceFromBoundValues`), vanished filter → fallback.
+ No automated test yet (needs RPC save/open or a crafted .jasp fixture).
+3. [open] Same-dataset-two-filters desktop GUI demo: the module analysis routes per form's
+ selection slice; a test data pair where BOTH forms use dataset 1 with different filters would
+ exercise the C8 two-slice path in the GUI (covered in rlogic unit, not e2e).
+4. [upstream] JASP bug candidate: bundle tooling writes manifest `"version":[[0,96,2]]` but
+ `InstalledModules::parseModuleInfo` throws on arrays → module silently skipped at restart.
+ installModuleLocal.sh works around it (rewrites to string).
+5. [KNOWN PRE-EXISTING FAILURE — user-confirmed, NOT from the FilterSelect refactor]
+ `ctest testDbMigration` aborts: "Trying to load ':memory:' but it doesn't exist!" — broken
+ since the earlier multi-dataset work (workspace/database lifecycle). Investigate separately.
6. [note] Syntax-mode side effects to watch: readRequestedDataset() after an aware parse consumes
- queue slices; jaspSyntax result decoding (columnEncoderContext) is per current dataset —
- multi-dataset result decoding in pure syntax output may need the same multi-encoder care.
-6. [ops] jaspSyntax installs MUST pass `JASPSYNTAX_LIB_PATH=`
- (configure otherwise downloads release binaries needing mysql/pq/icu74, absent here);
+ queue slices; jaspSyntax result decoding is per current dataset — multi-dataset result decoding
+ in pure syntax output may need the same multi-encoder care.
+7. [ops] jaspSyntax installs MUST pass `JASPSYNTAX_LIB_PATH=`;
after each SyntaxInterface rebuild copy the .so to BOTH `jaspSyntax/src/` and
`.toolLib/jaspSyntax/libs/`.
+8. [later] FormulaBase as host in its own right (its own FilterSelect + option): today a Formula
+ only follows the VariablesForm it lives in (varInfoForItem). Top-level Formulas keep the
+ analysis-wide fallback.
-## Done (this session)
-- jasp-desktop `515c1f241` (dropdown visibility: syncMultiDataSetAwareness push, EntryBase notify,
- VariablesFormBase::setUp bootstrap — static controls never get formIsKnown — + render probe).
-- jasp-desktop `a8cd23e5d` dead dataset-aware decode plumbing removed (C++ dataSetIdFromEncoded
- mirror, .decodeColNamesForDataSet callback chain), encode->decode->encode cycle test on real
- encoders (pins the `_Encoded` format).
-- jasp-desktop `b87a8bbbe` empty-cells fix (primaryDataSetId for unfiltered analyses; aware
- checked before preload; cols always collected; rlogic bridge round-trip through jaspSyntax
- proving the index-directly invariant against real encoder output) + submodule bumps.
-- jaspBase `edc73fe` helpers operate in the encoded namespace (dataSetColumnFromEncoded +
- dataSetEncodedNames snapshot deleted; real `_Encoded` parsing; direct indexing; faithful fixtures).
-- jaspTools `0d621f3` dead stub + maps removed.
-- jaspTestModule `6f6cec1` demo indexes directly; path-1 fixtures carry real encoded names.
-- COMMITTED `2bc37b8`+jasp-desktop `3e09b7b31` etc. (all suites green: JASPTest 109, QuickTest 93, rlogic incl bridge, jaspBase 46,
-X dataset selection across jasp-desktop (workspace
- dataSetByTitle, DataSetProvider titled loads + firstLoadedDataSetId + named loads skip reset,
- VariablesFormBase dataSetSelectionOption/dataSetTitleValues/selectDataSetByName/
- applyDataSetSelection, JASPControl _setInitialized apply-hook, AnalysisForm
- dataSetSelectionOptionNames, syntaxbridge pre-check + aware prepare branch + shared
- DataBridge::prepareMultiDataSetRun extraction), jaspSyntax (loadDataSets,
- loadQmlAndParseOptionsStatus, importer name), jaspBase (storeDataSets -> loadDataSets,
- runWrappedAnalysis aware flow with string parts), jaspTestModule (selection options + depends
- in testMultiDataSet.qml, twin's own qml, wrapper test rewritten, buildBundle check fixed).
-- Known NOT-a-bug: jaspTools doesn't encode (longstanding, user-confirmed, out of scope).
-
-## Crash 2026-10-08
-SEGV opening Test Multi-DataSet on desktop with two CSVs loaded: log ended at
-`AnalysisForm::setAnalysisUp() for 0x...` and JASP died.
-
-**Root cause** (jasp-desktop): `testMultiDataSet.qml` carries `depends: "dataSetA"` /
-`depends: "dataSetB"` on the AssignedVariablesLists (bind the syntax-mode dataset-selection
-option before the lists, 3e09b7b31/5b983c9). On desktop that option's bound DropDown is
-deliberately unnamed (`name: syntaxMode ? variablesForm.dataSetSelectionOption : ""`) so it is
-never registered in `AnalysisForm::_controls`; `JASPControl::_addExplicitDependency` resolved
-the name to `nullptr` and inserted it into `_depends` unconditionally. `AnalysisForm::sortControls`
-then dereferenced it (`depend->depends()` at this=0x20). Backtrace: setAnalysisUp -> _setUpControls
--> _setUp -> sortControls -> std::set::begin(this=0x20).
-
-**Fix** jasp-desktop `785afe486`: _addExplicitDependency only inserts resolved, non-self controls
-(an unresolvable `depends` name imposes no binding order; desktop stays 100% functional, the
-syntax-mode DropDown stays inert there); sortControls skips nulls defensively. No module changes.
+## Done (FilterSelect refactor, 2026-10-08) — plan file: /home/virtuoos/.opencode/plan/multidataset-filterselect.md
+- jasp-desktop `8636529f5` RED contract tests first (two forms two filters simultaneously,
+ bogus-id rejection, per-form list contents; fixture dataset "Second" w/ overlapping TestInts).
+- jasp-desktop `557f089d1` the core: HostFilterSelection (filter-id, per-host state, C10
+ validation), JASPControl::effectiveVarInfo/effectiveSelectionFilter + all consumers rerouted
+ (lists, SourceItem, textareas, custom contrasts, filteredDataEntry, R/JAGS textareas),
+ FilterSelect.qml, createMeta stamps host filter, Filter::columnEncoder, single-dataset guards,
+ usesDataSet-referencedDataSets; DELETED: dataSetSelection bool + both old dropdowns,
+ selectDataSetByName/applyDataSetSelection, _setInitialized re-apply hook, name-based
+ selection, analysis-filter mirroring.
+- jasp-desktop `3bbafd477` + jaspBase `69ec48c` filter-keyed slice queue (pair collector,
+ per-pair slices, `.sliceKeyForDataSet`, rlogic + unit tests for the contract).
+- jasp-desktop `e8a4db4e5` bridge name→default-filter-id translation (C7), errors list datasets.
+- jasp-desktop `46c4603c3` TextAreaBase host (FilterSelect in TextArea.qml, JAGS highlighter
+ follows host) + Formula follows its form's host.
+- module `c2d59eb` qmls use only dataSetSelectionOption (+depends, now resolvable in both modes);
+ R routes via the form's own selection slice with legacy fallback; wrapper regenerates.
+- module RPC verifier now drives the dropdown contract itself (options carry filter ids, NO
+ analysis_setFilter anywhere): independent simultaneous selections, A:Score mean 12.50 vs
+ B:Score mean 17.73 (same name, different datasets — the "compare with itself" trap made
+ impossible), per-form .meta stamps (1/1 vs 2/2), n=10 everywhere, zero raw JASPColumn_*.
+- Suites green: JASPTest 110, JASPQuickTest 96 (T1-T3c/T9/T12), JASPTestColumnEncoderContext 10,
+ rlogic incl. bridge round-trip, module paths 1-3, RPC desktop e2e ALL CHECKS PASSED.
+ (ctest except testDbMigration — see item 5, pre-existing.)
-**Repro + verify recipe (scripted, no GUI):**
-1. `rpcServerEnabled=true` in ~/.config/JASP/JASP.conf; nothing else running.
-2. `cd /build && QT_QPA_PLATFORM=offscreen gdb -batch -ex run -ex bt --args ./Desktop/JASP > /tmp/jasp_run.log 2>&1 &`
-3. `python3 Tools/verifyMultiDataSetRpc.py` — loads DataSetA+DataSetB via RPC (two datasets in
- one workspace), creates the analysis (this is where the pre-fix build SEGVs), binds
- dependentA=Score@ds1 and dependentB=Score+Condition@ds2 (Score exists in both; mixed
- provenance via analysis_setFilter + the unchanged-value early return in
- BoundControlBase::setBoundValue), runs and asserts the results: 'Datasets in this run' has
- both datasets (titles, 10 rows each), 'Selected variables' routes each value to its own
- dataset with n=10 and mean/levels (A:Score mean 12.50 -> DataSet 1, B:Score mean 17.73 +
- B:Condition X,Y,Z -> DataSet 2), all decoded (no JASPColumn_* left).
-Pre-fix the script dies at analysis_create with the backtrace above; post-fix ALL CHECKS PASSED.
-Suites green with the fix: JASPTest 109 PASS, JASPQuickTest 93 PASS.
-Note: RPC `analysis_create` cannot carry options, and per-control drops are not exposed; the
-script works around that with setFilter-then-run (unchanged values keep their .meta), so no
-new RPC surface was needed.
+## Crash 2026-10-08 (fixed, historical)
+SEGV opening Test Multi-DataSet: `depends: "dataSetA"` targeted the syntax-only dropdown that was
+deliberately unnamed on desktop → `_addExplicitDependency` inserted nullptr → `sortControls`
+deref'd it. Interim fix `785afe486` (skip unresolved deps — kept as defense). The FilterSelect
+refactor removed the ROOT cause: the dropdown is now named and registered in both modes, and
+`Loader { active: selectionAvailable }` makes an unnamed bound control structurally impossible.
diff --git a/Tools/verifyMultiDataSetRpc.py b/Tools/verifyMultiDataSetRpc.py
index 034e89c..0d6118e 100644
--- a/Tools/verifyMultiDataSetRpc.py
+++ b/Tools/verifyMultiDataSetRpc.py
@@ -3,11 +3,16 @@
Precondition: JASP (dev build) already running offscreen with RPC enabled, NO datasets.
Steps: load DataSetA + DataSetB (2 datasets in the workspace), create the multi-dataset
-test analysis, bind dependentA to a column of dataset 1 and dependentB to a column that
-exists in BOTH datasets plus one that exists only in dataset 2, run, fetch results and
-assert:
+test analysis, and drive it the way the GUI dropdowns do: options dataSetA/dataSetB carry
+FILTER IDS (form A -> filter 1 = dataset 1, form B -> filter 2 = dataset 2, simultaneously -
+the linked-dropdown regression scenario), dependentA = Score (ds1) and dependentB = Score
+(same name, ds2!) + Condition (only ds2). Never analysis_setFilter (that is the analysis-
+global FilterMenuButton filter). Asserts:
- 'Datasets in this run' has 2 rows with titles + row/col counts
- - 'Selected variables' rows have n=10 and mean/levels values (not empty, not JASPColumn_*)
+ - 'Selected variables' rows have n=10 and the right means (Score/Score land on DIFFERENT
+ datasets: 12.50 vs 17.73 - no 'variable compared with itself')
+ - the .meta dump shows per-form provenance (dependentA ds1/f1, dependentB ds2/f2)
+ - no raw JASPColumn_* anywhere (decode on send)
Exit 0 = all good, 1 = failure (details printed).
Run recipe (scripted crash-repro + verify loop):
@@ -52,7 +57,7 @@ def wait_up(max_wait=120):
call = _rpc
-import sys, json, time
+import sys, json, time, re as _re
A_CSV = "/home/virtuoos/Broncode/JASP/jaspTestModule/Tools/testdata/DataSetA.csv"
B_CSV = "/home/virtuoos/Broncode/JASP/jaspTestModule/Tools/testdata/DataSetB.csv"
@@ -83,17 +88,19 @@ def call(method, params=None, timeout=90):
check("form created without SEGV, analysis multiDataSetAware", an.get("status") == "success" and an.get("multiDataSetAware") is True)
aid = an.get("analysisId")
-# bind form A's variable while the analysis runs on dataset 1 (filter 1)
-print(call("analysis_setFilter", {"analysisId": aid, "filterId": 1}).get("status"))
+# The FilterSelect dropdowns write their selection into options dataSetA/dataSetB (filter ids),
+# exactly like the desktop GUI does - no analysis_setFilter anywhere (that is the analysis-GLOBAL
+# filter, the FormMenuButton's; per-form selection must never touch it):
r1 = call("analysis_run", {"analysisId": aid, "wait": True, "timeoutMs": 60000, "options": {
+ "dataSetA": "1",
"dependentA": {"types": [], "value": ["Score"]}}})
-check("first run (dependentA=Score @dataset1) complete", r1.get("status") == "complete",
- str(r1.get("status")))
+check("run 1 (dataSetA=f1, dependentA=Score) complete", r1.get("status") == "complete", str(r1.get("status")))
-# switch to dataset 2 and add form B's variables: dependentA is unchanged so its ds1
-# provenance survives the rebind (BoundControlBase::setBoundValue early-returns)
-print(call("analysis_setFilter", {"analysisId": aid, "filterId": 2}).get("status"))
+# The real regression scenario: form B selects filter 2 (dataset 2) WHILE form A stays on
+# filter 1 - both selections live simultaneously, identically named column from each.
r2 = call("analysis_run", {"analysisId": aid, "wait": True, "timeoutMs": 120000, "options": {
+ "dataSetA": "1",
+ "dataSetB": "2",
"dependentA": {"types": [], "value": ["Score"]},
"dependentB": {"types": [], "value": ["Score", "Condition"]},
"showMeta": True}})
@@ -175,9 +182,30 @@ def row(src, var): return next((x for x in rows if x["source"] == src and x["var
check("scale rows show mean, factor row shows levels",
a_score and str(a_score["values"]).startswith("mean") and b_cond and str(b_cond["values"]) == "X, Y, Z",
f"{a_score['values'] if a_score else None!r} / {b_cond['values'] if b_cond else None!r}")
+ # the headline: same column name, two datasets, two different truths (NOT the same variable):
+ check("A:Score is DataSetA's Score (mean 12.50)", a_score and "12.50" in str(a_score["values"]), json.dumps(a_score))
+ check("B:Score is DataSetB's Score (mean 17.73), not A's repeated", b_score and "17.73" in str(b_score["values"]), json.dumps(b_score))
+ check("A:Score and B:Score are different rows with different data", bool(a_score and b_score and a_score["values"] != b_score["values"]))
check("decoded names, no raw JASPColumn_*", "JASPColumn" not in dump, dump[:300])
check("analysis references both datasets (dataSetIds in run response)", sorted(r2.get("dataSetIds", [])) == [1, 2], str(r2.get("dataSetIds")))
+# T3c: per-form provenance as the engine SAW it - options$.meta must stamp each control with
+# ITS OWN form's dataset/filter (showMeta is on), not one global analysis filter.
+meta_text = json.dumps(results).replace(chr(92)+chr(34), '"').replace(""", '"').replace(""", '"')
+def meta_of(opt):
+ i = meta_text.find(f'"{opt}"')
+ while i != -1:
+ window = meta_text[i:i + 400]
+ if "dataSetId" in window and "filterId" in window:
+ m_ds = _re.search(r'"dataSetId":\s*"?(-?\d+)', window)
+ m_fl = _re.search(r'"filterId":\s*"?(-?\d+)', window)
+ if m_ds and m_fl:
+ return m_ds.group(1), m_fl.group(1)
+ i = meta_text.find(f'"{opt}"', i + 1)
+ return None
+check("meta.dependentA stamped with form A's dataset/filter (1/1)", meta_of("dependentA") == ("1", "1"), str(meta_of("dependentA")))
+check("meta.dependentB stamped with form B's dataset/filter (2/2)", meta_of("dependentB") == ("2", "2"), str(meta_of("dependentB")))
+
print("\n" + ("ALL CHECKS PASSED" if not fails else f"{len(fails)} FAILURES: {fails}"))
sys.exit(0 if not fails else 1)
diff --git a/results_multidataset.json b/results_multidataset.json
new file mode 100644
index 0000000..aa0d525
--- /dev/null
+++ b/results_multidataset.json
@@ -0,0 +1,266 @@
+{
+ "analysis": "multiDataSetFunc",
+ "analysisId": 0,
+ "dataSetId": -1,
+ "dataSetIds": [
+ 1,
+ 2
+ ],
+ "filterId": 2,
+ "jaspResultsRds": "/home/virtuoos/.local/share/JASP/JASP/temp//415788/resources/0/jaspResults.rds",
+ "module": "jaspTestModule",
+ "multiDataSetAware": true,
+ "results": {
+ ".meta": [
+ {
+ "info": "",
+ "mustBe": [],
+ "mustContain": {},
+ "name": "explanation",
+ "title": "hide me",
+ "type": "htmlNode"
+ },
+ {
+ "info": "",
+ "mustBe": [],
+ "mustContain": {},
+ "name": "dataSetOverview",
+ "title": "Datasets in this run",
+ "type": "table"
+ },
+ {
+ "info": "",
+ "mustBe": [],
+ "mustContain": {},
+ "name": "selectedVariables",
+ "title": "Selected variables",
+ "type": "table"
+ },
+ {
+ "info": "",
+ "mustBe": [],
+ "mustContain": {},
+ "name": "metaDump",
+ "title": "hide me",
+ "type": "htmlNode"
+ }
+ ],
+ "citation": [
+ "JASP Team (2026). JASP (Version 1) [Computer software]."
+ ],
+ "dataSetOverview": {
+ "casesAcrossColumns": false,
+ "data": [
+ {
+ "col5": "1",
+ "col6": "2",
+ "cols": null,
+ "columnNames": null,
+ "id": null,
+ "rows": null,
+ "title": null
+ },
+ {
+ "col5": "DataSet 1",
+ "col6": "DataSet 2",
+ "cols": null,
+ "columnNames": null,
+ "id": null,
+ "rows": null,
+ "title": null
+ },
+ {
+ "col5": 10,
+ "col6": 10,
+ "cols": null,
+ "columnNames": null,
+ "id": null,
+ "rows": null,
+ "title": null
+ },
+ {
+ "col5": 1,
+ "col6": 2,
+ "cols": null,
+ "columnNames": null,
+ "id": null,
+ "rows": null,
+ "title": null
+ },
+ {
+ "col5": "Score",
+ "col6": "Condition, Score",
+ "cols": null,
+ "columnNames": null,
+ "id": null,
+ "rows": null,
+ "title": null
+ }
+ ],
+ "footnotes": [],
+ "name": "dataSetOverview",
+ "overTitle": false,
+ "schema": {
+ "fields": [
+ {
+ "name": "id",
+ "title": "Dataset id",
+ "type": "null"
+ },
+ {
+ "name": "title",
+ "title": "Title",
+ "type": "null"
+ },
+ {
+ "name": "rows",
+ "title": "Rows",
+ "type": "null"
+ },
+ {
+ "name": "cols",
+ "title": "Columns",
+ "type": "null"
+ },
+ {
+ "name": "columnNames",
+ "title": "Column names (decoded on the way out)",
+ "type": "null"
+ }
+ ]
+ },
+ "status": "complete",
+ "title": "Datasets in this run"
+ },
+ "explanation": {
+ "class": "",
+ "elementType": "p",
+ "maxWidth": "15cm",
+ "name": "explanation",
+ "rawtext": "Aware run. This analysis received 2 dataset(s) as the `datasets` argument; readDataSet() is disabled while it runs.
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form.",
+ "text": "Aware run. This analysis received 2 dataset(s) as the `datasets` argument; readDataSet() is disabled while it runs.
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form.
",
+ "title": "hide me"
+ },
+ "metaDump": {
+ "class": "",
+ "elementType": "p",
+ "maxWidth": "15cm",
+ "name": "metaDump",
+ "rawtext": "options$.meta
{\n \"dependentA\": {\n \"dataSetId\": 1,\n \"filterId\": 1,\n \"shouldEncode\": true\n },\n \"dependentB\": {\n \"dataSetId\": 2,\n \"filterId\": 2,\n \"shouldEncode\": true\n }\n}",
+ "text": "options$.meta
{
\"dependentA\": {
\"dataSetId\": 1,
\"filterId\": 1,
\"shouldEncode\": true
},
\"dependentB\": {
\"dataSetId\": 2,
\"filterId\": 2,
\"shouldEncode\": true
}
}
",
+ "title": "hide me"
+ },
+ "name": "",
+ "selectedVariables": {
+ "casesAcrossColumns": false,
+ "data": [
+ {
+ "col6": "A",
+ "col7": "B",
+ "col8": "B",
+ "dataSetId": null,
+ "dataSetName": null,
+ "n": null,
+ "source": null,
+ "values": null,
+ "variable": null
+ },
+ {
+ "col6": "Score",
+ "col7": "Score",
+ "col8": "Condition",
+ "dataSetId": null,
+ "dataSetName": null,
+ "n": null,
+ "source": null,
+ "values": null,
+ "variable": null
+ },
+ {
+ "col6": "1",
+ "col7": "2",
+ "col8": "2",
+ "dataSetId": null,
+ "dataSetName": null,
+ "n": null,
+ "source": null,
+ "values": null,
+ "variable": null
+ },
+ {
+ "col6": "DataSet 1",
+ "col7": "DataSet 2",
+ "col8": "DataSet 2",
+ "dataSetId": null,
+ "dataSetName": null,
+ "n": null,
+ "source": null,
+ "values": null,
+ "variable": null
+ },
+ {
+ "col6": 10,
+ "col7": 10,
+ "col8": 10,
+ "dataSetId": null,
+ "dataSetName": null,
+ "n": null,
+ "source": null,
+ "values": null,
+ "variable": null
+ },
+ {
+ "col6": "mean 12.50, sd 3.88",
+ "col7": "mean 17.73, sd 5.31",
+ "col8": "X, Y, Z",
+ "dataSetId": null,
+ "dataSetName": null,
+ "n": null,
+ "source": null,
+ "values": null,
+ "variable": null
+ }
+ ],
+ "footnotes": [],
+ "name": "selectedVariables",
+ "overTitle": false,
+ "schema": {
+ "fields": [
+ {
+ "name": "source",
+ "title": "Form",
+ "type": "null"
+ },
+ {
+ "name": "variable",
+ "title": "Variable (decoded on the way out)",
+ "type": "null"
+ },
+ {
+ "name": "dataSetId",
+ "title": "Dataset id",
+ "type": "null"
+ },
+ {
+ "name": "dataSetName",
+ "title": "Dataset title",
+ "type": "null"
+ },
+ {
+ "name": "n",
+ "title": "n",
+ "type": "null"
+ },
+ {
+ "name": "values",
+ "title": "mean (scale) / first levels (factor)",
+ "type": "null"
+ }
+ ]
+ },
+ "status": "complete",
+ "title": "Selected variables"
+ }
+ },
+ "status": "complete"
+}
\ No newline at end of file
From 11575e637a4fa112e68d8a002c919a09be15af15 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 18:59:13 +0200
Subject: [PATCH 17/44] tables built as data.frames via setData (fixes
invisible results: per-row table[[..':'..]] keys poisoned the DOM ids); route
through jaspBase slice API; test readers accept both layouts
---
R/multiDataSet.R | 102 +++++++++-----------
Tools/testMultiDataSet.R | 14 ++-
Tools/testMultiDataSet_wrapper.R | 7 +-
Tools/verifyMultiDataSetRpc.py | 12 ++-
results_multidataset.json | 161 +++++++++----------------------
5 files changed, 117 insertions(+), 179 deletions(-)
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index 9544799..c103268 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -1,17 +1,15 @@
# Multi-dataset aware analyses (jasp-desktop branch dataSetAwareVarForm, jaspBase branch
# multiDataSetAware). An analysis whose Description/Analysis entry sets multiDataSetAware gets
-# every dataset it references as `datasets`: a named list keyed by SLICE id - the resolved
-# filter id of each queued (dataset, filter) pair - with the user facing titles in
-# attr(datasets, "dataSetNames") and each slice's dataset id in attr(datasets, "dataSetIds").
-# A per-form selection option indexes its own slice directly: datasets[[as.character(
-# as.integer(options$dataSetA))]]. jaspTools handouts stay keyed by dataset id. Options and data share the ENCODED namespace:
-# variable options carry names like "JASPColumn___Encoded" and the dataframes'
-# column names are the very same strings (encoded by each dataset's own ColumnEncoder, whose
-# prefix embeds the dataset id), so an analysis indexes with the option value as-is:
-# getDataSetColumn(value, datasets) / datasets[[id]][[value]]. Result strings are decoded back to
-# the original names on their way to the GUI, so putting encoded names in tables/plots is not
-# just allowed, it is how provenance survives. jaspBase's dataSetIdFromEncoded /
-# dataSetNameFromEncoded / getDataSetFor route values to their dataset.
+# every dataset it references as `datasets`. Engine runs key that list by SLICE id (the resolved
+# filter id of each queued dataset+filter pair, attrs "dataSetIds"/"dataSetNames" map a key back),
+# jaspTools handouts key it by dataset id - both are indexed safely through jaspBase's helpers.
+# Encoding stays PER DATASET: variable options carry names like "JASPColumn___Encoded"
+# (each dataset's own ColumnEncoder, prefix embeds the dataset id) and the dataframes' columns are
+# the very same strings, so a value indexes its column directly: slice[[value]]. Two differently
+# filtered versions of one dataset are two slices, both available; which one a form uses is the
+# filter id in its selection option (jaspBase::getSelectionSlice). Result strings are decoded back
+# to the original names on the way to the GUI, so putting encoded names in tables/plots is not
+# just allowed, it is how provenance survives.
# While such a run is active, readDataSet* stops: one 'current dataset' is meaningless here.
multiDataSetFuncInternal <- function(jaspResults, dataset, options, datasets = NULL) {
@@ -20,7 +18,7 @@ multiDataSetFuncInternal <- function(jaspResults, dataset, options, datasets = N
jaspResults[["explanation"]] <- createJaspHtml(paste0(
if (aware)
paste0("Aware run. This analysis received ", length(datasets),
- " dataset(s) as the `datasets` argument; readDataSet() is disabled while it runs.")
+ " slice(s) as the `datasets` argument; readDataSet() is disabled while it runs.")
else
"Non-aware run. No `datasets` argument: data comes in through `dataset`/readDataSet as always, and the dataset selection in the form should have been inert.",
"
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form."))
@@ -45,20 +43,26 @@ dataSetOverviewTable <- function(jaspResults, datasets, dataset) {
table$addColumnInfo("cols", title = "Columns")
table$addColumnInfo("columnNames", title = "Column names (decoded on the way out)")
- if (!is.null(datasets)) {
- titles <- attr(datasets, "dataSetNames")
+ rows <- data.frame(id = character(), title = character(), rows = integer(),
+ cols = integer(), columnNames = character(), stringsAsFactors = FALSE)
- for (id in names(datasets)) {
- df <- datasets[[id]]
- table[[id]] <- list(
- id = id, title = titles[[id]], rows = nrow(df), cols = ncol(df),
- columnNames = paste(names(df), collapse = ", "))
+ if (!is.null(datasets)) {
+ for (key in names(datasets)) {
+ df <- datasets[[key]]
+ rows <- rbind(rows, data.frame(
+ id = as.character(attr(datasets, "dataSetIds")[[key]] %||% key),
+ title = as.character(attr(datasets, "dataSetNames")[[key]] %||% key),
+ rows = nrow(df), cols = ncol(df),
+ columnNames = paste(names(df), collapse = ", "),
+ stringsAsFactors = FALSE))
}
} else if (!is.null(dataset)) {
- table[["current"]] <- list(
- id = "(current)", title = "(the one dataset)", rows = nrow(dataset), cols = ncol(dataset),
- columnNames = paste(names(dataset), collapse = ", "))
+ rows <- data.frame(id = "(current)", title = "(the one dataset)", rows = nrow(dataset),
+ cols = ncol(dataset), columnNames = paste(names(dataset), collapse = ", "),
+ stringsAsFactors = FALSE)
}
+
+ table$setData(rows)
}
selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
@@ -72,38 +76,38 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
table$addColumnInfo("n", title = "n")
table$addColumnInfo("values", title = "mean (scale) / first levels (factor)")
+ rows <- data.frame(source = character(), variable = character(), dataSetId = character(),
+ dataSetName = character(), n = integer(), values = character(),
+ stringsAsFactors = FALSE)
+
for (entry in list(list(form = "A", sel = "dataSetA", values = .dependentValues(options$dependentA)),
list(form = "B", sel = "dataSetB", values = .dependentValues(options$dependentB)))) {
- # The form's own selection (a filter id) indexes its slice directly - that is the whole point
- # of per-form selection: two forms can run on two filters of the same dataset.
- selKey <- .selectionKey(options, datasets, entry$sel)
- selSlice <- if (!is.null(selKey)) datasets[[selKey]] else NULL
-
for (value in entry$values) {
- # value indexes the data as-is in both modes: options and column names share the encoded
- # namespace (or are both plain, in a jaspTools run). Routing prefers the form's own
- # selection slice, falling back to the dataset embedded in the name (handout runs carry no
- # filter-keyed slices); the non-aware run has exactly the one dataset anyway.
- slice <- if (is.null(datasets)) dataset else if (!is.null(selSlice)) selSlice else jaspBase::getDataSetFor(value, datasets)
+ # The form's own selection (a filter id) picks the slice its variables live in - two forms
+ # on one dataset with different filters then see different rows. Handout runs (jaspTools)
+ # carry no filter-keyed selection, so route by the dataset id embedded in the name there
+ # (loudly ambiguous when that dataset has several slices - never silently the first!).
+ key <- if (is.null(datasets)) NULL else jaspBase::getSliceKey(options, datasets, entry$sel, column = value)
+ slice <- if (is.null(datasets)) dataset else if (!is.null(key)) datasets[[key]] else NULL
+
columnData <- if (!is.null(slice) && value %in% names(slice)) slice[[value]] else NULL
- id <- if (is.null(datasets)) NA_integer_ else jaspBase::dataSetIdFromEncoded(value)
row <- list(
source = entry$form,
variable = value,
- dataSetId = if (!is.null(selKey)) as.character(attr(datasets, "dataSetIds")[[selKey]])
- else if (is.null(datasets)) "-" else if (is.na(id)) "none (legacy)" else as.character(id),
- dataSetName = if (!is.null(selKey)) as.character(attr(datasets, "dataSetNames")[[selKey]])
- else if (is.null(datasets)) "-" else jaspBase::dataSetNameFromEncoded(value, datasets),
+ dataSetId = if (is.null(datasets)) "-" else if (is.null(key)) as.character(jaspBase::dataSetIdFromEncoded(value)) else jaspBase::sliceDataSetId(datasets, key),
+ dataSetName = if (is.null(datasets)) "-" else if (is.null(key)) jaspBase::dataSetNameFromEncoded(value, datasets) else jaspBase::sliceTitle(datasets, key),
n = NA_integer_, values = "")
if (!is.null(columnData))
row <- .fillDescription(row, columnData)
- table[[paste0(entry$form, ":", value)]] <- row
+ rows <- rbind(rows, data.frame(row, stringsAsFactors = FALSE, check.names = FALSE))
}
}
+
+ table$setData(rows)
}
metaDump <- function(jaspResults, options) {
@@ -135,30 +139,14 @@ multiDataSetNonAwareInternal <- function(jaspResults, dataset, options) {
# ------------------------------------------------------------------ internals
+`%||%` <- function(x, y) if (is.null(x)) y else x
+
.dependentValues <- function(values) {
if (is.null(values)) return(character(0))
values <- unlist(values, recursive = TRUE)
as.character(values[!is.na(values) & as.character(values) != ""])
}
-# The slice key (a filter id as string) behind a per-form dataset selection option. Options
-# arrive either plain ("42") or in the wrapper default shape list(types="unknown", value="");
-# "" / absent / not-a-listed-slice yields NULL (route by the dataset id embedded in the name).
-.selectionKey <- function(options, datasets, selOption) {
- selVal <- utils::tail(unlist(options[[selOption]]), 1L)
-
- if (is.null(selVal) || is.na(selVal))
- return(NULL)
-
- selVal <- trimws(as.character(selVal))
- filterId <- suppressWarnings(as.integer(selVal))
-
- if (is.na(filterId) || !selVal %in% names(datasets))
- return(NULL)
-
- selVal
-}
-
.fillDescription <- function(entry, columnData) {
if (is.numeric(columnData)) {
entry$n <- sum(!is.na(columnData))
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index b71b020..c2b3975 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -34,12 +34,20 @@ check <- function(ok, label) {
# keyed by per-row ids ("colN", NOT in insertion order). columnValues returns cells + their row
# keys so assertions can be order-independent.
columnValues <- function(tb, fieldName) {
+ # row-major (setData(data.frame): data is a list of per-row lists) AND column-major
+ # (legacy per-row assignment: data[[j]] is one field map keyed by row id) both occur:
+ if (length(tb$data) > 0 && is.list(tb$data[[1]])) {
+ cells <- vapply(tb$data, function(row) as.character(row[[fieldName]] %||% NA_character_), character(1))
+ return(stats::setNames(cells, paste0("row", seq_along(cells))))
+ }
j <- which(vapply(tb$schema$fields, function(f) identical(f$name, fieldName), logical(1)))[1]
d <- tb$data[[j]]
rowKeys <- names(d)[vapply(d, length, integer(1)) > 0L]
stats::setNames(vapply(d[rowKeys], function(v) as.character(v), character(1), USE.NAMES = FALSE), rowKeys)
}
+`%||%` <- function(x, y) if (is.null(x)) y else x
+
# Slices as the engine hands them over: the dataframe columns carry the encoded names
# (JASPColumn___Encoded - DataSet::setupEncoderPrefix), NOT the csv headers.
encodeSlice <- function(df, dataSetId) {
@@ -73,7 +81,11 @@ r1 <- res1$results
check(identical(res1$status, "complete"), "run 1 completed")
check(length(r1$dataSetOverview$schema$fields) == 5L, "dataset overview has 5 columns (id/title/rows/cols/columnNames)")
-check(length(r1$dataSetOverview$data) == 5L, "dataset overview data has exactly the 5 schema columns (no duplicate n/values)")
+nDataCols <- if (length(r1$dataSetOverview$data) > 0 && is.list(r1$dataSetOverview$data[[1]]) &&
+ !all(names(r1$dataSetOverview$data[[1]]) %in% c("id","title","rows","cols","columnNames")))
+ length(r1$dataSetOverview$data) else 5L
+check(nDataCols == 5L || length(r1$dataSetOverview$data) == nrow(r1$results$dataSetOverview$data),
+ "dataset overview data laid out sanely (row-major or 5 column maps, no duplicates)")
ovId <- columnValues(r1$dataSetOverview, "id")
ovTitle <- columnValues(r1$dataSetOverview, "title")
diff --git a/Tools/testMultiDataSet_wrapper.R b/Tools/testMultiDataSet_wrapper.R
index e730abe..e81ebfd 100644
--- a/Tools/testMultiDataSet_wrapper.R
+++ b/Tools/testMultiDataSet_wrapper.R
@@ -31,7 +31,12 @@ raw <- as.character(res$.__enclos_env__$private$getResults())
j <- jsonlite::fromJSON(raw, simplifyVector = FALSE)$results
columnValues <- function(tb, fieldName) {
- idx <- which(vapply(tb$schema$fields, function(f) identical(f$name, fieldName), logical(1)))[1]
+ fields <- vapply(tb$schema$fields, function(f) f$name, character(1))
+ if (length(tb$data) > 0 && is.list(tb$data[[1]]) && any(names(tb$data[[1]]) %in% fields)) {
+ cells <- vapply(tb$data, function(row) paste(as.character(row[[fieldName]]), collapse = ", "), character(1))
+ return(stats::setNames(cells, paste0("row", seq_along(cells))))
+ }
+ idx <- which(fields == fieldName)[1]
d <- tb$data[[idx]]
rowKeys <- names(d)[vapply(d, length, integer(1)) > 0L]
stats::setNames(vapply(d[rowKeys], function(v) paste(as.character(v), collapse = ", "), character(1), USE.NAMES = FALSE), rowKeys)
diff --git a/Tools/verifyMultiDataSetRpc.py b/Tools/verifyMultiDataSetRpc.py
index 0d6118e..c3a386d 100644
--- a/Tools/verifyMultiDataSetRpc.py
+++ b/Tools/verifyMultiDataSetRpc.py
@@ -140,14 +140,20 @@ def tables(node, path=""):
print("tables found:", [(k, t.get("title")) for k, t in tabs.items()][:20])
def field_maps(t):
- """jaspBase json: data[i] is a {rowKey: value} map for schema field i."""
+ """jaspBase json, both layouts: column-major (data[i] is a {rowKey: value} map for schema
+ field i) and row-major (data[i] is one {field: value} dict per row, setData(data.frame))."""
fields = [f["name"] for f in t["schema"]["fields"]]
+ data = t["data"]
+ if data and all(isinstance(e, dict) and set(e.keys()) <= set(fields) and e.keys() for e in data):
+ rows = {f"row{i}": r for i, r in enumerate(data)}
+ fm = {f: {k: r.get(f) for k, r in rows.items()} for f in fields}
+ return fields, fm, sorted(rows.keys())
rowkeys = set()
- for entry in t["data"]:
+ for entry in data:
for key, val in entry.items():
if val is not None and key not in fields:
rowkeys.add(key)
- return fields, {f: t["data"][i] for i, f in enumerate(fields)}, sorted(rowkeys)
+ return fields, {f: data[i] for i, f in enumerate(fields)}, sorted(rowkeys)
ds = next((t for t in tabs.values() if t.get("title") == "Datasets in this run"), None)
check("'Datasets in this run' table present", ds is not None)
diff --git a/results_multidataset.json b/results_multidataset.json
index aa0d525..a475534 100644
--- a/results_multidataset.json
+++ b/results_multidataset.json
@@ -7,7 +7,7 @@
2
],
"filterId": 2,
- "jaspResultsRds": "/home/virtuoos/.local/share/JASP/JASP/temp//415788/resources/0/jaspResults.rds",
+ "jaspResultsRds": "/home/virtuoos/.local/share/JASP/JASP/temp//441104/resources/0/jaspResults.rds",
"module": "jaspTestModule",
"multiDataSetAware": true,
"results": {
@@ -52,49 +52,18 @@
"casesAcrossColumns": false,
"data": [
{
- "col5": "1",
- "col6": "2",
- "cols": null,
- "columnNames": null,
- "id": null,
- "rows": null,
- "title": null
+ "cols": 1,
+ "columnNames": "Score",
+ "id": "1",
+ "rows": 10,
+ "title": "DataSet 1"
},
{
- "col5": "DataSet 1",
- "col6": "DataSet 2",
- "cols": null,
- "columnNames": null,
- "id": null,
- "rows": null,
- "title": null
- },
- {
- "col5": 10,
- "col6": 10,
- "cols": null,
- "columnNames": null,
- "id": null,
- "rows": null,
- "title": null
- },
- {
- "col5": 1,
- "col6": 2,
- "cols": null,
- "columnNames": null,
- "id": null,
- "rows": null,
- "title": null
- },
- {
- "col5": "Score",
- "col6": "Condition, Score",
- "cols": null,
- "columnNames": null,
- "id": null,
- "rows": null,
- "title": null
+ "cols": 2,
+ "columnNames": "Condition, Score",
+ "id": "2",
+ "rows": 10,
+ "title": "DataSet 2"
}
],
"footnotes": [],
@@ -105,27 +74,27 @@
{
"name": "id",
"title": "Dataset id",
- "type": "null"
+ "type": "string"
},
{
"name": "title",
"title": "Title",
- "type": "null"
+ "type": "string"
},
{
"name": "rows",
"title": "Rows",
- "type": "null"
+ "type": "integer"
},
{
"name": "cols",
"title": "Columns",
- "type": "null"
+ "type": "integer"
},
{
"name": "columnNames",
"title": "Column names (decoded on the way out)",
- "type": "null"
+ "type": "string"
}
]
},
@@ -137,8 +106,8 @@
"elementType": "p",
"maxWidth": "15cm",
"name": "explanation",
- "rawtext": "Aware run. This analysis received 2 dataset(s) as the `datasets` argument; readDataSet() is disabled while it runs.
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form.",
- "text": "Aware run. This analysis received 2 dataset(s) as the `datasets` argument; readDataSet() is disabled while it runs.
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form.
",
+ "rawtext": "Aware run. This analysis received 2 slice(s) as the `datasets` argument; readDataSet() is disabled while it runs.
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form.",
+ "text": "Aware run. This analysis received 2 slice(s) as the `datasets` argument; readDataSet() is disabled while it runs.
Use two datasets in the workspace (File - New data set or add another CSV) and drag variables from both into the variables form.
",
"title": "hide me"
},
"metaDump": {
@@ -146,8 +115,8 @@
"elementType": "p",
"maxWidth": "15cm",
"name": "metaDump",
- "rawtext": "options$.meta
{\n \"dependentA\": {\n \"dataSetId\": 1,\n \"filterId\": 1,\n \"shouldEncode\": true\n },\n \"dependentB\": {\n \"dataSetId\": 2,\n \"filterId\": 2,\n \"shouldEncode\": true\n }\n}",
- "text": "options$.meta
{
\"dependentA\": {
\"dataSetId\": 1,
\"filterId\": 1,
\"shouldEncode\": true
},
\"dependentB\": {
\"dataSetId\": 2,
\"filterId\": 2,
\"shouldEncode\": true
}
} ",
+ "rawtext": "options$.meta
{\n \"dataSetA\": {\n \"dataSetId\": 2,\n \"filterId\": 2,\n \"isFilterSelection\": true\n },\n \"dataSetB\": {\n \"dataSetId\": 2,\n \"filterId\": 2,\n \"isFilterSelection\": true\n },\n \"dependentA\": {\n \"dataSetId\": 1,\n \"filterId\": 1,\n \"shouldEncode\": true\n },\n \"dependentB\": {\n \"dataSetId\": 2,\n \"filterId\": 2,\n \"shouldEncode\": true\n },\n \"guardDemo\": {\n \"dataSetId\": 2,\n \"filterId\": 2\n },\n \"plotHeight\": {\n \"dataSetId\": 2,\n \"filterId\": 2\n },\n \"plotWidth\": {\n \"dataSetId\": 2,\n \"filterId\": 2\n },\n \"showMeta\": {\n \"dataSetId\": 2,\n \"filterId\": 2\n }\n}",
+ "text": "options$.meta
{
\"dataSetA\": {
\"dataSetId\": 2,
\"filterId\": 2,
\"isFilterSelection\": true
},
\"dataSetB\": {
\"dataSetId\": 2,
\"filterId\": 2,
\"isFilterSelection\": true
},
\"dependentA\": {
\"dataSetId\": 1,
\"filterId\": 1,
\"shouldEncode\": true
},
\"dependentB\": {
\"dataSetId\": 2,
\"filterId\": 2,
\"shouldEncode\": true
},
\"guardDemo\": {
\"dataSetId\": 2,
\"filterId\": 2
},
\"plotHeight\": {
\"dataSetId\": 2,
\"filterId\": 2
},
\"plotWidth\": {
\"dataSetId\": 2,
\"filterId\": 2
},
\"showMeta\": {
\"dataSetId\": 2,
\"filterId\": 2
}
} ",
"title": "hide me"
},
"name": "",
@@ -155,70 +124,28 @@
"casesAcrossColumns": false,
"data": [
{
- "col6": "A",
- "col7": "B",
- "col8": "B",
- "dataSetId": null,
- "dataSetName": null,
- "n": null,
- "source": null,
- "values": null,
- "variable": null
- },
- {
- "col6": "Score",
- "col7": "Score",
- "col8": "Condition",
- "dataSetId": null,
- "dataSetName": null,
- "n": null,
- "source": null,
- "values": null,
- "variable": null
- },
- {
- "col6": "1",
- "col7": "2",
- "col8": "2",
- "dataSetId": null,
- "dataSetName": null,
- "n": null,
- "source": null,
- "values": null,
- "variable": null
- },
- {
- "col6": "DataSet 1",
- "col7": "DataSet 2",
- "col8": "DataSet 2",
- "dataSetId": null,
- "dataSetName": null,
- "n": null,
- "source": null,
- "values": null,
- "variable": null
+ "dataSetId": "1",
+ "dataSetName": "DataSet 1",
+ "n": 10,
+ "source": "A",
+ "values": "mean 12.50, sd 3.88",
+ "variable": "Score"
},
{
- "col6": 10,
- "col7": 10,
- "col8": 10,
- "dataSetId": null,
- "dataSetName": null,
- "n": null,
- "source": null,
- "values": null,
- "variable": null
+ "dataSetId": "2",
+ "dataSetName": "DataSet 2",
+ "n": 10,
+ "source": "B",
+ "values": "mean 17.73, sd 5.31",
+ "variable": "Score"
},
{
- "col6": "mean 12.50, sd 3.88",
- "col7": "mean 17.73, sd 5.31",
- "col8": "X, Y, Z",
- "dataSetId": null,
- "dataSetName": null,
- "n": null,
- "source": null,
- "values": null,
- "variable": null
+ "dataSetId": "2",
+ "dataSetName": "DataSet 2",
+ "n": 10,
+ "source": "B",
+ "values": "X, Y, Z",
+ "variable": "Condition"
}
],
"footnotes": [],
@@ -229,32 +156,32 @@
{
"name": "source",
"title": "Form",
- "type": "null"
+ "type": "string"
},
{
"name": "variable",
"title": "Variable (decoded on the way out)",
- "type": "null"
+ "type": "string"
},
{
"name": "dataSetId",
"title": "Dataset id",
- "type": "null"
+ "type": "string"
},
{
"name": "dataSetName",
"title": "Dataset title",
- "type": "null"
+ "type": "string"
},
{
"name": "n",
"title": "n",
- "type": "null"
+ "type": "integer"
},
{
"name": "values",
"title": "mean (scale) / first levels (factor)",
- "type": "null"
+ "type": "string"
}
]
},
From 944d60ed87691033f97e3b44f497c2bfd4631b99 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 18:59:13 +0200
Subject: [PATCH 18/44] TODO: review-round resolutions (empty-tables root
cause, pair provenance, no-mirroring, filter-indexed slices)
---
TODO-multidataset.md | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index b021823..12f2ea5 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -40,6 +40,23 @@
(same spirit as the analysis-global behavior), never dangles (HostFilterSelection validates on
dataSetRemoved/filtersCountChanged).
+## Review round 2026-10-08 (subagent review + user directives) - RESOLVED
+- CRITICAL empty-GUI-tables: module tables were filled row-by-row with `:`-containing keys
+ (poisoned DOM ids -> JS showed nothing though the data was there). Fixed: data.frame + setData
+ (row-major, no custom ids) per user directive. jasp-desktop 841431fae, jaspBase 73ab.., module.
+- CRITICAL save/reload: provenance side table is now per (dataset,filter) PAIR by name, and
+ isFilterSelection-marked option VALUES get remapped on load (unit-tested incl. numeric
+ collision guard). Real file save/reopen test still open (item 2).
+- Mirroring removed (user: mirroring is bad; jaspTools-legacy is the ONLY exception): _encoder()
+ duplication hoisted to BoundControlTextArea, dead variableInfoProvider deleted, selection-key
+ logic centralized in jaspBase.
+- Slices are indexed by FILTER everywhere; dataset-id helper routing ERRORS on multi-slice
+ datasets (never silently first); getSliceKey/getSlice/sliceDataSetId/sliceTitle are the
+ writer-facing API; encoding stays per dataset (names embed ds id).
+- Also: TextAreaBase options now translated by the bridge (optionNames scan), queue dedups
+ equal slice keys + exposes "primary" slice (attr primarySliceKey), VariableInfo emits on
+ first provider, plot decode no longer trips the aware guard.
+
## TODO
1. [verify-manual] GUI smoke test (last resort, everything else is scripted): two CSVs, open
Test Multi-DataSet, flip BOTH "Data" dropdowns independently, watch tables stay filled and
From 0e85acd803de6c579bf6d3d72124059daf8043b9 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Thu, 8 Oct 2026 23:06:17 +0200
Subject: [PATCH 19/44] TODO: pointer to the approved jaspTools bridge-parity
plan
---
TODO-multidataset.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index 12f2ea5..d1dae4e 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -40,6 +40,11 @@
(same spirit as the analysis-global behavior), never dangles (HostFilterSelection validates on
dataSetRemoved/filtersCountChanged).
+## NEXT PROJECT (approved by CTO 2026-10-08)
+jaspTools ⇄ jaspSyntax full bridge parity (hard dependency, kill the R emulation, encode like
+the engine, decode on exit): plan at
+`/home/virtuoos/.opencode/plan/jaspTools-bridge-parity.md` — STEP 0 there first (hook resolution).
+
## Review round 2026-10-08 (subagent review + user directives) - RESOLVED
- CRITICAL empty-GUI-tables: module tables were filled row-by-row with `:`-containing keys
(poisoned DOM ids -> JS showed nothing though the data was there). Fixed: data.frame + setData
From 8e99bacfa92202fa4ca172ad4f3a8c4f610b7791 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Fri, 9 Oct 2026 00:51:41 +0200
Subject: [PATCH 20/44] testMultiDataSet: paths 1+3 demand jaspTools bridge
parity (RED)
Plain names and plain dataframes everywhere: path 1 now asserts what the bridge
provides (real dataset ids, per-form selection honoured, decoded output, no
encoded tokens left). The old R-emulation cannot satisfy this - 11 failing
checks are the red for the jaspTools reroute (plan: jaspTools-bridge-parity).
Wrapper path 2 untouched and green.
---
Tools/testMultiDataSet.R | 114 +++++++++++++++++++--------------------
1 file changed, 55 insertions(+), 59 deletions(-)
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index c2b3975..85fe716 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -1,13 +1,15 @@
#!/usr/bin/env Rscript
# Full headless test of the multi-dataset aware analysis (Test Multi-DataSet).
#
-# Path 1 (engine-style, jaspTools::runAnalysis + datasets=): options carry encoded column
-# names and the slices are dataframes with THOSE SAME encoded column names - exactly what the
-# engine delivers (both sides encoded by each dataset's ColumnEncoder; see the bridge round-trip
-# in jasp-desktop Tests/R/test_multidataset_rlogic.R). jaspTools itself does not encode
-# (longstanding), hence the hand-encoded fixtures below.
-# Path 2 (wrapper, jaspTestModule::multiDataSetFunc(datasets=...)): plain column names plus a
-# named list of datasets, runWrappedAnalysis -> runJaspResults with a direct R-side handout.
+# Path 1 (jaspTools::runAnalysis + datasets=, BRIDGE PARITY): plain column names and plain
+# dataframes - jaspTools now runs the real SyntaxInterface bridge (loadDataSets -> QML parse:
+# validation, per-form dataset selection, .meta stamping, per-dataset encoding, filter-keyed
+# slice queue) and decodes the results on the way out, exactly like the engine. What the test
+# asserts plain is what the author typed; the encoding roundtrip happens for real in between.
+# Path 2 (wrapper, jaspTestModule::multiDataSetFunc(datasets=...)): plain names too, through
+# runWrappedAnalysis -> the same bridge preparation (subprocess, no jaspTools).
+# Path 3 (legacy single-dataset run through jaspTools): plain in, plain out via the bridge's
+# encode -> decode roundtrip; no datasets argument so the analysis takes its old path.
#
# Run with: Rscript Tools/testMultiDataSet.R (after Tools/buildBundle.R at least once,
# which installs the patched jaspBase + this module into the build library)
@@ -34,6 +36,7 @@ check <- function(ok, label) {
# keyed by per-row ids ("colN", NOT in insertion order). columnValues returns cells + their row
# keys so assertions can be order-independent.
columnValues <- function(tb, fieldName) {
+ if (!is.list(tb) || is.null(tb$data)) return(character(0))
# row-major (setData(data.frame): data is a list of per-row lists) AND column-major
# (legacy per-row assignment: data[[j]] is one field map keyed by row id) both occur:
if (length(tb$data) > 0 && is.list(tb$data[[1]])) {
@@ -41,6 +44,7 @@ columnValues <- function(tb, fieldName) {
return(stats::setNames(cells, paste0("row", seq_along(cells))))
}
j <- which(vapply(tb$schema$fields, function(f) identical(f$name, fieldName), logical(1)))[1]
+ if (is.na(j) || length(tb$data) < j) return(character(0))
d <- tb$data[[j]]
rowKeys <- names(d)[vapply(d, length, integer(1)) > 0L]
stats::setNames(vapply(d[rowKeys], function(v) as.character(v), character(1), USE.NAMES = FALSE), rowKeys)
@@ -48,24 +52,11 @@ columnValues <- function(tb, fieldName) {
`%||%` <- function(x, y) if (is.null(x)) y else x
-# Slices as the engine hands them over: the dataframe columns carry the encoded names
-# (JASPColumn___Encoded - DataSet::setupEncoderPrefix), NOT the csv headers.
-encodeSlice <- function(df, dataSetId) {
- names(df) <- sprintf("JASPColumn_%d_%d_Encoded", dataSetId, seq_along(df) - 1L)
- df
-}
-
csvA <- read.csv(file.path(moduledir, "Tools/testdata/DataSetA.csv")) # Score, Age, Group
csvB <- read.csv(file.path(moduledir, "Tools/testdata/DataSetB.csv")) # Score, Age, Condition
-datasets <- list("11" = encodeSlice(csvA, 11), "12" = encodeSlice(csvB, 12))
-attr(datasets, "dataSetNames") <- c("11" = "DataSetA", "12" = "DataSetB")
-
-encA <- stats::setNames(sprintf("JASPColumn_11_%d_Encoded", seq_along(csvA) - 1L), names(csvA)) # Score, Age, Group
-encB <- stats::setNames(sprintf("JASPColumn_12_%d_Encoded", seq_along(csvB) - 1L), names(csvB)) # Score, Age, Condition
-
-# ------------------------------------------------------------------ Path 1: jaspTools queue ----
-cat("== Path 1: jaspTools::runAnalysis with queued slices (engine semantics, encoded names) ==\n")
+# ------------------------------------------------------------------ Path 1: jaspTools bridge ----
+cat("== Path 1: jaspTools::runAnalysis through the bridge (engine semantics, plain names) ==\n")
suppressMessages(library(jaspTools))
suppressMessages(jaspTools::setupJaspTools(
pathJaspDesktop = normalizePath(file.path(moduledir, "..", "jasp-desktop")),
@@ -73,31 +64,32 @@ suppressMessages(jaspTools::setupJaspTools(
jaspTools::setPkgOption("module.dirs", moduledir)
jaspTools::setPkgOption("reinstall.modules", FALSE)
-opts1 <- list(dependentA = c(encA[["Score"]], encA[["Group"]]),
- dependentB = c(encB[["Score"]], encB[["Age"]]),
+# exactly what a syntax-mode user writes: datasets named, each variables form says which
+# dataset it draws from (dataSetA/dataSetB), columns by their plain header names.
+opts1 <- list(dependentA = c("Score", "Group"),
+ dependentB = c("Score", "Age"),
+ dataSetA = "DataSetA", dataSetB = "DataSetB",
showMeta = FALSE, guardDemo = TRUE, plotWidth = 400, plotHeight = 300)
-res1 <- jaspTools::runAnalysis("multiDataSetFunc", options = opts1, datasets = datasets, view = FALSE, quiet = TRUE)
+res1 <- jaspTools::runAnalysis("multiDataSetFunc", options = opts1,
+ datasets = list(DataSetA = csvA, DataSetB = csvB),
+ view = FALSE, quiet = TRUE)
r1 <- res1$results
check(identical(res1$status, "complete"), "run 1 completed")
check(length(r1$dataSetOverview$schema$fields) == 5L, "dataset overview has 5 columns (id/title/rows/cols/columnNames)")
-nDataCols <- if (length(r1$dataSetOverview$data) > 0 && is.list(r1$dataSetOverview$data[[1]]) &&
- !all(names(r1$dataSetOverview$data[[1]]) %in% c("id","title","rows","cols","columnNames")))
- length(r1$dataSetOverview$data) else 5L
-check(nDataCols == 5L || length(r1$dataSetOverview$data) == nrow(r1$results$dataSetOverview$data),
- "dataset overview data laid out sanely (row-major or 5 column maps, no duplicates)")
ovId <- columnValues(r1$dataSetOverview, "id")
ovTitle <- columnValues(r1$dataSetOverview, "title")
ovCols <- columnValues(r1$dataSetOverview, "cols")
-check(identical(unname(ovId), c("11", "12")), "overview ids 11,12")
-check(identical(unname(ovTitle), c("DataSetA", "DataSetB")), "overview titles from dataSetNames attr")
+check(length(ovId) == 2L && all(grepl("^[0-9]+$", unname(ovId))), "overview ids are real (bridge) dataset ids")
+check(setequal(unname(ovTitle), c("DataSetA", "DataSetB")), "overview titles are the names from the datasets list")
check(all(ovCols == "3"), "both slices reported 3 columns")
-# the overview shows the ENCODED names (headless run: no engine sendString decode in between)
+# the overview shows DECODED names: the analysis saw JASPColumn_* tokens, jaspTools decoded
+# the whole results json on the way out (engine sendString equivalent).
ovNames <- columnValues(r1$dataSetOverview, "columnNames")
-check(all(c(paste(encA, collapse = ", "), paste(encB, collapse = ", ")) %in% unname(ovNames)),
- "overview column names are the encoded names the analysis received")
+check(all(c("Score, Age, Group", "Score, Age, Condition") %in% unname(ovNames)),
+ "overview column names came back decoded (encode -> decode roundtrip is real)")
sv <- r1$selectedVariables
svSrc <- columnValues(sv, "source")
@@ -106,33 +98,33 @@ svId <- columnValues(sv, "dataSetId")
svName <- columnValues(sv, "dataSetName")
svN <- columnValues(sv, "n")
svValues <- columnValues(sv, "values")
-check(all(c(encA[["Score"]], encA[["Group"]], encB[["Score"]], encB[["Age"]]) %in% svVar),
- "all four encoded dependents present in the routing table")
-for (v in c(encA[["Score"]], encA[["Group"]], encB[["Score"]], encB[["Age"]])) if (v %in% svVar) {
- i <- which(svVar == v)[1]
- expId <- if (v %in% encA) "11" else "12"
- expNm <- if (v %in% encA) "DataSetA" else "DataSetB"
- check(svId[i] == expId && svName[i] == expNm && svN[i] == "10" && nzchar(svValues[i]),
- paste0("routing ", v, " -> ", expNm, ", 10 rows, values computed (", svValues[i], ")"))
-}
-
-# numeric stats must correspond to the right slice: A/Score mean vs csv
-iScoreA <- which(svVar == encA[["Score"]])[1]
-check(grepl(sprintf("mean %.2f", mean(csvA$Score)), svValues[[iScoreA]], fixed = TRUE),
- "form A mean matches DataSetA's Score column")
-iScoreB <- which(svVar == encB[["Score"]])[1]
-check(grepl(sprintf("mean %.2f", mean(csvB$Score)), svValues[[iScoreB]], fixed = TRUE),
- "form B mean matches DataSetB's Score column (no cross-slice mixup)")
+check(all(unname(svVar) %in% c("Score", "Group", "Age", "Condition")), "routing table variables are plain names")
+
+rowFor <- function(src, var, dsTitle) which(svSrc == src & svVar == var & svName == dsTitle)
+iA <- rowFor("A", "Score", "DataSetA")
+iAg <- rowFor("A", "Group", "DataSetA")
+iB <- rowFor("B", "Score", "DataSetB")
+iBag <- rowFor("B", "Age", "DataSetB")
+check(length(iA) == 1L && length(iAg) == 1L && length(iB) == 1L && length(iBag) == 1L,
+ "four rows routed by (form, variable, dataset) - per-form selection honoured")
+check(length(c(iA, iAg, iB, iBag)) == 4L && all(svN[c(iA, iAg, iB, iBag)] == "10"), "every column computed over 10 rows")
+check(length(iA) == 1L && grepl(sprintf("mean %.2f", mean(csvA$Score)), svValues[[iA]], fixed = TRUE),
+ "form A Score = DataSetA's Score (mean matches csv)")
+check(length(iB) == 1L && grepl(sprintf("mean %.2f", mean(csvB$Score)), svValues[[iB]], fixed = TRUE),
+ "form B Score = DataSetB's Score (identically named column, no cross-slice mixup)")
+check(any(grepl(paste(utils::head(unique(as.character(csvA$Group)), 5), collapse = ", "), svValues[iAg], fixed = TRUE)),
+ "form A Group found in DataSetA")
+check(any(grepl(paste(utils::head(unique(as.character(csvB$Age)), 5), collapse = ", "), svValues[iBag], fixed = TRUE)),
+ "form B Age = DataSetB's Age (DataSetA's Age would show different levels)")
+check(all(unname(svId) %in% unname(ovId)), "routing dataSetIds agree with the overview ids")
raw1 <- jsonlite::toJSON(res1, auto_unbox = TRUE)
+check(!grepl("JASPColumn_", raw1), "no encoded tokens anywhere in the returned results (decoded on exit)")
check(grepl("not available in multi-dataset aware analyses", raw1, fixed = TRUE),
"guard demo: readDataSet() hard-stopped during the aware run")
# ------------------------------------------------------------------ Path 2: wrapper call -------
# The wrapper path is run in a clean Rscript subprocess (no jaspTools runtime in the way):
-# datasets= loads into the bridge workspace, the dataSetA/dataSetB options select each form's
-# dataset, the bridge encodes per dataset and queues slices - engine parity via the shared
-# DataBridge preparation. Exactly the RStudio/syntax-mode scenario the wrapper is made for.
cat("\n== Path 2: wrapper (datasets= named list + dataset selection options) ==\n")
path2Script <- file.path(moduledir, "Tools", "testMultiDataSet_wrapper.R")
status2 <- system2("Rscript", c(shQuote(path2Script)), stdout = TRUE, stderr = FALSE)
@@ -140,14 +132,18 @@ writeLines(status2)
check(any(grepl("MULTIDATASET-WRAPPER-OK", status2, fixed = TRUE)), "wrapper subprocess succeeded")
# ------------------------------------------------------------------ Path 3: legacy still OK ----
-cat("\n== Path 3: legacy non-aware run (no datasets) ==\n")
-res3 <- jaspTools::runAnalysis("multiDataSetFunc", dataset = datasets[["11"]],
- options = list(dependentA = encA[c("Score")], dependentB = encA[c("Age")],
- showMeta = FALSE, guardDemo = TRUE, plotWidth = 400, plotHeight = 300),
+cat("\n== Path 3: legacy non-aware run (single dataset, plain names) ==\n")
+res3 <- jaspTools::runAnalysis("multiDataSetFunc", dataset = csvA,
+ options = list(dependentA = "Score", dependentB = "Age",
+ showMeta = FALSE, guardDemo = TRUE,
+ plotWidth = 400, plotHeight = 300),
view = FALSE, quiet = TRUE)
raw3 <- jsonlite::toJSON(res3, auto_unbox = TRUE)
check(identical(res3$status, "complete"), "legacy run completed")
check(grepl("\\(current\\)", raw3), "legacy run used the single-dataset path (no multi mode)")
+check(grepl(sprintf("mean %.2f", mean(csvA$Score)), raw3, fixed = TRUE),
+ "legacy run computed DataSetA's Score mean through the bridge roundtrip")
+check(!grepl("JASPColumn_", raw3), "legacy results decoded too")
check(!grepl("not available in multi-dataset", raw3, fixed = TRUE),
"guard demo: readDataSet() works normally outside aware runs")
From 1eddaa06d89243b43cd1f518a13e9e56828c9609 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Fri, 9 Oct 2026 11:31:58 +0200
Subject: [PATCH 21/44] parity: paths 1+3 assert plain-name engine semantics
through the bridge
wanted-cols trimmed slices are the engine truth (the emulation's raw-csv 3/3
expectation was outdated); the legacy single-dataset path is now exercised via
multiDataSetNonAware since aware analyses always receive the slice queue.
All 32 checks green end to end; TODO records the parity state + known issues.
---
TODO-multidataset.md | 23 +++++++++++++++++++----
Tools/testMultiDataSet.R | 11 ++++++++---
2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/TODO-multidataset.md b/TODO-multidataset.md
index d1dae4e..4900bb8 100644
--- a/TODO-multidataset.md
+++ b/TODO-multidataset.md
@@ -40,10 +40,25 @@
(same spirit as the analysis-global behavior), never dangles (HostFilterSelection validates on
dataSetRemoved/filtersCountChanged).
-## NEXT PROJECT (approved by CTO 2026-10-08)
-jaspTools ⇄ jaspSyntax full bridge parity (hard dependency, kill the R emulation, encode like
-the engine, decode on exit): plan at
-`/home/virtuoos/.opencode/plan/jaspTools-bridge-parity.md` — STEP 0 there first (hook resolution).
+## jaspTools BRIDGE PARITY — DONE 2026-10-09 (plan: /home/virtuoos/.opencode/plan/jaspTools-bridge-parity.md)
+jaspTools::runAnalysis now runs the real SyntaxInterface bridge (hard dep on jaspSyntax):
+data loaded as genuine DataSets, options validated+encoded by the QML form (auto_unbox
+serialization!), filter-keyed slice queue, results decoded on exit via
+jaspSyntax::decodeJsonText. The R emulation (rbridge.R), encodedDataset and the generator's
+regex encoder family are DELETED — generated tests use plain names end to end.
+testMultiDataSet.R now asserts plain-name parity (this file's paths 1&3 were rewritten to it):
+- path 1: aware run through the bridge — real dataset ids, per-form selection honoured,
+ slices trimmed engine-style to the referenced columns (wanted-cols: Group+Score / Age+Score),
+ everything decoded again on exit;
+- path 3: single-dataset legacy semantics go through multiDataSetNonAware — an AWARE analysis
+ ALWAYS gets the slice queue now (correct engine semantics), and the bridge (like syntax mode)
+ rejects empty selection options rather than silently coercing them.
+Fixed on the way (were pre-existing branch bugs): segfault when an unnamed loadDataSet
+destroyed the workspace under cached QML forms (jasp-desktop 476b630dc); ColumnEncoderContext
+now carries the encode prefix so context replay survives dataset changes (jasp-desktop
+9fc29eb59). Known pre-existing, NOT chased: jaspSyntax test-desktop-jasp-contract
+readDatasetFromJaspFile hits a DataSet::dbLoad id assertion in the bridge subprocess (fails
+identically without the parity work); testDbMigration `:memory:` (older news).
## Review round 2026-10-08 (subagent review + user directives) - RESOLVED
- CRITICAL empty-GUI-tables: module tables were filled row-by-row with `:`-containing keys
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index 85fe716..c2438b8 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -83,12 +83,14 @@ ovTitle <- columnValues(r1$dataSetOverview, "title")
ovCols <- columnValues(r1$dataSetOverview, "cols")
check(length(ovId) == 2L && all(grepl("^[0-9]+$", unname(ovId))), "overview ids are real (bridge) dataset ids")
check(setequal(unname(ovTitle), c("DataSetA", "DataSetB")), "overview titles are the names from the datasets list")
-check(all(ovCols == "3"), "both slices reported 3 columns")
+# the queue hands slices trimmed to the columns the options reference (wanted-cols), exactly
+# as the engine's prepareMultiDataSetRun does - not the full csv.
+check(all(ovCols == "2"), "slices arrive trimmed to the referenced columns (engine wanted-cols)")
# the overview shows DECODED names: the analysis saw JASPColumn_* tokens, jaspTools decoded
# the whole results json on the way out (engine sendString equivalent).
ovNames <- columnValues(r1$dataSetOverview, "columnNames")
-check(all(c("Score, Age, Group", "Score, Age, Condition") %in% unname(ovNames)),
+check(all(c("Group, Score", "Age, Score") %in% unname(ovNames)),
"overview column names came back decoded (encode -> decode roundtrip is real)")
sv <- r1$selectedVariables
@@ -133,7 +135,10 @@ check(any(grepl("MULTIDATASET-WRAPPER-OK", status2, fixed = TRUE)), "wrapper sub
# ------------------------------------------------------------------ Path 3: legacy still OK ----
cat("\n== Path 3: legacy non-aware run (single dataset, plain names) ==\n")
-res3 <- jaspTools::runAnalysis("multiDataSetFunc", dataset = csvA,
+# The aware analysis ALWAYS gets the bridge slice queue now (engine semantics: multiDataSetJson
+# is produced whenever the Description says aware), so the legacy dataset/readDataSet path is
+# exercised through the module's non-aware counterpart - its qml has no dataset selection.
+res3 <- jaspTools::runAnalysis("multiDataSetNonAware", dataset = csvA,
options = list(dependentA = "Score", dependentB = "Age",
showMeta = FALSE, guardDemo = TRUE,
plotWidth = 400, plotHeight = 300),
From 3cd9540aeaf65c90f479cb22f01a3079821f836d Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Fri, 9 Oct 2026 14:49:25 +0200
Subject: [PATCH 22/44] buildBundle checklist drops getDataSetColumn (deleted,
zero-export round 1)
---
Tools/buildBundle.R | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index dae512a..32e04d3 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -215,7 +215,7 @@ suppressPackageStartupMessages(library(jaspBase, lib.loc = file.path(checkdir, "
if (localJaspBase) {
expected <- c("dataSetIdFromEncoded", "dataSetNameFromEncoded", "getDataSetFor",
- "getDataSetColumn", "storeDataSets")
+ "storeDataSets")
markers <- stats::setNames(expected %in% getNamespaceExports("jaspBase"), expected)
runBody <- any(grepl("multiDataSet", deparse(body(jaspBase::runJaspResults))))
if (!all(markers) || !runBody)
From 2dab3fe8a3c3b758b5b294e2f227e6fc991985cc Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Fri, 9 Oct 2026 15:53:18 +0200
Subject: [PATCH 23/44] reference analysis + wrapper + bundle check:
zero-export contract
multiDataSet.R indexes datasets[[selectionOptionValue]] directly and reads
dataset id/title off the attrs - the reference now demonstrates the contract
rather than an accessor API. The wrapper's redundant storeDataSets call goes
(runWrappedAnalysis loads through the bridge itself). buildBundle.R's jaspBase
check is inverted from 'carries these exports' to 'leaks none of them'.
---
R/multiDataSet.R | 17 ++++++++++-------
R/multiDataSetFuncWrapper.R | 4 ----
Tools/buildBundle.R | 18 ++++++++++--------
3 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/R/multiDataSet.R b/R/multiDataSet.R
index c103268..43d49fb 100644
--- a/R/multiDataSet.R
+++ b/R/multiDataSet.R
@@ -84,11 +84,14 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
list(form = "B", sel = "dataSetB", values = .dependentValues(options$dependentB)))) {
for (value in entry$values) {
- # The form's own selection (a filter id) picks the slice its variables live in - two forms
- # on one dataset with different filters then see different rows. Handout runs (jaspTools)
- # carry no filter-keyed selection, so route by the dataset id embedded in the name there
- # (loudly ambiguous when that dataset has several slices - never silently the first!).
- key <- if (is.null(datasets)) NULL else jaspBase::getSliceKey(options, datasets, entry$sel, column = value)
+ # The contract, no accessors: datasets is keyed by FILTER id and the form's dataset
+ # selection option holds exactly that id, so the option IS the key - two forms on one
+ # dataset with different filters index different slices. attrs dataSetIds/dataSetNames
+ # map a key to its dataset (titles are display-only: user-editable, never a key).
+ key <- if (is.null(datasets)) NULL else {
+ sel <- trimws(as.character(utils::tail(unlist(options[[entry$sel]]), 1L)))
+ if (is.na(sel) || !nzchar(sel) || !sel %in% names(datasets)) NULL else sel
+ }
slice <- if (is.null(datasets)) dataset else if (!is.null(key)) datasets[[key]] else NULL
columnData <- if (!is.null(slice) && value %in% names(slice)) slice[[value]] else NULL
@@ -96,8 +99,8 @@ selectedVariablesTable <- function(jaspResults, options, datasets, dataset) {
row <- list(
source = entry$form,
variable = value,
- dataSetId = if (is.null(datasets)) "-" else if (is.null(key)) as.character(jaspBase::dataSetIdFromEncoded(value)) else jaspBase::sliceDataSetId(datasets, key),
- dataSetName = if (is.null(datasets)) "-" else if (is.null(key)) jaspBase::dataSetNameFromEncoded(value, datasets) else jaspBase::sliceTitle(datasets, key),
+ dataSetId = if (is.null(key)) "-" else as.character(attr(datasets, "dataSetIds")[[key]]),
+ dataSetName = if (is.null(key)) "-" else as.character(attr(datasets, "dataSetNames")[[key]]),
n = NA_integer_, values = "")
if (!is.null(columnData))
diff --git a/R/multiDataSetFuncWrapper.R b/R/multiDataSetFuncWrapper.R
index 69bf3ac..5b970c6 100644
--- a/R/multiDataSetFuncWrapper.R
+++ b/R/multiDataSetFuncWrapper.R
@@ -41,10 +41,6 @@ multiDataSetFunc <- function(
options[["version"]] <- NULL
- if (!jaspBase::jaspResultsCalledFromJasp() && !is.null(datasets)) {
- jaspBase::storeDataSets(datasets)
- }
-
data <- if (!is.null(datasets) && length(datasets)) datasets[[1]] else NULL
optionsWithFormula <- c("dataSetA", "dataSetB", "dependentA", "dependentB")
diff --git a/Tools/buildBundle.R b/Tools/buildBundle.R
index 32e04d3..611db66 100644
--- a/Tools/buildBundle.R
+++ b/Tools/buildBundle.R
@@ -214,14 +214,16 @@ archive::archive_extract(file.path(checkdir, jaspBaseHash), dir = pkgdir)
suppressPackageStartupMessages(library(jaspBase, lib.loc = file.path(checkdir, "lib")))
if (localJaspBase) {
- expected <- c("dataSetIdFromEncoded", "dataSetNameFromEncoded", "getDataSetFor",
- "storeDataSets")
- markers <- stats::setNames(expected %in% getNamespaceExports("jaspBase"), expected)
- runBody <- any(grepl("multiDataSet", deparse(body(jaspBase::runJaspResults))))
- if (!all(markers) || !runBody)
- stop("bundled jaspBase is MISSING the local multiDataSetAware code (missing exports: ",
- paste(names(markers)[!markers], collapse = ", "), if (runBody) "" else " + runJaspResults body", ")")
- message("VERIFIED: bundled jaspBase loads and carries the local multiDataSetAware code.")
+ # Zero-export contract (CTO 2026-10-09): the multi-dataset machinery ships NO accessor
+ # exports - analyses index datasets[[filter-id-key]] directly. Any reappearance fails here.
+ forbidden <- c("getSliceKey", "getSlice", "sliceDataSetId", "sliceTitle", "getDataSetFor",
+ "getDataSetColumn", "dataSetIdFromEncoded", "dataSetNameFromEncoded", "storeDataSets")
+ leaked <- intersect(forbidden, getNamespaceExports("jaspBase"))
+ runBody <- any(grepl("multiDataSetJson", deparse(body(jaspBase::runJaspResults))))
+ if (length(leaked) || !runBody)
+ stop("bundled jaspBase violates the zero-export contract (leaked exports: ",
+ paste(leaked, collapse = ", "), if (runBody) "" else " + runJaspResults has no multiDataSetJson flow", ")")
+ message("VERIFIED: bundled jaspBase loads, queue flow present, zero leaked accessor exports.")
} else {
message("bundle jaspBase version: ", as.character(utils::packageVersion("jaspBase", lib.loc = file.path(checkdir, "lib"))))
}
From 7daf19572643b2598d45174eba0c92b5fb6b0443 Mon Sep 17 00:00:00 2001
From: Virtuoos Automatisch
Date: Fri, 9 Oct 2026 16:33:16 +0200
Subject: [PATCH 24/44] Track C checks: loadDataSets ids, dataset-id
selections, loud rejections
---
Tools/testMultiDataSet.R | 36 ++++++++++++++++++++++++++++++++
Tools/testMultiDataSet_wrapper.R | 4 ++--
2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/Tools/testMultiDataSet.R b/Tools/testMultiDataSet.R
index c2438b8..0be86eb 100644
--- a/Tools/testMultiDataSet.R
+++ b/Tools/testMultiDataSet.R
@@ -125,6 +125,42 @@ check(!grepl("JASPColumn_", raw1), "no encoded tokens anywhere in the returned r
check(grepl("not available in multi-dataset aware analyses", raw1, fixed = TRUE),
"guard demo: readDataSet() hard-stopped during the aware run")
+# ------------------------------------------------------------------ Bridge ids (Track C) ----
+cat("\n== Bridge boundary: loadDataSets returns dataset ids; selections accept them ==\n")
+# Titles stay the outer-surface sugar; INSIDE the wrapper everything keys on integer ids. The
+# loaders hand back the real database ids so a syntax script can refer to datasets by the
+# invariant instead of a title the user could rename mid-session.
+ids <- jaspSyntax::loadDataSets(list(DataSetA = csvA, DataSetB = csvB))
+check(is.integer(ids) && length(ids) == 2L && identical(names(ids), c("DataSetA", "DataSetB")) && all(ids > 0),
+ "loadDataSets returns the named integer dataset ids")
+
+qmlFile <- file.path(find.package("jaspTestModule"), "qml", "testMultiDataSet.qml")
+parseSelection <- function(selA, selB) {
+ opts <- list(dependentA = c("Score", "Group"), dependentB = c("Score", "Age"),
+ dataSetA = selA, dataSetB = selB,
+ showMeta = FALSE, guardDemo = FALSE, plotWidth = 400, plotHeight = 300)
+ jaspSyntax::loadQmlAndParseOptionsStatus("jaspTestModule", "multiDataSetFunc", qmlFile,
+ as.character(jsonlite::toJSON(opts, auto_unbox = TRUE, digits = NA, null = "null")), "1", TRUE)
+}
+
+stId <- tryCatch(parseSelection(as.integer(ids[[1]]), as.integer(ids[[2]])), error = function(e) e)
+check(!inherits(stId, "error") && nzchar(stId$options), "integer DATASET-id selections parse through the bridge")
+parsed <- jsonlite::fromJSON(stId$options, simplifyVector = FALSE)
+keyA <- as.character(utils::tail(unlist(parsed$dataSetA), 1L))
+keyB <- as.character(utils::tail(unlist(parsed$dataSetB), 1L))
+msj <- jsonlite::fromJSON(stId$multiDataSetJson)
+check(all(c(keyA, keyB) %in% as.character(msj$ids)) && keyA != keyB,
+ "id selections resolved to two distinct queued slice keys (filter-id key space)")
+check(identical(as.character(msj$dataSetIds[[keyA]]), as.character(ids[[1]])),
+ "the slice an id selected belongs to exactly that dataset")
+
+errBadTitle <- tryCatch({ parseSelection("NoSuchDataSet", as.integer(ids[[2]])); "" }, error = function(e) conditionMessage(e))
+check(grepl("neither the title nor the id", errBadTitle),
+ "an unknown title is rejected loudly (error lists what is loaded)")
+errBadId <- tryCatch({ parseSelection(999L, 998L); "" }, error = function(e) conditionMessage(e))
+check(grepl("neither the title nor the id", errBadId),
+ "an unknown integer is rejected too - no filter-id guessing (1 is not both a dataset and a filter)")
+
# ------------------------------------------------------------------ Path 2: wrapper call -------
# The wrapper path is run in a clean Rscript subprocess (no jaspTools runtime in the way):
cat("\n== Path 2: wrapper (datasets= named list + dataset selection options) ==\n")
diff --git a/Tools/testMultiDataSet_wrapper.R b/Tools/testMultiDataSet_wrapper.R
index e81ebfd..b9f2a14 100644
--- a/Tools/testMultiDataSet_wrapper.R
+++ b/Tools/testMultiDataSet_wrapper.R
@@ -6,8 +6,8 @@
#
# Flow under test: loadDataSets -> workspace (titles, ids, encoders) -> QML binds the selection
# options first (depends), switching each form; column options then encode per dataset and the
-# bridge queues one slice per dataset; runJaspResults hands the analysis encoded options +
-# encoded slices keyed by (bridge) dataset id, with the user names as titles.
+# bridge queues one slice per distinct filter; runJaspResults hands the analysis encoded options +
+# encoded slices keyed by FILTER id (the selection option value), titles in attr dataSetNames.
moduledir <- normalizePath(file.path(dirname(sub("^--file=", "", grep("^--file=", commandArgs(FALSE), value = TRUE)[[1]])), ".."))
pkglib <- Sys.getenv("JASP_TEST_PKGLIB", file.path(moduledir, "ModuleBundleBuildDir", "build_dir", "jaspTestModule"))
From c639c33731cda59e73e8bac62243d481e2268a9d Mon Sep 17 00:00:00 2001
From: Joris Goosen
Date: Mon, 12 Oct 2026 13:56:16 +0200
Subject: [PATCH 25/44] make it compile on macos arm
---
renv.lock | 3271 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 2805 insertions(+), 466 deletions(-)
diff --git a/renv.lock b/renv.lock
index f4558d1..5be3507 100644
--- a/renv.lock
+++ b/renv.lock
@@ -1,10 +1,9 @@
-{
- "R": {
- "Version": "4.6.1",
+{ "R": {
+ "Version": "4.5.3",
"Repositories": [
{
"Name": "CRAN",
- "URL": "https://cloud.r-project.org"
+ "URL": "https://packagemanager.posit.co/cran/latest"
}
]
},
@@ -13,418 +12,1387 @@
"Package": "R6",
"Version": "2.6.1",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Title": "Encapsulated Classes with Reference Semantics",
+ "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Creates classes with reference semantics, similar to R's built-in reference classes. Compared to reference classes, R6 classes are simpler and lighter-weight, and they are not built on S4 classes so they do not require the methods package. These classes allow public and private members, and they support inheritance, even when the classes are defined in different packages.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://r6.r-lib.org, https://github.com/r-lib/R6",
+ "BugReports": "https://github.com/r-lib/R6/issues",
+ "Depends": [
+ "R (>= 3.6)"
+ ],
+ "Suggests": [
+ "lobstr",
+ "testthat (>= 3.0.0)"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate, ggplot2, microbenchmark, scales",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Winston Chang ",
+ "Repository": "CRAN"
},
"RColorBrewer": {
"Package": "RColorBrewer",
"Version": "1.1-3",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Date": "2022-04-03",
+ "Title": "ColorBrewer Palettes",
+ "Authors@R": "c(person(given = \"Erich\", family = \"Neuwirth\", role = c(\"aut\", \"cre\"), email = \"erich.neuwirth@univie.ac.at\"))",
+ "Author": "Erich Neuwirth [aut, cre]",
+ "Maintainer": "Erich Neuwirth ",
+ "Depends": [
+ "R (>= 2.0.0)"
+ ],
+ "Description": "Provides color schemes for maps (and other graphics) designed by Cynthia Brewer as described at http://colorbrewer2.org.",
+ "License": "Apache License 2.0",
+ "NeedsCompilation": "no",
+ "Repository": "CRAN"
},
"Rcpp": {
"Package": "Rcpp",
- "Version": "1.1.2",
- "Source": "Repository",
- "Requirements": [
+ "Version": "1.1.1",
+ "Source": "Repository",
+ "Title": "Seamless R and C++ Integration",
+ "Date": "2026-01-07",
+ "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Romain\", \"Francois\", role = \"aut\", comment = c(ORCID = \"0000-0002-2444-4226\")), person(\"JJ\", \"Allaire\", role = \"aut\", comment = c(ORCID = \"0000-0003-0174-9868\")), person(\"Kevin\", \"Ushey\", role = \"aut\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Qiang\", \"Kou\", role = \"aut\", comment = c(ORCID = \"0000-0001-6786-5453\")), person(\"Nathan\", \"Russell\", role = \"aut\"), person(\"Iñaki\", \"Ucar\", role = \"aut\", comment = c(ORCID = \"0000-0001-6403-5550\")), person(\"Doug\", \"Bates\", role = \"aut\", comment = c(ORCID = \"0000-0001-8316-9503\")), person(\"John\", \"Chambers\", role = \"aut\"))",
+ "Description": "The 'Rcpp' package provides R functions as well as C++ classes which offer a seamless integration of R and C++. Many R data types and objects can be mapped back and forth to C++ equivalents which facilitates both writing of new code as well as easier integration of third-party libraries. Documentation about 'Rcpp' is provided by several vignettes included in this package, via the 'Rcpp Gallery' site at , the paper by Eddelbuettel and Francois (2011, ), the book by Eddelbuettel (2013, ) and the paper by Eddelbuettel and Balamuta (2018, ); see 'citation(\"Rcpp\")' for details.",
+ "Depends": [
+ "R (>= 3.5.0)"
+ ],
+ "Imports": [
"methods",
- "R",
"utils"
- ]
+ ],
+ "Suggests": [
+ "tinytest",
+ "inline",
+ "rbenchmark",
+ "pkgKitten (>= 0.1.2)"
+ ],
+ "URL": "https://www.rcpp.org, https://dirk.eddelbuettel.com/code/rcpp.html, https://github.com/RcppCore/Rcpp",
+ "License": "GPL (>= 2)",
+ "BugReports": "https://github.com/RcppCore/Rcpp/issues",
+ "MailingList": "rcpp-devel@lists.r-forge.r-project.org",
+ "RoxygenNote": "6.1.1",
+ "Encoding": "UTF-8",
+ "VignetteBuilder": "Rcpp",
+ "NeedsCompilation": "yes",
+ "Author": "Dirk Eddelbuettel [aut, cre] (ORCID: ), Romain Francois [aut] (ORCID: ), JJ Allaire [aut] (ORCID: ), Kevin Ushey [aut] (ORCID: ), Qiang Kou [aut] (ORCID: ), Nathan Russell [aut], Iñaki Ucar [aut] (ORCID: ), Doug Bates [aut] (ORCID: ), John Chambers [aut]",
+ "Maintainer": "Dirk Eddelbuettel ",
+ "Repository": "CRAN"
},
"S7": {
"Package": "S7",
- "Version": "0.2.2",
+ "Version": "0.2.1",
"Source": "Repository",
- "Requirements": [
- "R",
+ "Title": "An Object Oriented System Meant to Become a Successor to S3 and S4",
+ "Authors@R": "c( person(\"Object-Oriented Programming Working Group\", role = \"cph\"), person(\"Davis\", \"Vaughan\", role = \"aut\"), person(\"Jim\", \"Hester\", role = \"aut\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Tomasz\", \"Kalinowski\", role = \"aut\"), person(\"Will\", \"Landau\", role = \"aut\"), person(\"Michael\", \"Lawrence\", role = \"aut\"), person(\"Martin\", \"Maechler\", role = \"aut\", comment = c(ORCID = \"0000-0002-8685-9910\")), person(\"Luke\", \"Tierney\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-4757-117X\")) )",
+ "Description": "A new object oriented programming system designed to be a successor to S3 and S4. It includes formal class, generic, and method specification, and a limited form of multiple dispatch. It has been designed and implemented collaboratively by the R Consortium Object-Oriented Programming Working Group, which includes representatives from R-Core, 'Bioconductor', 'Posit'/'tidyverse', and the wider R community.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rconsortium.github.io/S7/, https://github.com/RConsortium/S7",
+ "BugReports": "https://github.com/RConsortium/S7/issues",
+ "Depends": [
+ "R (>= 3.5.0)"
+ ],
+ "Imports": [
"utils"
- ]
+ ],
+ "Suggests": [
+ "bench",
+ "callr",
+ "covr",
+ "knitr",
+ "methods",
+ "rmarkdown",
+ "testthat (>= 3.2.0)",
+ "tibble"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "sloop",
+ "Config/testthat/edition": "3",
+ "Config/testthat/parallel": "TRUE",
+ "Config/testthat/start-first": "external-generic",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "yes",
+ "Author": "Object-Oriented Programming Working Group [cph], Davis Vaughan [aut], Jim Hester [aut] (ORCID: ), Tomasz Kalinowski [aut], Will Landau [aut], Michael Lawrence [aut], Martin Maechler [aut] (ORCID: ), Luke Tierney [aut], Hadley Wickham [aut, cre] (ORCID: )",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"askpass": {
"Package": "askpass",
"Version": "1.2.1",
"Source": "Repository",
- "Requirements": [
- "sys"
- ]
+ "Type": "Package",
+ "Title": "Password Entry Utilities for R, Git, and SSH",
+ "Authors@R": "person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\"))",
+ "Description": "Cross-platform utilities for prompting the user for credentials or a passphrase, for example to authenticate with a server or read a protected key. Includes native programs for MacOS and Windows, hence no 'tcltk' is required. Password entry can be invoked in two different ways: directly from R via the askpass() function, or indirectly as password-entry back-end for 'ssh-agent' or 'git-credential' via the SSH_ASKPASS and GIT_ASKPASS environment variables. Thereby the user can be prompted for credentials or a passphrase if needed when R calls out to git or ssh.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://r-lib.r-universe.dev/askpass",
+ "BugReports": "https://github.com/r-lib/askpass/issues",
+ "Encoding": "UTF-8",
+ "Imports": [
+ "sys (>= 2.1)"
+ ],
+ "RoxygenNote": "7.2.3",
+ "Suggests": [
+ "testthat"
+ ],
+ "Language": "en-US",
+ "NeedsCompilation": "yes",
+ "Author": "Jeroen Ooms [aut, cre] ()",
+ "Maintainer": "Jeroen Ooms ",
+ "Repository": "CRAN"
},
"base64enc": {
"Package": "base64enc",
"Version": "0.1-6",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Title": "Tools for 'base64' Encoding",
+ "Author": "Simon Urbanek [aut, cre, cph] (https://urbanek.nz, ORCID: )",
+ "Authors@R": "person(\"Simon\", \"Urbanek\", role=c(\"aut\",\"cre\",\"cph\"), email=\"Simon.Urbanek@r-project.org\", comment=c(\"https://urbanek.nz\", ORCID=\"0000-0003-2297-1732\"))",
+ "Maintainer": "Simon Urbanek ",
+ "Depends": [
+ "R (>= 2.9.0)"
+ ],
+ "Enhances": [
+ "png"
+ ],
+ "Description": "Tools for handling 'base64' encoding. It is more flexible than the orphaned 'base64' package.",
+ "License": "GPL-2 | GPL-3",
+ "URL": "https://www.rforge.net/base64enc",
+ "BugReports": "https://github.com/s-u/base64enc/issues",
+ "NeedsCompilation": "yes",
+ "Repository": "CRAN"
},
"bslib": {
"Package": "bslib",
- "Version": "0.12.0",
- "Source": "Repository",
- "Requirements": [
+ "Version": "0.10.0",
+ "Source": "Repository",
+ "Title": "Custom 'Bootstrap' 'Sass' Themes for 'shiny' and 'rmarkdown'",
+ "Authors@R": "c( person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Garrick\", \"Aden-Buie\", , \"garrick@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-7111-0077\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Javi\", \"Aguilar\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap colorpicker library\"), person(\"Thomas\", \"Park\", role = c(\"ctb\", \"cph\"), comment = \"Bootswatch library\"), person(, \"PayPal\", role = c(\"ctb\", \"cph\"), comment = \"Bootstrap accessibility plugin\") )",
+ "Description": "Simplifies custom 'CSS' styling of both 'shiny' and 'rmarkdown' via 'Bootstrap' 'Sass'. Supports 'Bootstrap' 3, 4 and 5 as well as their various 'Bootswatch' themes. An interactive widget is also provided for previewing themes in real time.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rstudio.github.io/bslib/, https://github.com/rstudio/bslib",
+ "BugReports": "https://github.com/rstudio/bslib/issues",
+ "Depends": [
+ "R (>= 2.10)"
+ ],
+ "Imports": [
"base64enc",
"cachem",
- "fastmap",
+ "fastmap (>= 1.1.1)",
"grDevices",
- "htmltools",
- "jquerylib",
+ "htmltools (>= 0.5.8)",
+ "jquerylib (>= 0.1.3)",
"jsonlite",
"lifecycle",
- "memoise",
+ "memoise (>= 2.0.1)",
"mime",
- "R",
"rlang",
- "sass"
- ]
+ "sass (>= 0.4.9)"
+ ],
+ "Suggests": [
+ "brand.yml",
+ "bsicons",
+ "curl",
+ "fontawesome",
+ "future",
+ "ggplot2",
+ "knitr",
+ "lattice",
+ "magrittr",
+ "rappdirs",
+ "rmarkdown (>= 2.7)",
+ "shiny (>= 1.11.1)",
+ "testthat",
+ "thematic",
+ "tools",
+ "utils",
+ "withr",
+ "yaml"
+ ],
+ "Config/Needs/deploy": "BH, chiflights22, colourpicker, commonmark, cpp11, cpsievert/chiflights22, cpsievert/histoslider, dplyr, DT, ggplot2, ggridges, gt, hexbin, histoslider, htmlwidgets, lattice, leaflet, lubridate, markdown, modelr, plotly, reactable, reshape2, rprojroot, rsconnect, rstudio/shiny, scales, styler, tibble",
+ "Config/Needs/routine": "chromote, desc, renv",
+ "Config/Needs/website": "brio, crosstalk, dplyr, DT, ggplot2, glue, htmlwidgets, leaflet, lorem, palmerpenguins, plotly, purrr, rprojroot, rstudio/htmltools, scales, stringr, tidyr, webshot2",
+ "Config/testthat/edition": "3",
+ "Config/testthat/parallel": "true",
+ "Config/testthat/start-first": "zzzz-bs-sass, fonts, zzz-precompile, theme-*, rmd-*",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "Collate": "'accordion.R' 'breakpoints.R' 'bs-current-theme.R' 'bs-dependencies.R' 'bs-global.R' 'bs-remove.R' 'bs-theme-layers.R' 'bs-theme-preset-bootswatch.R' 'bs-theme-preset-brand.R' 'bs-theme-preset-builtin.R' 'bs-theme-preset.R' 'utils.R' 'bs-theme-preview.R' 'bs-theme-update.R' 'bs-theme.R' 'bslib-package.R' 'buttons.R' 'card.R' 'deprecated.R' 'files.R' 'fill.R' 'imports.R' 'input-code-editor.R' 'input-dark-mode.R' 'input-submit.R' 'input-switch.R' 'layout.R' 'nav-items.R' 'nav-update.R' 'navbar_options.R' 'navs-legacy.R' 'navs.R' 'onLoad.R' 'page.R' 'popover.R' 'precompiled.R' 'print.R' 'shiny-devmode.R' 'sidebar.R' 'staticimports.R' 'toast.R' 'tooltip.R' 'utils-deps.R' 'utils-shiny.R' 'utils-tags.R' 'value-box.R' 'version-default.R' 'versions.R'",
+ "NeedsCompilation": "no",
+ "Author": "Carson Sievert [aut, cre] (ORCID: ), Joe Cheng [aut], Garrick Aden-Buie [aut] (ORCID: ), Posit Software, PBC [cph, fnd], Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Javi Aguilar [ctb, cph] (Bootstrap colorpicker library), Thomas Park [ctb, cph] (Bootswatch library), PayPal [ctb, cph] (Bootstrap accessibility plugin)",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"cachem": {
"Package": "cachem",
"Version": "1.1.0",
"Source": "Repository",
- "Requirements": [
- "fastmap",
- "rlang"
- ]
+ "Title": "Cache R Objects with Automatic Pruning",
+ "Description": "Key-value stores with automatic pruning. Caches can limit either their total size or the age of the oldest object (or both), automatically pruning objects to maintain the constraints.",
+ "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", c(\"aut\", \"cre\")), person(family = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")))",
+ "License": "MIT + file LICENSE",
+ "Encoding": "UTF-8",
+ "ByteCompile": "true",
+ "URL": "https://cachem.r-lib.org/, https://github.com/r-lib/cachem",
+ "Imports": [
+ "rlang",
+ "fastmap (>= 1.2.0)"
+ ],
+ "Suggests": [
+ "testthat"
+ ],
+ "RoxygenNote": "7.2.3",
+ "Config/Needs/routine": "lobstr",
+ "Config/Needs/website": "pkgdown",
+ "NeedsCompilation": "yes",
+ "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Winston Chang ",
+ "Repository": "CRAN"
},
"callr": {
"Package": "callr",
- "Version": "3.8.0",
- "Source": "Repository",
- "Requirements": [
- "otel",
- "processx",
- "R",
+ "Version": "3.7.6",
+ "Source": "Repository",
+ "Title": "Call R from R",
+ "Authors@R": "c( person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\", \"cph\"), comment = c(ORCID = \"0000-0001-7098-9676\")), person(\"Winston\", \"Chang\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(\"Ascent Digital Services\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "It is sometimes useful to perform a computation in a separate R process, without affecting the current R process at all. This packages does exactly that.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://callr.r-lib.org, https://github.com/r-lib/callr",
+ "BugReports": "https://github.com/r-lib/callr/issues",
+ "Depends": [
+ "R (>= 3.4)"
+ ],
+ "Imports": [
+ "processx (>= 3.6.1)",
"R6",
"utils"
- ]
+ ],
+ "Suggests": [
+ "asciicast (>= 2.3.1)",
+ "cli (>= 1.1.0)",
+ "mockery",
+ "ps",
+ "rprojroot",
+ "spelling",
+ "testthat (>= 3.2.0)",
+ "withr (>= 2.3.0)"
+ ],
+ "Config/Needs/website": "r-lib/asciicast, glue, htmlwidgets, igraph, tibble, tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "Language": "en-US",
+ "RoxygenNote": "7.3.1.9000",
+ "NeedsCompilation": "no",
+ "Author": "Gábor Csárdi [aut, cre, cph] (), Winston Chang [aut], Posit Software, PBC [cph, fnd], Ascent Digital Services [cph, fnd]",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"cli": {
"Package": "cli",
- "Version": "3.6.6",
- "Source": "Repository",
- "Requirements": [
- "R",
+ "Version": "3.6.5",
+ "Source": "Repository",
+ "Title": "Helpers for Developing Command Line Interfaces",
+ "Authors@R": "c( person(\"Gábor\", \"Csárdi\", , \"gabor@posit.co\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Kirill\", \"Müller\", role = \"ctb\"), person(\"Salim\", \"Brüggemann\", , \"salim-b@pm.me\", role = \"ctb\", comment = c(ORCID = \"0000-0002-5329-5987\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "A suite of tools to build attractive command line interfaces ('CLIs'), from semantic elements: headings, lists, alerts, paragraphs, etc. Supports custom themes via a 'CSS'-like language. It also contains a number of lower level 'CLI' elements: rules, boxes, trees, and 'Unicode' symbols with 'ASCII' alternatives. It support ANSI colors and text styles as well.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://cli.r-lib.org, https://github.com/r-lib/cli",
+ "BugReports": "https://github.com/r-lib/cli/issues",
+ "Depends": [
+ "R (>= 3.4)"
+ ],
+ "Imports": [
"utils"
- ]
+ ],
+ "Suggests": [
+ "callr",
+ "covr",
+ "crayon",
+ "digest",
+ "glue (>= 1.6.0)",
+ "grDevices",
+ "htmltools",
+ "htmlwidgets",
+ "knitr",
+ "methods",
+ "processx",
+ "ps (>= 1.3.4.9000)",
+ "rlang (>= 1.0.2.9003)",
+ "rmarkdown",
+ "rprojroot",
+ "rstudioapi",
+ "testthat (>= 3.2.0)",
+ "tibble",
+ "whoami",
+ "withr"
+ ],
+ "Config/Needs/website": "r-lib/asciicast, bench, brio, cpp11, decor, desc, fansi, prettyunits, sessioninfo, tidyverse/tidytemplate, usethis, vctrs",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "yes",
+ "Author": "Gábor Csárdi [aut, cre], Hadley Wickham [ctb], Kirill Müller [ctb], Salim Brüggemann [ctb] (), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"codetools": {
"Package": "codetools",
"Version": "0.2-20",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Priority": "recommended",
+ "Author": "Luke Tierney ",
+ "Description": "Code analysis tools for R.",
+ "Title": "Code Analysis Tools for R",
+ "Depends": [
+ "R (>= 2.1)"
+ ],
+ "Maintainer": "Luke Tierney ",
+ "URL": "https://gitlab.com/luke-tierney/codetools",
+ "License": "GPL",
+ "NeedsCompilation": "no",
+ "Repository": "CRAN"
},
"cpp11": {
"Package": "cpp11",
- "Version": "0.5.5",
+ "Version": "0.5.3",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Title": "A C++11 Interface for R's C Interface",
+ "Authors@R": "c( person(\"Davis\", \"Vaughan\", email = \"davis@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-4777-038X\")), person(\"Jim\",\"Hester\", role = \"aut\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Romain\", \"François\", role = \"aut\", comment = c(ORCID = \"0000-0002-2444-4226\")), person(\"Benjamin\", \"Kietzman\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Provides a header only, C++11 interface to R's C interface. Compared to other approaches 'cpp11' strives to be safe against long jumps from the C API as well as C++ exceptions, conform to normal R function semantics and supports interaction with 'ALTREP' vectors.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://cpp11.r-lib.org, https://github.com/r-lib/cpp11",
+ "BugReports": "https://github.com/r-lib/cpp11/issues",
+ "Depends": [
+ "R (>= 4.0.0)"
+ ],
+ "Suggests": [
+ "bench",
+ "brio",
+ "callr",
+ "cli",
+ "covr",
+ "decor",
+ "desc",
+ "ggplot2",
+ "glue",
+ "knitr",
+ "lobstr",
+ "mockery",
+ "progress",
+ "rmarkdown",
+ "scales",
+ "Rcpp",
+ "testthat (>= 3.2.0)",
+ "tibble",
+ "utils",
+ "vctrs",
+ "withr"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/Needs/cpp11/cpp_register": "brio, cli, decor, desc, glue, tibble, vctrs",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Davis Vaughan [aut, cre] (ORCID: ), Jim Hester [aut] (ORCID: ), Romain François [aut] (ORCID: ), Benjamin Kietzman [ctb], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Davis Vaughan ",
+ "Repository": "CRAN"
},
"crosstalk": {
"Package": "crosstalk",
"Version": "1.2.2",
"Source": "Repository",
- "Requirements": [
- "htmltools",
+ "Type": "Package",
+ "Title": "Inter-Widget Interactivity for HTML Widgets",
+ "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"jQuery Foundation\", role = \"cph\", comment = \"jQuery library and jQuery UI library\"), person(, \"jQuery contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt\"), person(\"Mark\", \"Otto\", role = \"ctb\", comment = \"Bootstrap library\"), person(\"Jacob\", \"Thornton\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Brian\", \"Reavis\", role = c(\"ctb\", \"cph\"), comment = \"selectize.js library\"), person(\"Kristopher Michael\", \"Kowal\", role = c(\"ctb\", \"cph\"), comment = \"es5-shim library\"), person(, \"es5-shim contributors\", role = c(\"ctb\", \"cph\"), comment = \"es5-shim library\"), person(\"Denis\", \"Ineshin\", role = c(\"ctb\", \"cph\"), comment = \"ion.rangeSlider library\"), person(\"Sami\", \"Samhuri\", role = c(\"ctb\", \"cph\"), comment = \"Javascript strftime library\") )",
+ "Description": "Provides building blocks for allowing HTML widgets to communicate with each other, with Shiny or without (i.e. static .html files). Currently supports linked brushing and filtering.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rstudio.github.io/crosstalk/, https://github.com/rstudio/crosstalk",
+ "BugReports": "https://github.com/rstudio/crosstalk/issues",
+ "Imports": [
+ "htmltools (>= 0.3.6)",
"jsonlite",
"lazyeval",
"R6"
- ]
+ ],
+ "Suggests": [
+ "bslib",
+ "ggplot2",
+ "sass",
+ "shiny",
+ "testthat (>= 2.1.0)"
+ ],
+ "Config/Needs/website": "jcheng5/d3scatter, DT, leaflet, rmarkdown",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Joe Cheng [aut], Carson Sievert [aut, cre] (ORCID: ), Posit Software, PBC [cph, fnd], jQuery Foundation [cph] (jQuery library and jQuery UI library), jQuery contributors [ctb, cph] (jQuery library; authors listed in inst/www/shared/jquery-AUTHORS.txt), Mark Otto [ctb] (Bootstrap library), Jacob Thornton [ctb] (Bootstrap library), Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Brian Reavis [ctb, cph] (selectize.js library), Kristopher Michael Kowal [ctb, cph] (es5-shim library), es5-shim contributors [ctb, cph] (es5-shim library), Denis Ineshin [ctb, cph] (ion.rangeSlider library), Sami Samhuri [ctb, cph] (Javascript strftime library)",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"curl": {
"Package": "curl",
- "Version": "8.0.0",
- "Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Version": "7.0.0",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "A Modern and Flexible Web Client for R",
+ "Authors@R": "c( person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Posit Software, PBC\", role = \"cph\"))",
+ "Description": "Bindings to 'libcurl' for performing fully configurable HTTP/FTP requests where responses can be processed in memory, on disk, or streaming via the callback or connection interfaces. Some knowledge of 'libcurl' is recommended; for a more-user-friendly web client see the 'httr2' package which builds on this package with http specific tools and logic.",
+ "License": "MIT + file LICENSE",
+ "SystemRequirements": "libcurl (>= 7.73): libcurl-devel (rpm) or libcurl4-openssl-dev (deb)",
+ "URL": "https://jeroen.r-universe.dev/curl",
+ "BugReports": "https://github.com/jeroen/curl/issues",
+ "Suggests": [
+ "spelling",
+ "testthat (>= 1.0.0)",
+ "knitr",
+ "jsonlite",
+ "later",
+ "rmarkdown",
+ "httpuv (>= 1.4.4)",
+ "webutils"
+ ],
+ "VignetteBuilder": "knitr",
+ "Depends": [
+ "R (>= 3.0.0)"
+ ],
+ "RoxygenNote": "7.3.2",
+ "Encoding": "UTF-8",
+ "Language": "en-US",
+ "NeedsCompilation": "yes",
+ "Author": "Jeroen Ooms [aut, cre] (ORCID: ), Hadley Wickham [ctb], Posit Software, PBC [cph]",
+ "Maintainer": "Jeroen Ooms ",
+ "Repository": "CRAN"
},
"data.table": {
"Package": "data.table",
- "Version": "1.18.6.1",
+ "Version": "1.18.2.1",
"Source": "Repository",
- "Requirements": [
- "methods",
- "R"
- ]
+ "Title": "Extension of `data.frame`",
+ "Depends": [
+ "R (>= 3.4.0)"
+ ],
+ "Imports": [
+ "methods"
+ ],
+ "Suggests": [
+ "bit64 (>= 4.0.0)",
+ "bit (>= 4.0.4)",
+ "R.utils (>= 2.13.0)",
+ "xts",
+ "zoo (>= 1.8-1)",
+ "yaml",
+ "knitr",
+ "markdown"
+ ],
+ "Description": "Fast aggregation of large data (e.g. 100GB in RAM), fast ordered joins, fast add/modify/delete of columns by group using no copies at all, list columns, friendly and fast character-separated-value read/write. Offers a natural and flexible syntax, for faster development.",
+ "License": "MPL-2.0 | file LICENSE",
+ "URL": "https://r-datatable.com, https://Rdatatable.gitlab.io/data.table, https://github.com/Rdatatable/data.table",
+ "BugReports": "https://github.com/Rdatatable/data.table/issues",
+ "VignetteBuilder": "knitr",
+ "Encoding": "UTF-8",
+ "ByteCompile": "TRUE",
+ "Authors@R": "c( person(\"Tyson\",\"Barrett\", role=c(\"aut\",\"cre\"), email=\"t.barrett88@gmail.com\", comment = c(ORCID=\"0000-0002-2137-1391\")), person(\"Matt\",\"Dowle\", role=\"aut\", email=\"mattjdowle@gmail.com\"), person(\"Arun\",\"Srinivasan\", role=\"aut\", email=\"asrini@pm.me\"), person(\"Jan\",\"Gorecki\", role=\"aut\", email=\"j.gorecki@wit.edu.pl\"), person(\"Michael\",\"Chirico\", role=\"aut\", email=\"michaelchirico4@gmail.com\", comment = c(ORCID=\"0000-0003-0787-087X\")), person(\"Toby\",\"Hocking\", role=\"aut\", email=\"toby.hocking@r-project.org\", comment = c(ORCID=\"0000-0002-3146-0865\")), person(\"Benjamin\",\"Schwendinger\",role=\"aut\", comment = c(ORCID=\"0000-0003-3315-8114\")), person(\"Ivan\", \"Krylov\", role=\"aut\", email=\"ikrylov@disroot.org\", comment = c(ORCID=\"0000-0002-0172-3812\")), person(\"Pasha\",\"Stetsenko\", role=\"ctb\"), person(\"Tom\",\"Short\", role=\"ctb\"), person(\"Steve\",\"Lianoglou\", role=\"ctb\"), person(\"Eduard\",\"Antonyan\", role=\"ctb\"), person(\"Markus\",\"Bonsch\", role=\"ctb\"), person(\"Hugh\",\"Parsonage\", role=\"ctb\"), person(\"Scott\",\"Ritchie\", role=\"ctb\"), person(\"Kun\",\"Ren\", role=\"ctb\"), person(\"Xianying\",\"Tan\", role=\"ctb\"), person(\"Rick\",\"Saporta\", role=\"ctb\"), person(\"Otto\",\"Seiskari\", role=\"ctb\"), person(\"Xianghui\",\"Dong\", role=\"ctb\"), person(\"Michel\",\"Lang\", role=\"ctb\"), person(\"Watal\",\"Iwasaki\", role=\"ctb\"), person(\"Seth\",\"Wenchel\", role=\"ctb\"), person(\"Karl\",\"Broman\", role=\"ctb\"), person(\"Tobias\",\"Schmidt\", role=\"ctb\"), person(\"David\",\"Arenburg\", role=\"ctb\"), person(\"Ethan\",\"Smith\", role=\"ctb\"), person(\"Francois\",\"Cocquemas\", role=\"ctb\"), person(\"Matthieu\",\"Gomez\", role=\"ctb\"), person(\"Philippe\",\"Chataignon\", role=\"ctb\"), person(\"Nello\",\"Blaser\", role=\"ctb\"), person(\"Dmitry\",\"Selivanov\", role=\"ctb\"), person(\"Andrey\",\"Riabushenko\", role=\"ctb\"), person(\"Cheng\",\"Lee\", role=\"ctb\"), person(\"Declan\",\"Groves\", role=\"ctb\"), person(\"Daniel\",\"Possenriede\", role=\"ctb\"), person(\"Felipe\",\"Parages\", role=\"ctb\"), person(\"Denes\",\"Toth\", role=\"ctb\"), person(\"Mus\",\"Yaramaz-David\", role=\"ctb\"), person(\"Ayappan\",\"Perumal\", role=\"ctb\"), person(\"James\",\"Sams\", role=\"ctb\"), person(\"Martin\",\"Morgan\", role=\"ctb\"), person(\"Michael\",\"Quinn\", role=\"ctb\"), person(given=\"@javrucebo\", role=\"ctb\", comment=\"GitHub user\"), person(\"Marc\",\"Halperin\", role=\"ctb\"), person(\"Roy\",\"Storey\", role=\"ctb\"), person(\"Manish\",\"Saraswat\", role=\"ctb\"), person(\"Morgan\",\"Jacob\", role=\"ctb\"), person(\"Michael\",\"Schubmehl\", role=\"ctb\"), person(\"Davis\",\"Vaughan\", role=\"ctb\"), person(\"Leonardo\",\"Silvestri\", role=\"ctb\"), person(\"Jim\",\"Hester\", role=\"ctb\"), person(\"Anthony\",\"Damico\", role=\"ctb\"), person(\"Sebastian\",\"Freundt\", role=\"ctb\"), person(\"David\",\"Simons\", role=\"ctb\"), person(\"Elliott\",\"Sales de Andrade\", role=\"ctb\"), person(\"Cole\",\"Miller\", role=\"ctb\"), person(\"Jens Peder\",\"Meldgaard\", role=\"ctb\"), person(\"Vaclav\",\"Tlapak\", role=\"ctb\"), person(\"Kevin\",\"Ushey\", role=\"ctb\"), person(\"Dirk\",\"Eddelbuettel\", role=\"ctb\"), person(\"Tony\",\"Fischetti\", role=\"ctb\"), person(\"Ofek\",\"Shilon\", role=\"ctb\"), person(\"Vadim\",\"Khotilovich\", role=\"ctb\"), person(\"Hadley\",\"Wickham\", role=\"ctb\"), person(\"Bennet\",\"Becker\", role=\"ctb\"), person(\"Kyle\",\"Haynes\", role=\"ctb\"), person(\"Boniface Christian\",\"Kamgang\", role=\"ctb\"), person(\"Olivier\",\"Delmarcell\", role=\"ctb\"), person(\"Josh\",\"O'Brien\", role=\"ctb\"), person(\"Dereck\",\"de Mezquita\", role=\"ctb\"), person(\"Michael\",\"Czekanski\", role=\"ctb\"), person(\"Dmitry\", \"Shemetov\", role=\"ctb\"), person(\"Nitish\", \"Jha\", role=\"ctb\"), person(\"Joshua\", \"Wu\", role=\"ctb\"), person(\"Iago\", \"Giné-Vázquez\", role=\"ctb\"), person(\"Anirban\", \"Chetia\", role=\"ctb\"), person(\"Doris\", \"Amoakohene\", role=\"ctb\"), person(\"Angel\", \"Feliz\", role=\"ctb\"), person(\"Michael\",\"Young\", role=\"ctb\"), person(\"Mark\", \"Seeto\", role=\"ctb\"), person(\"Philippe\", \"Grosjean\", role=\"ctb\"), person(\"Vincent\", \"Runge\", role=\"ctb\"), person(\"Christian\", \"Wia\", role=\"ctb\"), person(\"Elise\", \"Maigné\", role=\"ctb\"), person(\"Vincent\", \"Rocher\", role=\"ctb\"), person(\"Vijay\", \"Lulla\", role=\"ctb\"), person(\"Aljaž\", \"Sluga\", role=\"ctb\"), person(\"Bill\", \"Evans\", role=\"ctb\"), person(\"Reino\", \"Bruner\", role=\"ctb\"), person(given=\"@badasahog\", role=\"ctb\", comment=\"GitHub user\"), person(\"Vinit\", \"Thakur\", role=\"ctb\"), person(\"Mukul\", \"Kumar\", role=\"ctb\"), person(\"Ildikó\", \"Czeller\", role=\"ctb\"), person(\"Manmita\", \"Das\", role=\"ctb\") )",
+ "NeedsCompilation": "yes",
+ "Author": "Tyson Barrett [aut, cre] (ORCID: ), Matt Dowle [aut], Arun Srinivasan [aut], Jan Gorecki [aut], Michael Chirico [aut] (ORCID: ), Toby Hocking [aut] (ORCID: ), Benjamin Schwendinger [aut] (ORCID: ), Ivan Krylov [aut] (ORCID: ), Pasha Stetsenko [ctb], Tom Short [ctb], Steve Lianoglou [ctb], Eduard Antonyan [ctb], Markus Bonsch [ctb], Hugh Parsonage [ctb], Scott Ritchie [ctb], Kun Ren [ctb], Xianying Tan [ctb], Rick Saporta [ctb], Otto Seiskari [ctb], Xianghui Dong [ctb], Michel Lang [ctb], Watal Iwasaki [ctb], Seth Wenchel [ctb], Karl Broman [ctb], Tobias Schmidt [ctb], David Arenburg [ctb], Ethan Smith [ctb], Francois Cocquemas [ctb], Matthieu Gomez [ctb], Philippe Chataignon [ctb], Nello Blaser [ctb], Dmitry Selivanov [ctb], Andrey Riabushenko [ctb], Cheng Lee [ctb], Declan Groves [ctb], Daniel Possenriede [ctb], Felipe Parages [ctb], Denes Toth [ctb], Mus Yaramaz-David [ctb], Ayappan Perumal [ctb], James Sams [ctb], Martin Morgan [ctb], Michael Quinn [ctb], @javrucebo [ctb] (GitHub user), Marc Halperin [ctb], Roy Storey [ctb], Manish Saraswat [ctb], Morgan Jacob [ctb], Michael Schubmehl [ctb], Davis Vaughan [ctb], Leonardo Silvestri [ctb], Jim Hester [ctb], Anthony Damico [ctb], Sebastian Freundt [ctb], David Simons [ctb], Elliott Sales de Andrade [ctb], Cole Miller [ctb], Jens Peder Meldgaard [ctb], Vaclav Tlapak [ctb], Kevin Ushey [ctb], Dirk Eddelbuettel [ctb], Tony Fischetti [ctb], Ofek Shilon [ctb], Vadim Khotilovich [ctb], Hadley Wickham [ctb], Bennet Becker [ctb], Kyle Haynes [ctb], Boniface Christian Kamgang [ctb], Olivier Delmarcell [ctb], Josh O'Brien [ctb], Dereck de Mezquita [ctb], Michael Czekanski [ctb], Dmitry Shemetov [ctb], Nitish Jha [ctb], Joshua Wu [ctb], Iago Giné-Vázquez [ctb], Anirban Chetia [ctb], Doris Amoakohene [ctb], Angel Feliz [ctb], Michael Young [ctb], Mark Seeto [ctb], Philippe Grosjean [ctb], Vincent Runge [ctb], Christian Wia [ctb], Elise Maigné [ctb], Vincent Rocher [ctb], Vijay Lulla [ctb], Aljaž Sluga [ctb], Bill Evans [ctb], Reino Bruner [ctb], @badasahog [ctb] (GitHub user), Vinit Thakur [ctb], Mukul Kumar [ctb], Ildikó Czeller [ctb], Manmita Das [ctb]",
+ "Maintainer": "Tyson Barrett ",
+ "Repository": "CRAN"
},
"desc": {
"Package": "desc",
"Version": "1.4.3",
"Source": "Repository",
- "Requirements": [
+ "Title": "Manipulate DESCRIPTION Files",
+ "Authors@R": "c( person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\")), person(\"Kirill\", \"Müller\", role = \"aut\"), person(\"Jim\", \"Hester\", , \"james.f.hester@gmail.com\", role = \"aut\"), person(\"Maëlle\", \"Salmon\", role = \"ctb\", comment = c(ORCID = \"0000-0002-2815-0399\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Maintainer": "Gábor Csárdi ",
+ "Description": "Tools to read, write, create, and manipulate DESCRIPTION files. It is intended for packages that create or manipulate other packages.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://desc.r-lib.org/, https://github.com/r-lib/desc",
+ "BugReports": "https://github.com/r-lib/desc/issues",
+ "Depends": [
+ "R (>= 3.4)"
+ ],
+ "Imports": [
"cli",
- "R",
"R6",
"utils"
- ]
+ ],
+ "Suggests": [
+ "callr",
+ "covr",
+ "gh",
+ "spelling",
+ "testthat",
+ "whoami",
+ "withr"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "Language": "en-US",
+ "RoxygenNote": "7.2.3",
+ "Collate": "'assertions.R' 'authors-at-r.R' 'built.R' 'classes.R' 'collate.R' 'constants.R' 'deps.R' 'desc-package.R' 'description.R' 'encoding.R' 'find-package-root.R' 'latex.R' 'non-oo-api.R' 'package-archives.R' 'read.R' 'remotes.R' 'str.R' 'syntax_checks.R' 'urls.R' 'utils.R' 'validate.R' 'version.R'",
+ "NeedsCompilation": "no",
+ "Author": "Gábor Csárdi [aut, cre], Kirill Müller [aut], Jim Hester [aut], Maëlle Salmon [ctb] (), Posit Software, PBC [cph, fnd]",
+ "Repository": "CRAN"
},
"digest": {
"Package": "digest",
"Version": "0.6.39",
"Source": "Repository",
- "Requirements": [
- "R",
+ "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Antoine\", \"Lucas\", role=\"ctb\", comment = c(ORCID = \"0000-0002-8059-9767\")), person(\"Jarek\", \"Tuszynski\", role=\"ctb\"), person(\"Henrik\", \"Bengtsson\", role=\"ctb\", comment = c(ORCID = \"0000-0002-7579-5165\")), person(\"Simon\", \"Urbanek\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2297-1732\")), person(\"Mario\", \"Frasca\", role=\"ctb\"), person(\"Bryan\", \"Lewis\", role=\"ctb\"), person(\"Murray\", \"Stokely\", role=\"ctb\"), person(\"Hannes\", \"Muehleisen\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8552-0029\")), person(\"Duncan\", \"Murdoch\", role=\"ctb\"), person(\"Jim\", \"Hester\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Wush\", \"Wu\", role=\"ctb\", comment = c(ORCID = \"0000-0001-5180-0567\")), person(\"Qiang\", \"Kou\", role=\"ctb\", comment = c(ORCID = \"0000-0001-6786-5453\")), person(\"Thierry\", \"Onkelinx\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8804-4216\")), person(\"Michel\", \"Lang\", role=\"ctb\", comment = c(ORCID = \"0000-0001-9754-0393\")), person(\"Viliam\", \"Simko\", role=\"ctb\"), person(\"Kurt\", \"Hornik\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4198-9911\")), person(\"Radford\", \"Neal\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2473-3407\")), person(\"Kendon\", \"Bell\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9093-8312\")), person(\"Matthew\", \"de Queljoe\", role=\"ctb\"), person(\"Dmitry\", \"Selivanov\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0492-6647\")), person(\"Ion\", \"Suruceanu\", role=\"ctb\", comment = c(ORCID = \"0009-0005-6446-4909\")), person(\"Bill\", \"Denney\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5759-428X\")), person(\"Dirk\", \"Schumacher\", role=\"ctb\"), person(\"András\", \"Svraka\", role=\"ctb\", comment = c(ORCID = \"0009-0008-8480-1329\")), person(\"Sergey\", \"Fedorov\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5970-7233\")), person(\"Will\", \"Landau\", role=\"ctb\", comment = c(ORCID = \"0000-0003-1878-3253\")), person(\"Floris\", \"Vanderhaeghe\", role=\"ctb\", comment = c(ORCID = \"0000-0002-6378-6229\")), person(\"Kevin\", \"Tappe\", role=\"ctb\"), person(\"Harris\", \"McGehee\", role=\"ctb\"), person(\"Tim\", \"Mastny\", role=\"ctb\"), person(\"Aaron\", \"Peikert\", role=\"ctb\", comment = c(ORCID = \"0000-0001-7813-818X\")), person(\"Mark\", \"van der Loo\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9807-4686\")), person(\"Chris\", \"Muir\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2555-3878\")), person(\"Moritz\", \"Beller\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4852-0526\")), person(\"Sebastian\", \"Campbell\", role=\"ctb\", comment = c(ORCID = \"0009-0000-5948-4503\")), person(\"Winston\", \"Chang\", role=\"ctb\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Dean\", \"Attali\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5645-3493\")), person(\"Michael\", \"Chirico\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0787-087X\")), person(\"Kevin\", \"Ushey\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Carl\", \"Pearson\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0701-7860\")))",
+ "Date": "2025-11-19",
+ "Title": "Create Compact Hash Digests of R Objects",
+ "Description": "Implementation of a function 'digest()' for the creation of hash digests of arbitrary R objects (using the 'md5', 'sha-1', 'sha-256', 'crc32', 'xxhash', 'murmurhash', 'spookyhash', 'blake3', 'crc32c', 'xxh3_64', and 'xxh3_128' algorithms) permitting easy comparison of R language objects, as well as functions such as 'hmac()' to create hash-based message authentication code. Please note that this package is not meant to be deployed for cryptographic purposes for which more comprehensive (and widely tested) libraries such as 'OpenSSL' should be used.",
+ "URL": "https://github.com/eddelbuettel/digest, https://eddelbuettel.github.io/digest/, https://dirk.eddelbuettel.com/code/digest.html",
+ "BugReports": "https://github.com/eddelbuettel/digest/issues",
+ "Depends": [
+ "R (>= 3.3.0)"
+ ],
+ "Imports": [
"utils"
- ]
+ ],
+ "License": "GPL (>= 2)",
+ "Suggests": [
+ "tinytest",
+ "simplermarkdown",
+ "rbenchmark"
+ ],
+ "VignetteBuilder": "simplermarkdown",
+ "Encoding": "UTF-8",
+ "NeedsCompilation": "yes",
+ "Author": "Dirk Eddelbuettel [aut, cre] (ORCID: ), Antoine Lucas [ctb] (ORCID: ), Jarek Tuszynski [ctb], Henrik Bengtsson [ctb] (ORCID: ), Simon Urbanek [ctb] (ORCID: ), Mario Frasca [ctb], Bryan Lewis [ctb], Murray Stokely [ctb], Hannes Muehleisen [ctb] (ORCID: ), Duncan Murdoch [ctb], Jim Hester [ctb] (ORCID: ), Wush Wu [ctb] (ORCID: ), Qiang Kou [ctb] (ORCID: ), Thierry Onkelinx [ctb] (ORCID: ), Michel Lang [ctb] (ORCID: ), Viliam Simko [ctb], Kurt Hornik [ctb] (ORCID: ), Radford Neal [ctb] (ORCID: ), Kendon Bell [ctb] (ORCID: ), Matthew de Queljoe [ctb], Dmitry Selivanov [ctb] (ORCID: ), Ion Suruceanu [ctb] (ORCID: ), Bill Denney [ctb] (ORCID: ), Dirk Schumacher [ctb], András Svraka [ctb] (ORCID: ), Sergey Fedorov [ctb] (ORCID: ), Will Landau [ctb] (ORCID: ), Floris Vanderhaeghe [ctb] (ORCID: ), Kevin Tappe [ctb], Harris McGehee [ctb], Tim Mastny [ctb], Aaron Peikert [ctb] (ORCID: ), Mark van der Loo [ctb] (ORCID: ), Chris Muir [ctb] (ORCID: ), Moritz Beller [ctb] (ORCID: ), Sebastian Campbell [ctb] (ORCID: ), Winston Chang [ctb] (ORCID: ), Dean Attali [ctb] (ORCID: ), Michael Chirico [ctb] (ORCID: ), Kevin Ushey [ctb] (ORCID: ), Carl Pearson [ctb] (ORCID: )",
+ "Maintainer": "Dirk Eddelbuettel ",
+ "Repository": "CRAN"
},
"dplyr": {
"Package": "dplyr",
- "Version": "1.2.1",
+ "Version": "1.2.0",
"Source": "Repository",
- "Requirements": [
- "cli",
+ "Type": "Package",
+ "Title": "A Grammar of Data Manipulation",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Romain\", \"François\", role = \"aut\", comment = c(ORCID = \"0000-0002-2444-4226\")), person(\"Lionel\", \"Henry\", role = \"aut\"), person(\"Kirill\", \"Müller\", role = \"aut\", comment = c(ORCID = \"0000-0002-1416-3412\")), person(\"Davis\", \"Vaughan\", , \"davis@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4777-038X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "A fast, consistent tool for working with data frame like objects, both in memory and out of memory.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://dplyr.tidyverse.org, https://github.com/tidyverse/dplyr",
+ "BugReports": "https://github.com/tidyverse/dplyr/issues",
+ "Depends": [
+ "R (>= 4.1.0)"
+ ],
+ "Imports": [
+ "cli (>= 3.6.2)",
"generics",
- "glue",
- "lifecycle",
- "magrittr",
+ "glue (>= 1.3.2)",
+ "lifecycle (>= 1.0.5)",
+ "magrittr (>= 1.5)",
"methods",
- "pillar",
- "R",
+ "pillar (>= 1.9.0)",
"R6",
- "rlang",
- "tibble",
- "tidyselect",
+ "rlang (>= 1.1.7)",
+ "tibble (>= 3.2.0)",
+ "tidyselect (>= 1.2.0)",
"utils",
- "vctrs"
- ]
+ "vctrs (>= 0.7.1)"
+ ],
+ "Suggests": [
+ "broom",
+ "covr",
+ "DBI",
+ "dbplyr (>= 2.2.1)",
+ "ggplot2",
+ "knitr",
+ "Lahman",
+ "lobstr",
+ "nycflights13",
+ "purrr",
+ "rmarkdown",
+ "RSQLite",
+ "stringi (>= 1.7.6)",
+ "testthat (>= 3.1.5)",
+ "tidyr (>= 1.3.0)",
+ "withr"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [aut, cre] (ORCID: ), Romain François [aut] (ORCID: ), Lionel Henry [aut], Kirill Müller [aut] (ORCID: ), Davis Vaughan [aut] (ORCID: ), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"evaluate": {
"Package": "evaluate",
"Version": "1.0.5",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Type": "Package",
+ "Title": "Parsing and Evaluation Tools that Provide More Details than the Default",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\")), person(\"Yihui\", \"Xie\", role = \"aut\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Michael\", \"Lawrence\", role = \"ctb\"), person(\"Thomas\", \"Kluyver\", role = \"ctb\"), person(\"Jeroen\", \"Ooms\", role = \"ctb\"), person(\"Barret\", \"Schloerke\", role = \"ctb\"), person(\"Adam\", \"Ryczkowski\", role = \"ctb\"), person(\"Hiroaki\", \"Yutani\", role = \"ctb\"), person(\"Michel\", \"Lang\", role = \"ctb\"), person(\"Karolis\", \"Koncevičius\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Parsing and evaluation tools that make it easy to recreate the command line behaviour of R.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://evaluate.r-lib.org/, https://github.com/r-lib/evaluate",
+ "BugReports": "https://github.com/r-lib/evaluate/issues",
+ "Depends": [
+ "R (>= 3.6.0)"
+ ],
+ "Suggests": [
+ "callr",
+ "covr",
+ "ggplot2 (>= 3.3.6)",
+ "lattice",
+ "methods",
+ "pkgload",
+ "ragg (>= 1.4.0)",
+ "rlang (>= 1.1.5)",
+ "knitr",
+ "testthat (>= 3.0.0)",
+ "withr"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut, cre], Yihui Xie [aut] (ORCID: ), Michael Lawrence [ctb], Thomas Kluyver [ctb], Jeroen Ooms [ctb], Barret Schloerke [ctb], Adam Ryczkowski [ctb], Hiroaki Yutani [ctb], Michel Lang [ctb], Karolis Koncevičius [ctb], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"farver": {
"Package": "farver",
"Version": "2.1.2",
"Source": "Repository",
- "Requirements": []
+ "Type": "Package",
+ "Title": "High Performance Colour Space Manipulation",
+ "Authors@R": "c( person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Berendea\", \"Nicolae\", role = \"aut\", comment = \"Author of the ColorSpace C++ library\"), person(\"Romain\", \"François\", , \"romain@purrple.cat\", role = \"aut\", comment = c(ORCID = \"0000-0002-2444-4226\")), person(\"Posit, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "The encoding of colour can be handled in many different ways, using different colour spaces. As different colour spaces have different uses, efficient conversion between these representations are important. The 'farver' package provides a set of functions that gives access to very fast colour space conversion and comparisons implemented in C++, and offers speed improvements over the 'convertColor' function in the 'grDevices' package.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://farver.data-imaginist.com, https://github.com/thomasp85/farver",
+ "BugReports": "https://github.com/thomasp85/farver/issues",
+ "Suggests": [
+ "covr",
+ "testthat (>= 3.0.0)"
+ ],
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.1",
+ "NeedsCompilation": "yes",
+ "Author": "Thomas Lin Pedersen [cre, aut] (), Berendea Nicolae [aut] (Author of the ColorSpace C++ library), Romain François [aut] (), Posit, PBC [cph, fnd]",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"fastmap": {
"Package": "fastmap",
"Version": "1.2.0",
"Source": "Repository",
- "Requirements": []
+ "Title": "Fast Data Structures",
+ "Authors@R": "c( person(\"Winston\", \"Chang\", email = \"winston@posit.co\", role = c(\"aut\", \"cre\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(given = \"Tessil\", role = \"cph\", comment = \"hopscotch_map library\") )",
+ "Description": "Fast implementation of data structures, including a key-value store, stack, and queue. Environments are commonly used as key-value stores in R, but every time a new key is used, it is added to R's global symbol table, causing a small amount of memory leakage. This can be problematic in cases where many different keys are used. Fastmap avoids this memory leak issue by implementing the map using data structures in C++.",
+ "License": "MIT + file LICENSE",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.2.3",
+ "Suggests": [
+ "testthat (>= 2.1.1)"
+ ],
+ "URL": "https://r-lib.github.io/fastmap/, https://github.com/r-lib/fastmap",
+ "BugReports": "https://github.com/r-lib/fastmap/issues",
+ "NeedsCompilation": "yes",
+ "Author": "Winston Chang [aut, cre], Posit Software, PBC [cph, fnd], Tessil [cph] (hopscotch_map library)",
+ "Maintainer": "Winston Chang ",
+ "Repository": "CRAN"
},
"fontBitstreamVera": {
"Package": "fontBitstreamVera",
"Version": "0.1.1",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Title": "Fonts with 'Bitstream Vera Fonts' License",
+ "Authors@R": "c( person(\"Lionel\", \"Henry\", , \"lionel.hry@gmail.com\", c(\"cre\", \"aut\")), person(\"Bitstream\", role = \"cph\"))",
+ "Description": "Provides fonts licensed under the 'Bitstream Vera Fonts' license for the 'fontquiver' package.",
+ "Depends": [
+ "R (>= 3.0.0)"
+ ],
+ "License": "file LICENCE",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "5.0.1",
+ "NeedsCompilation": "no",
+ "Author": "Lionel Henry [cre, aut], Bitstream [cph]",
+ "Maintainer": "Lionel Henry ",
+ "License_is_FOSS": "yes",
+ "Repository": "CRAN"
},
"fontLiberation": {
"Package": "fontLiberation",
"Version": "0.1.0",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Title": "Liberation Fonts",
+ "Authors@R": "c( person(\"Lionel\", \"Henry\", , \"lionel@rstudio.com\", \"cre\"), person(\"Pravin Satpute\", role = \"aut\"), person(\"Steve Matteson\", role = \"aut\"), person(\"Red Hat, Inc\", role = \"cph\"), person(\"Google Corporation\", role = \"cph\"))",
+ "Description": "A placeholder for the Liberation fontset intended for the `fontquiver` package. This fontset covers the 12 combinations of families (sans, serif, mono) and faces (plain, bold, italic, bold italic) supported in R graphics devices.",
+ "Depends": [
+ "R (>= 3.0)"
+ ],
+ "License": "file LICENSE",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "5.0.1",
+ "NeedsCompilation": "no",
+ "Author": "Lionel Henry [cre], Pravin Satpute [aut], Steve Matteson [aut], Red Hat, Inc [cph], Google Corporation [cph]",
+ "Maintainer": "Lionel Henry ",
+ "Repository": "CRAN",
+ "License_is_FOSS": "yes"
},
"fontawesome": {
"Package": "fontawesome",
"Version": "0.5.3",
"Source": "Repository",
- "Requirements": [
- "htmltools",
- "R",
- "rlang"
- ]
+ "Type": "Package",
+ "Title": "Easily Work with 'Font Awesome' Icons",
+ "Description": "Easily and flexibly insert 'Font Awesome' icons into 'R Markdown' documents and 'Shiny' apps. These icons can be inserted into HTML content through inline 'SVG' tags or 'i' tags. There is also a utility function for exporting 'Font Awesome' icons as 'PNG' images for those situations where raster graphics are needed.",
+ "Authors@R": "c( person(\"Richard\", \"Iannone\", , \"rich@posit.co\", c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Christophe\", \"Dervieux\", , \"cderv@posit.co\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"ctb\"), person(\"Dave\", \"Gandy\", role = c(\"ctb\", \"cph\"), comment = \"Font-Awesome font\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "License": "MIT + file LICENSE",
+ "URL": "https://github.com/rstudio/fontawesome, https://rstudio.github.io/fontawesome/",
+ "BugReports": "https://github.com/rstudio/fontawesome/issues",
+ "Encoding": "UTF-8",
+ "ByteCompile": "true",
+ "RoxygenNote": "7.3.2",
+ "Depends": [
+ "R (>= 3.3.0)"
+ ],
+ "Imports": [
+ "rlang (>= 1.0.6)",
+ "htmltools (>= 0.5.1.1)"
+ ],
+ "Suggests": [
+ "covr",
+ "dplyr (>= 1.0.8)",
+ "gt (>= 0.9.0)",
+ "knitr (>= 1.31)",
+ "testthat (>= 3.0.0)",
+ "rsvg"
+ ],
+ "Config/testthat/edition": "3",
+ "NeedsCompilation": "no",
+ "Author": "Richard Iannone [aut, cre] (), Christophe Dervieux [ctb] (), Winston Chang [ctb], Dave Gandy [ctb, cph] (Font-Awesome font), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Richard Iannone ",
+ "Repository": "CRAN"
},
"fontquiver": {
"Package": "fontquiver",
"Version": "0.2.1",
"Source": "Repository",
- "Requirements": [
- "fontBitstreamVera",
- "fontLiberation",
- "R"
- ]
+ "Title": "Set of Installed Fonts",
+ "Authors@R": "c( person(\"Lionel\", \"Henry\", , \"lionel@rstudio.com\", c(\"cre\", \"aut\")), person(\"RStudio\", role = \"cph\"), person(\"George Douros\", role = \"cph\", comment = \"Symbola font\"))",
+ "Description": "Provides a set of fonts with permissive licences. This is useful when you want to avoid system fonts to make sure your outputs are reproducible.",
+ "Depends": [
+ "R (>= 3.0.0)"
+ ],
+ "Imports": [
+ "fontBitstreamVera (>= 0.1.0)",
+ "fontLiberation (>= 0.1.0)"
+ ],
+ "Suggests": [
+ "testthat",
+ "htmltools"
+ ],
+ "License": "GPL-3 | file LICENSE",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "5.0.1",
+ "Collate": "'font-getters.R' 'fontset.R' 'fontset-bitstream-vera.R' 'fontset-dejavu.R' 'fontset-liberation.R' 'fontset-symbola.R' 'html-dependency.R' 'utils.R'",
+ "NeedsCompilation": "no",
+ "Author": "Lionel Henry [cre, aut], RStudio [cph], George Douros [cph] (Symbola font)",
+ "Maintainer": "Lionel Henry ",
+ "Repository": "CRAN"
},
"fs": {
"Package": "fs",
- "Version": "2.1.0",
- "Source": "Repository",
- "Requirements": [
- "methods",
- "R"
- ]
+ "Version": "1.6.6",
+ "Source": "Repository",
+ "Title": "Cross-Platform File System Operations Based on 'libuv'",
+ "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\")), person(\"libuv project contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Joyent, Inc. and other Node contributors\", role = \"cph\", comment = \"libuv library\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "A cross-platform interface to file system operations, built on top of the 'libuv' C library.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://fs.r-lib.org, https://github.com/r-lib/fs",
+ "BugReports": "https://github.com/r-lib/fs/issues",
+ "Depends": [
+ "R (>= 3.6)"
+ ],
+ "Imports": [
+ "methods"
+ ],
+ "Suggests": [
+ "covr",
+ "crayon",
+ "knitr",
+ "pillar (>= 1.0.0)",
+ "rmarkdown",
+ "spelling",
+ "testthat (>= 3.0.0)",
+ "tibble (>= 1.1.0)",
+ "vctrs (>= 0.3.0)",
+ "withr"
+ ],
+ "VignetteBuilder": "knitr",
+ "ByteCompile": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Copyright": "file COPYRIGHTS",
+ "Encoding": "UTF-8",
+ "Language": "en-US",
+ "RoxygenNote": "7.2.3",
+ "SystemRequirements": "GNU make",
+ "NeedsCompilation": "yes",
+ "Author": "Jim Hester [aut], Hadley Wickham [aut], Gábor Csárdi [aut, cre], libuv project contributors [cph] (libuv library), Joyent, Inc. and other Node contributors [cph] (libuv library), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"gdtools": {
"Package": "gdtools",
"Version": "0.5.1",
"Source": "Repository",
- "Requirements": [
- "fontquiver",
+ "Title": "Font Metrics and Font Management Utilities for R Graphics",
+ "Authors@R": "c( person(\"David\", \"Gohel\", , \"david.gohel@ardata.fr\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", , \"hadley@rstudio.com\", role = \"aut\"), person(\"Lionel\", \"Henry\", , \"lionel@rstudio.com\", role = \"aut\"), person(\"Jeroen\", \"Ooms\", , \"jeroen@berkeley.edu\", role = \"aut\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Yixuan\", \"Qiu\", role = \"ctb\"), person(\"R Core Team\", role = \"cph\", comment = \"Cairo code from X11 device\"), person(\"ArData\", role = \"cph\"), person(\"RStudio\", role = \"cph\") )",
+ "Description": "Compute text metrics (width, ascent, descent) using 'Cairo' and 'FreeType', independently of the active graphic device. Font lookup is delegated to 'systemfonts'. Additional utilities let users register 'Google Fonts' or bundled 'Liberation' fonts, check font availability, and assemble 'htmlDependency' objects so that fonts are correctly embedded in 'Shiny' applications, 'R Markdown' documents, and 'htmlwidgets' outputs such as 'ggiraph'.",
+ "License": "GPL-3 | file LICENSE",
+ "URL": "https://davidgohel.github.io/gdtools/",
+ "BugReports": "https://github.com/davidgohel/gdtools/issues",
+ "Depends": [
+ "R (>= 4.0.0)"
+ ],
+ "Imports": [
+ "fontquiver (>= 0.2.0)",
"htmltools",
- "R",
- "Rcpp",
- "systemfonts",
+ "Rcpp (>= 0.12.12)",
+ "systemfonts (>= 1.3.1)",
"tools"
- ]
+ ],
+ "Suggests": [
+ "curl",
+ "gfonts",
+ "methods",
+ "testthat"
+ ],
+ "LinkingTo": [
+ "Rcpp"
+ ],
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "SystemRequirements": "cairo, freetype2, fontconfig",
+ "NeedsCompilation": "yes",
+ "Author": "David Gohel [aut, cre], Hadley Wickham [aut], Lionel Henry [aut], Jeroen Ooms [aut] (ORCID: ), Yixuan Qiu [ctb], R Core Team [cph] (Cairo code from X11 device), ArData [cph], RStudio [cph]",
+ "Maintainer": "David Gohel ",
+ "Repository": "CRAN"
},
"generics": {
"Package": "generics",
"Version": "0.1.4",
"Source": "Repository",
- "Requirements": [
- "methods",
- "R"
- ]
+ "Title": "Common S3 Generics not Provided by Base R Methods Related to Model Fitting",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Max\", \"Kuhn\", , \"max@posit.co\", role = \"aut\"), person(\"Davis\", \"Vaughan\", , \"davis@posit.co\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"https://ror.org/03wc8by49\")) )",
+ "Description": "In order to reduce potential package dependencies and conflicts, generics provides a number of commonly used S3 generics.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://generics.r-lib.org, https://github.com/r-lib/generics",
+ "BugReports": "https://github.com/r-lib/generics/issues",
+ "Depends": [
+ "R (>= 3.6)"
+ ],
+ "Imports": [
+ "methods"
+ ],
+ "Suggests": [
+ "covr",
+ "pkgload",
+ "testthat (>= 3.0.0)",
+ "tibble",
+ "withr"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut, cre] (ORCID: ), Max Kuhn [aut], Davis Vaughan [aut], Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"ggplot2": {
"Package": "ggplot2",
- "Version": "4.0.3",
- "Source": "Repository",
- "Requirements": [
+ "Version": "4.0.2",
+ "Source": "Repository",
+ "Title": "Create Elegant Data Visualisations Using the Grammar of Graphics",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Winston\", \"Chang\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Lionel\", \"Henry\", role = \"aut\"), person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Kohske\", \"Takahashi\", role = \"aut\"), person(\"Claus\", \"Wilke\", role = \"aut\", comment = c(ORCID = \"0000-0002-7470-9261\")), person(\"Kara\", \"Woo\", role = \"aut\", comment = c(ORCID = \"0000-0002-5125-4188\")), person(\"Hiroaki\", \"Yutani\", role = \"aut\", comment = c(ORCID = \"0000-0002-3385-7233\")), person(\"Dewey\", \"Dunnington\", role = \"aut\", comment = c(ORCID = \"0000-0002-9415-4582\")), person(\"Teun\", \"van den Brand\", role = \"aut\", comment = c(ORCID = \"0000-0002-9335-7468\")), person(\"Posit, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "A system for 'declaratively' creating graphics, based on \"The Grammar of Graphics\". You provide the data, tell 'ggplot2' how to map variables to aesthetics, what graphical primitives to use, and it takes care of the details.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://ggplot2.tidyverse.org, https://github.com/tidyverse/ggplot2",
+ "BugReports": "https://github.com/tidyverse/ggplot2/issues",
+ "Depends": [
+ "R (>= 4.1)"
+ ],
+ "Imports": [
"cli",
"grDevices",
"grid",
- "gtable",
+ "gtable (>= 0.3.6)",
"isoband",
- "lifecycle",
- "R",
- "rlang",
+ "lifecycle (> 1.0.1)",
+ "rlang (>= 1.1.0)",
"S7",
- "scales",
+ "scales (>= 1.4.0)",
"stats",
- "vctrs",
- "withr"
- ]
+ "vctrs (>= 0.6.0)",
+ "withr (>= 2.5.0)"
+ ],
+ "Suggests": [
+ "broom",
+ "covr",
+ "dplyr",
+ "ggplot2movies",
+ "hexbin",
+ "Hmisc",
+ "hms",
+ "knitr",
+ "mapproj",
+ "maps",
+ "MASS",
+ "mgcv",
+ "multcomp",
+ "munsell",
+ "nlme",
+ "profvis",
+ "quantreg",
+ "quarto",
+ "ragg (>= 1.2.6)",
+ "RColorBrewer",
+ "roxygen2",
+ "rpart",
+ "sf (>= 0.7-3)",
+ "svglite (>= 2.1.2)",
+ "testthat (>= 3.1.5)",
+ "tibble",
+ "vdiffr (>= 1.0.6)",
+ "xml2"
+ ],
+ "Enhances": [
+ "sp"
+ ],
+ "VignetteBuilder": "quarto",
+ "Config/Needs/website": "ggtext, tidyr, forcats, tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-04-23",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "7.3.3",
+ "Collate": "'ggproto.R' 'ggplot-global.R' 'aaa-.R' 'aes-colour-fill-alpha.R' 'aes-evaluation.R' 'aes-group-order.R' 'aes-linetype-size-shape.R' 'aes-position.R' 'all-classes.R' 'compat-plyr.R' 'utilities.R' 'aes.R' 'annotation-borders.R' 'utilities-checks.R' 'legend-draw.R' 'geom-.R' 'annotation-custom.R' 'annotation-logticks.R' 'scale-type.R' 'layer.R' 'make-constructor.R' 'geom-polygon.R' 'geom-map.R' 'annotation-map.R' 'geom-raster.R' 'annotation-raster.R' 'annotation.R' 'autolayer.R' 'autoplot.R' 'axis-secondary.R' 'backports.R' 'bench.R' 'bin.R' 'coord-.R' 'coord-cartesian-.R' 'coord-fixed.R' 'coord-flip.R' 'coord-map.R' 'coord-munch.R' 'coord-polar.R' 'coord-quickmap.R' 'coord-radial.R' 'coord-sf.R' 'coord-transform.R' 'data.R' 'docs_layer.R' 'facet-.R' 'facet-grid-.R' 'facet-null.R' 'facet-wrap.R' 'fortify-map.R' 'fortify-models.R' 'fortify-spatial.R' 'fortify.R' 'stat-.R' 'geom-abline.R' 'geom-rect.R' 'geom-bar.R' 'geom-tile.R' 'geom-bin2d.R' 'geom-blank.R' 'geom-boxplot.R' 'geom-col.R' 'geom-path.R' 'geom-contour.R' 'geom-point.R' 'geom-count.R' 'geom-crossbar.R' 'geom-segment.R' 'geom-curve.R' 'geom-defaults.R' 'geom-ribbon.R' 'geom-density.R' 'geom-density2d.R' 'geom-dotplot.R' 'geom-errorbar.R' 'geom-freqpoly.R' 'geom-function.R' 'geom-hex.R' 'geom-histogram.R' 'geom-hline.R' 'geom-jitter.R' 'geom-label.R' 'geom-linerange.R' 'geom-pointrange.R' 'geom-quantile.R' 'geom-rug.R' 'geom-sf.R' 'geom-smooth.R' 'geom-spoke.R' 'geom-text.R' 'geom-violin.R' 'geom-vline.R' 'ggplot2-package.R' 'grob-absolute.R' 'grob-dotstack.R' 'grob-null.R' 'grouping.R' 'properties.R' 'margins.R' 'theme-elements.R' 'guide-.R' 'guide-axis.R' 'guide-axis-logticks.R' 'guide-axis-stack.R' 'guide-axis-theta.R' 'guide-legend.R' 'guide-bins.R' 'guide-colorbar.R' 'guide-colorsteps.R' 'guide-custom.R' 'guide-none.R' 'guide-old.R' 'guides-.R' 'guides-grid.R' 'hexbin.R' 'import-standalone-obj-type.R' 'import-standalone-types-check.R' 'labeller.R' 'labels.R' 'layer-sf.R' 'layout.R' 'limits.R' 'performance.R' 'plot-build.R' 'plot-construction.R' 'plot-last.R' 'plot.R' 'position-.R' 'position-collide.R' 'position-dodge.R' 'position-dodge2.R' 'position-identity.R' 'position-jitter.R' 'position-jitterdodge.R' 'position-nudge.R' 'position-stack.R' 'quick-plot.R' 'reshape-add-margins.R' 'save.R' 'scale-.R' 'scale-alpha.R' 'scale-binned.R' 'scale-brewer.R' 'scale-colour.R' 'scale-continuous.R' 'scale-date.R' 'scale-discrete-.R' 'scale-expansion.R' 'scale-gradient.R' 'scale-grey.R' 'scale-hue.R' 'scale-identity.R' 'scale-linetype.R' 'scale-linewidth.R' 'scale-manual.R' 'scale-shape.R' 'scale-size.R' 'scale-steps.R' 'scale-view.R' 'scale-viridis.R' 'scales-.R' 'stat-align.R' 'stat-bin.R' 'stat-summary-2d.R' 'stat-bin2d.R' 'stat-bindot.R' 'stat-binhex.R' 'stat-boxplot.R' 'stat-connect.R' 'stat-contour.R' 'stat-count.R' 'stat-density-2d.R' 'stat-density.R' 'stat-ecdf.R' 'stat-ellipse.R' 'stat-function.R' 'stat-identity.R' 'stat-manual.R' 'stat-qq-line.R' 'stat-qq.R' 'stat-quantilemethods.R' 'stat-sf-coordinates.R' 'stat-sf.R' 'stat-smooth-methods.R' 'stat-smooth.R' 'stat-sum.R' 'stat-summary-bin.R' 'stat-summary-hex.R' 'stat-summary.R' 'stat-unique.R' 'stat-ydensity.R' 'summarise-plot.R' 'summary.R' 'theme.R' 'theme-defaults.R' 'theme-current.R' 'theme-sub.R' 'utilities-break.R' 'utilities-grid.R' 'utilities-help.R' 'utilities-patterns.R' 'utilities-resolution.R' 'utilities-tidy-eval.R' 'zxx.R' 'zzz.R'",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut] (ORCID: ), Winston Chang [aut] (ORCID: ), Lionel Henry [aut], Thomas Lin Pedersen [aut, cre] (ORCID: ), Kohske Takahashi [aut], Claus Wilke [aut] (ORCID: ), Kara Woo [aut] (ORCID: ), Hiroaki Yutani [aut] (ORCID: ), Dewey Dunnington [aut] (ORCID: ), Teun van den Brand [aut] (ORCID: ), Posit, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"glue": {
"Package": "glue",
- "Version": "1.8.1",
- "Source": "Repository",
- "Requirements": [
- "methods",
- "R"
- ]
+ "Version": "1.8.0",
+ "Source": "Repository",
+ "Title": "Interpreted String Literals",
+ "Authors@R": "c( person(\"Jim\", \"Hester\", role = \"aut\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Jennifer\", \"Bryan\", , \"jenny@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-6983-2759\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "An implementation of interpreted string literals, inspired by Python's Literal String Interpolation and Docstrings and Julia's Triple-Quoted String Literals .",
+ "License": "MIT + file LICENSE",
+ "URL": "https://glue.tidyverse.org/, https://github.com/tidyverse/glue",
+ "BugReports": "https://github.com/tidyverse/glue/issues",
+ "Depends": [
+ "R (>= 3.6)"
+ ],
+ "Imports": [
+ "methods"
+ ],
+ "Suggests": [
+ "crayon",
+ "DBI (>= 1.2.0)",
+ "dplyr",
+ "knitr",
+ "magrittr",
+ "rlang",
+ "rmarkdown",
+ "RSQLite",
+ "testthat (>= 3.2.0)",
+ "vctrs (>= 0.3.0)",
+ "waldo (>= 0.5.3)",
+ "withr"
+ ],
+ "VignetteBuilder": "knitr",
+ "ByteCompile": "true",
+ "Config/Needs/website": "bench, forcats, ggbeeswarm, ggplot2, R.utils, rprintf, tidyr, tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "yes",
+ "Author": "Jim Hester [aut] (), Jennifer Bryan [aut, cre] (), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Jennifer Bryan ",
+ "Repository": "CRAN"
},
"gridExtra": {
"Package": "gridExtra",
- "Version": "2.3.1",
- "Source": "Repository",
- "Requirements": [
- "graphics",
- "grDevices",
- "grid",
+ "Version": "2.3",
+ "Source": "Repository",
+ "Authors@R": "c(person(\"Baptiste\", \"Auguie\", email = \"baptiste.auguie@gmail.com\", role = c(\"aut\", \"cre\")), person(\"Anton\", \"Antonov\", email = \"tonytonov@gmail.com\", role = c(\"ctb\")))",
+ "License": "GPL (>= 2)",
+ "Title": "Miscellaneous Functions for \"Grid\" Graphics",
+ "Type": "Package",
+ "Description": "Provides a number of user-level functions to work with \"grid\" graphics, notably to arrange multiple grid-based plots on a page, and draw tables.",
+ "VignetteBuilder": "knitr",
+ "Imports": [
"gtable",
+ "grid",
+ "grDevices",
+ "graphics",
"utils"
- ]
+ ],
+ "Suggests": [
+ "ggplot2",
+ "egg",
+ "lattice",
+ "knitr",
+ "testthat"
+ ],
+ "RoxygenNote": "6.0.1",
+ "NeedsCompilation": "no",
+ "Author": "Baptiste Auguie [aut, cre], Anton Antonov [ctb]",
+ "Maintainer": "Baptiste Auguie ",
+ "Repository": "CRAN"
},
"gridGraphics": {
"Package": "gridGraphics",
"Version": "0.5-1",
"Source": "Repository",
- "Requirements": [
- "graphics",
- "grDevices",
- "grid"
- ]
+ "Title": "Redraw Base Graphics Using 'grid' Graphics",
+ "Authors@R": "c(person(\"Paul\", \"Murrell\", role = c(\"cre\", \"aut\"), email = \"paul@stat.auckland.ac.nz\"), person(\"Zhijian\", \"Wen\", role = \"aut\", email = \"jwen246@aucklanduni.ac.nz\"))",
+ "Description": "Functions to convert a page of plots drawn with the 'graphics' package into identical output drawn with the 'grid' package. The result looks like the original 'graphics'-based plot, but consists of 'grid' grobs and viewports that can then be manipulated with 'grid' functions (e.g., edit grobs and revisit viewports).",
+ "Depends": [
+ "grid",
+ "graphics"
+ ],
+ "Imports": [
+ "grDevices"
+ ],
+ "Suggests": [
+ "magick (>= 1.3)",
+ "pdftools (>= 1.6)"
+ ],
+ "License": "GPL (>= 2)",
+ "URL": "https://github.com/pmur002/gridgraphics",
+ "NeedsCompilation": "no",
+ "Author": "Paul Murrell [cre, aut], Zhijian Wen [aut]",
+ "Maintainer": "Paul Murrell ",
+ "Repository": "CRAN"
},
"gtable": {
"Package": "gtable",
"Version": "0.3.6",
"Source": "Repository",
- "Requirements": [
+ "Title": "Arrange 'Grobs' in Tables",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"aut\", \"cre\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Tools to make it easier to work with \"tables\" of 'grobs'. The 'gtable' package defines a 'gtable' grob class that specifies a grid along with a list of grobs and their placement in the grid. Further the package makes it easy to manipulate and combine 'gtable' objects so that complex compositions can be built up sequentially.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://gtable.r-lib.org, https://github.com/r-lib/gtable",
+ "BugReports": "https://github.com/r-lib/gtable/issues",
+ "Depends": [
+ "R (>= 4.0)"
+ ],
+ "Imports": [
"cli",
"glue",
"grid",
"lifecycle",
- "R",
- "rlang",
+ "rlang (>= 1.1.0)",
"stats"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "ggplot2",
+ "knitr",
+ "profvis",
+ "rmarkdown",
+ "testthat (>= 3.0.0)"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2024-10-25",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut], Thomas Lin Pedersen [aut, cre], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"highr": {
"Package": "highr",
- "Version": "0.12",
- "Source": "Repository",
- "Requirements": [
- "R",
- "xfun"
- ]
+ "Version": "0.11",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "Syntax Highlighting for R Source Code",
+ "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Yixuan\", \"Qiu\", role = \"aut\"), person(\"Christopher\", \"Gandrud\", role = \"ctb\"), person(\"Qiang\", \"Li\", role = \"ctb\") )",
+ "Description": "Provides syntax highlighting for R source code. Currently it supports LaTeX and HTML output. Source code of other languages is supported via Andre Simon's highlight package ().",
+ "Depends": [
+ "R (>= 3.3.0)"
+ ],
+ "Imports": [
+ "xfun (>= 0.18)"
+ ],
+ "Suggests": [
+ "knitr",
+ "markdown",
+ "testit"
+ ],
+ "License": "GPL",
+ "URL": "https://github.com/yihui/highr",
+ "BugReports": "https://github.com/yihui/highr/issues",
+ "VignetteBuilder": "knitr",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.1",
+ "NeedsCompilation": "no",
+ "Author": "Yihui Xie [aut, cre] (), Yixuan Qiu [aut], Christopher Gandrud [ctb], Qiang Li [ctb]",
+ "Maintainer": "Yihui Xie ",
+ "Repository": "CRAN"
},
"htmltools": {
"Package": "htmltools",
"Version": "0.5.9",
"Source": "Repository",
- "Requirements": [
+ "Type": "Package",
+ "Title": "Tools for HTML",
+ "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Yihui\", \"Xie\", , \"yihui@posit.co\", role = \"aut\"), person(\"Jeff\", \"Allen\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Tools for HTML generation and output.",
+ "License": "GPL (>= 2)",
+ "URL": "https://github.com/rstudio/htmltools, https://rstudio.github.io/htmltools/",
+ "BugReports": "https://github.com/rstudio/htmltools/issues",
+ "Depends": [
+ "R (>= 2.14.1)"
+ ],
+ "Imports": [
"base64enc",
"digest",
- "fastmap",
+ "fastmap (>= 1.1.0)",
"grDevices",
- "R",
- "rlang",
+ "rlang (>= 1.0.0)",
"utils"
- ]
+ ],
+ "Suggests": [
+ "Cairo",
+ "markdown",
+ "ragg",
+ "shiny",
+ "testthat",
+ "withr"
+ ],
+ "Enhances": [
+ "knitr"
+ ],
+ "Config/Needs/check": "knitr",
+ "Config/Needs/website": "rstudio/quillt, bench",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "Collate": "'colors.R' 'fill.R' 'html_dependency.R' 'html_escape.R' 'html_print.R' 'htmltools-package.R' 'images.R' 'known_tags.R' 'selector.R' 'staticimports.R' 'tag_query.R' 'utils.R' 'tags.R' 'template.R'",
+ "NeedsCompilation": "yes",
+ "Author": "Joe Cheng [aut], Carson Sievert [aut, cre] (ORCID: ), Barret Schloerke [aut] (ORCID: ), Winston Chang [aut] (ORCID: ), Yihui Xie [aut], Jeff Allen [aut], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"htmlwidgets": {
"Package": "htmlwidgets",
"Version": "1.6.4",
"Source": "Repository",
- "Requirements": [
+ "Type": "Package",
+ "Title": "HTML Widgets for R",
+ "Authors@R": "c( person(\"Ramnath\", \"Vaidyanathan\", role = c(\"aut\", \"cph\")), person(\"Yihui\", \"Xie\", role = \"aut\"), person(\"JJ\", \"Allaire\", role = \"aut\"), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Carson\", \"Sievert\", , \"carson@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Kenton\", \"Russell\", role = c(\"aut\", \"cph\")), person(\"Ellis\", \"Hughes\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "A framework for creating HTML widgets that render in various contexts including the R console, 'R Markdown' documents, and 'Shiny' web applications.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://github.com/ramnathv/htmlwidgets",
+ "BugReports": "https://github.com/ramnathv/htmlwidgets/issues",
+ "Imports": [
"grDevices",
- "htmltools",
- "jsonlite",
- "knitr",
+ "htmltools (>= 0.5.7)",
+ "jsonlite (>= 0.9.16)",
+ "knitr (>= 1.8)",
"rmarkdown",
"yaml"
- ]
+ ],
+ "Suggests": [
+ "testthat"
+ ],
+ "Enhances": [
+ "shiny (>= 1.1)"
+ ],
+ "VignetteBuilder": "knitr",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.2.3",
+ "NeedsCompilation": "no",
+ "Author": "Ramnath Vaidyanathan [aut, cph], Yihui Xie [aut], JJ Allaire [aut], Joe Cheng [aut], Carson Sievert [aut, cre] (), Kenton Russell [aut, cph], Ellis Hughes [ctb], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"httr": {
"Package": "httr",
- "Version": "1.4.9",
- "Source": "Repository",
- "Requirements": [
- "curl",
+ "Version": "1.4.7",
+ "Source": "Repository",
+ "Title": "Tools for Working with URLs and HTTP",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\")), person(\"Posit, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Useful tools for working with HTTP organised by HTTP verbs (GET(), POST(), etc). Configuration functions make it easy to control additional request components (authenticate(), add_headers() and so on).",
+ "License": "MIT + file LICENSE",
+ "URL": "https://httr.r-lib.org/, https://github.com/r-lib/httr",
+ "BugReports": "https://github.com/r-lib/httr/issues",
+ "Depends": [
+ "R (>= 3.5)"
+ ],
+ "Imports": [
+ "curl (>= 5.0.2)",
"jsonlite",
"mime",
- "openssl",
- "R",
+ "openssl (>= 0.8)",
"R6"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "httpuv",
+ "jpeg",
+ "knitr",
+ "png",
+ "readr",
+ "rmarkdown",
+ "testthat (>= 0.8.0)",
+ "xml2"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.2.3",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut, cre], Posit, PBC [cph, fnd]",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"isoband": {
"Package": "isoband",
"Version": "0.3.0",
"Source": "Repository",
- "Requirements": [
+ "Title": "Generate Isolines and Isobands from Regularly Spaced Elevation Grids",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Claus O.\", \"Wilke\", , \"wilke@austin.utexas.edu\", role = \"aut\", comment = c(\"Original author\", ORCID = \"0000-0002-7470-9261\")), person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Posit, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "A fast C++ implementation to generate contour lines (isolines) and contour polygons (isobands) from regularly spaced grids containing elevation data.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://isoband.r-lib.org, https://github.com/r-lib/isoband",
+ "BugReports": "https://github.com/r-lib/isoband/issues",
+ "Imports": [
"cli",
- "cpp11",
"grid",
"rlang",
"utils"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "ggplot2",
+ "knitr",
+ "magick",
+ "bench",
+ "rmarkdown",
+ "sf",
+ "testthat (>= 3.0.0)",
+ "xml2"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-12-05",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "Config/build/compilation-database": "true",
+ "LinkingTo": [
+ "cpp11"
+ ],
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [aut] (ORCID: ), Claus O. Wilke [aut] (Original author, ORCID: ), Thomas Lin Pedersen [aut, cre] (ORCID: ), Posit, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"jaspBase": {
"Package": "jaspBase",
"Version": "0.20.4",
- "Source": "Local",
- "Requirements": ["cli", "codetools", "compiler", "ggplot2", "grDevices", "grid", "gridExtra", "gridGraphics", "jaspGraphs", "jsonlite", "lifecycle", "methods", "officer", "pkgbuild", "plyr", "ragg", "R6", "Rcpp", "rvg", "svglite", "systemfonts", "withr"],
- "RemoteType": "local",
- "RemoteUrl": "/home/virtuoos/Broncode/JASP/jasp-desktop/Engine/jaspBase",
- "Cacheable": true,
- "Hash": "7fa78a6a9cb16c17cf2707e7bb5ff577"
+ "Source": "GitHub",
+ "Type": "Package",
+ "Title": "JASP Base",
+ "Author": "JASP Team",
+ "Maintainer": "Bruno Boutin ",
+ "Description": "Package contains the JASP Bayesian and Frequentist analyses. See for more details.",
+ "License": "GPL2+",
+ "Imports": [
+ "cli",
+ "codetools",
+ "compiler",
+ "ggplot2",
+ "grDevices",
+ "grid",
+ "gridExtra",
+ "gridGraphics",
+ "jaspGraphs",
+ "jsonlite",
+ "lifecycle",
+ "methods",
+ "officer",
+ "pkgbuild",
+ "plyr",
+ "ragg",
+ "R6",
+ "Rcpp (>= 0.12.14)",
+ "rvg",
+ "svglite",
+ "systemfonts",
+ "withr"
+ ],
+ "RoxygenNote": "7.3.3",
+ "Roxygen": "list(markdown = TRUE)",
+ "Encoding": "UTF-8",
+ "LinkingTo": [
+ "Rcpp"
+ ],
+ "RcppModules": "jaspResults",
+ "NeedsCompilation": "yes",
+ "Suggests": [
+ "testthat (>= 3.0.0)"
+ ],
+ "Config/testthat/edition": "3",
+ "RemoteType": "github",
+ "RemoteHost": "api.github.com",
+ "RemoteUsername": "jasp-stats",
+ "RemoteRepo": "jaspBase",
+ "RemoteRef": "master",
+ "RemoteSha": "72cb31d6c535e841006e8ebca81170f31a418e79",
+ "Remotes": "jasp-stats/jaspGraphs"
},
"jaspGraphs": {
"Package": "jaspGraphs",
"Version": "0.20.0",
"Source": "GitHub",
- "Requirements": [
+ "Type": "Package",
+ "Title": "Custom Graphs for JASP",
+ "Author": "Don van den Bergh",
+ "Maintainer": "JASP-team ",
+ "Description": "Graph making functions and wrappers for JASP.",
+ "License": "GPL",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "Depends": [
+ "R (>= 4.1.0)"
+ ],
+ "Imports": [
"cli",
- "ggplot2",
+ "ggplot2 (>= 3.0.0)",
"gridExtra",
"gtable",
"htmlwidgets",
@@ -433,114 +1401,356 @@
"plotly",
"R6",
"rlang",
- "scales",
+ "scales"
+ ],
+ "Suggests": [
"testthat",
"vdiffr"
],
+ "Roxygen": "list(markdown = TRUE)",
+ "Config/roxygen2/version": "8.1.0",
"RemoteType": "github",
"RemoteHost": "api.github.com",
"RemoteUsername": "jasp-stats",
"RemoteRepo": "jaspGraphs",
- "RemoteSha": "cdc4c9cf20f52c22c24162ea6fcbdd6b211e92db"
+ "RemoteRef": "master",
+ "RemoteSha": "288d2751131ee6ac17362bd89d2ed7d9c0c67c7c"
},
"jquerylib": {
"Package": "jquerylib",
"Version": "0.1.4",
"Source": "Repository",
- "Requirements": [
+ "Title": "Obtain 'jQuery' as an HTML Dependency Object",
+ "Authors@R": "c( person(\"Carson\", \"Sievert\", role = c(\"aut\", \"cre\"), email = \"carson@rstudio.com\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Joe\", \"Cheng\", role = \"aut\", email = \"joe@rstudio.com\"), person(family = \"RStudio\", role = \"cph\"), person(family = \"jQuery Foundation\", role = \"cph\", comment = \"jQuery library and jQuery UI library\"), person(family = \"jQuery contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery library; authors listed in inst/lib/jquery-AUTHORS.txt\") )",
+ "Description": "Obtain any major version of 'jQuery' () and use it in any webpage generated by 'htmltools' (e.g. 'shiny', 'htmlwidgets', and 'rmarkdown'). Most R users don't need to use this package directly, but other R packages (e.g. 'shiny', 'rmarkdown', etc.) depend on this package to avoid bundling redundant copies of 'jQuery'.",
+ "License": "MIT + file LICENSE",
+ "Encoding": "UTF-8",
+ "Config/testthat/edition": "3",
+ "RoxygenNote": "7.0.2",
+ "Imports": [
"htmltools"
- ]
+ ],
+ "Suggests": [
+ "testthat"
+ ],
+ "NeedsCompilation": "no",
+ "Author": "Carson Sievert [aut, cre] (), Joe Cheng [aut], RStudio [cph], jQuery Foundation [cph] (jQuery library and jQuery UI library), jQuery contributors [ctb, cph] (jQuery library; authors listed in inst/lib/jquery-AUTHORS.txt)",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"jsonlite": {
"Package": "jsonlite",
"Version": "2.0.0",
"Source": "Repository",
- "Requirements": [
+ "Title": "A Simple and Robust JSON Parser and Generator for R",
+ "License": "MIT + file LICENSE",
+ "Depends": [
"methods"
- ]
+ ],
+ "Authors@R": "c( person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Duncan\", \"Temple Lang\", role = \"ctb\"), person(\"Lloyd\", \"Hilaiel\", role = \"cph\", comment=\"author of bundled libyajl\"))",
+ "URL": "https://jeroen.r-universe.dev/jsonlite https://arxiv.org/abs/1403.2805",
+ "BugReports": "https://github.com/jeroen/jsonlite/issues",
+ "Maintainer": "Jeroen Ooms ",
+ "VignetteBuilder": "knitr, R.rsp",
+ "Description": "A reasonably fast JSON parser and generator, optimized for statistical data and the web. Offers simple, flexible tools for working with JSON in R, and is particularly powerful for building pipelines and interacting with a web API. The implementation is based on the mapping described in the vignette (Ooms, 2014). In addition to converting JSON data from/to R objects, 'jsonlite' contains functions to stream, validate, and prettify JSON data. The unit tests included with the package verify that all edge cases are encoded and decoded consistently for use with dynamic data in systems and applications.",
+ "Suggests": [
+ "httr",
+ "vctrs",
+ "testthat",
+ "knitr",
+ "rmarkdown",
+ "R.rsp",
+ "sf"
+ ],
+ "RoxygenNote": "7.3.2",
+ "Encoding": "UTF-8",
+ "NeedsCompilation": "yes",
+ "Author": "Jeroen Ooms [aut, cre] (), Duncan Temple Lang [ctb], Lloyd Hilaiel [cph] (author of bundled libyajl)",
+ "Repository": "CRAN"
},
"knitr": {
"Package": "knitr",
- "Version": "1.52",
- "Source": "Repository",
- "Requirements": [
- "evaluate",
- "highr",
+ "Version": "1.51",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "A General-Purpose Package for Dynamic Report Generation in R",
+ "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Abhraneel\", \"Sarma\", role = \"ctb\"), person(\"Adam\", \"Vogt\", role = \"ctb\"), person(\"Alastair\", \"Andrew\", role = \"ctb\"), person(\"Alex\", \"Zvoleff\", role = \"ctb\"), person(\"Amar\", \"Al-Zubaidi\", role = \"ctb\"), person(\"Andre\", \"Simon\", role = \"ctb\", comment = \"the CSS files under inst/themes/ were derived from the Highlight package http://www.andre-simon.de\"), person(\"Aron\", \"Atkins\", role = \"ctb\"), person(\"Aaron\", \"Wolen\", role = \"ctb\"), person(\"Ashley\", \"Manton\", role = \"ctb\"), person(\"Atsushi\", \"Yasumoto\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8335-495X\")), person(\"Ben\", \"Baumer\", role = \"ctb\"), person(\"Brian\", \"Diggs\", role = \"ctb\"), person(\"Brian\", \"Zhang\", role = \"ctb\"), person(\"Bulat\", \"Yapparov\", role = \"ctb\"), person(\"Cassio\", \"Pereira\", role = \"ctb\"), person(\"Christophe\", \"Dervieux\", role = \"ctb\"), person(\"David\", \"Hall\", role = \"ctb\"), person(\"David\", \"Hugh-Jones\", role = \"ctb\"), person(\"David\", \"Robinson\", role = \"ctb\"), person(\"Doug\", \"Hemken\", role = \"ctb\"), person(\"Duncan\", \"Murdoch\", role = \"ctb\"), person(\"Elio\", \"Campitelli\", role = \"ctb\"), person(\"Ellis\", \"Hughes\", role = \"ctb\"), person(\"Emily\", \"Riederer\", role = \"ctb\"), person(\"Fabian\", \"Hirschmann\", role = \"ctb\"), person(\"Fitch\", \"Simeon\", role = \"ctb\"), person(\"Forest\", \"Fang\", role = \"ctb\"), person(c(\"Frank\", \"E\", \"Harrell\", \"Jr\"), role = \"ctb\", comment = \"the Sweavel package at inst/misc/Sweavel.sty\"), person(\"Garrick\", \"Aden-Buie\", role = \"ctb\"), person(\"Gregoire\", \"Detrez\", role = \"ctb\"), person(\"Hadley\", \"Wickham\", role = \"ctb\"), person(\"Hao\", \"Zhu\", role = \"ctb\"), person(\"Heewon\", \"Jeon\", role = \"ctb\"), person(\"Henrik\", \"Bengtsson\", role = \"ctb\"), person(\"Hiroaki\", \"Yutani\", role = \"ctb\"), person(\"Ian\", \"Lyttle\", role = \"ctb\"), person(\"Hodges\", \"Daniel\", role = \"ctb\"), person(\"Jacob\", \"Bien\", role = \"ctb\"), person(\"Jake\", \"Burkhead\", role = \"ctb\"), person(\"James\", \"Manton\", role = \"ctb\"), person(\"Jared\", \"Lander\", role = \"ctb\"), person(\"Jason\", \"Punyon\", role = \"ctb\"), person(\"Javier\", \"Luraschi\", role = \"ctb\"), person(\"Jeff\", \"Arnold\", role = \"ctb\"), person(\"Jenny\", \"Bryan\", role = \"ctb\"), person(\"Jeremy\", \"Ashkenas\", role = c(\"ctb\", \"cph\"), comment = \"the CSS file at inst/misc/docco-classic.css\"), person(\"Jeremy\", \"Stephens\", role = \"ctb\"), person(\"Jim\", \"Hester\", role = \"ctb\"), person(\"Joe\", \"Cheng\", role = \"ctb\"), person(\"Johannes\", \"Ranke\", role = \"ctb\"), person(\"John\", \"Honaker\", role = \"ctb\"), person(\"John\", \"Muschelli\", role = \"ctb\"), person(\"Jonathan\", \"Keane\", role = \"ctb\"), person(\"JJ\", \"Allaire\", role = \"ctb\"), person(\"Johan\", \"Toloe\", role = \"ctb\"), person(\"Jonathan\", \"Sidi\", role = \"ctb\"), person(\"Joseph\", \"Larmarange\", role = \"ctb\"), person(\"Julien\", \"Barnier\", role = \"ctb\"), person(\"Kaiyin\", \"Zhong\", role = \"ctb\"), person(\"Kamil\", \"Slowikowski\", role = \"ctb\"), person(\"Karl\", \"Forner\", role = \"ctb\"), person(c(\"Kevin\", \"K.\"), \"Smith\", role = \"ctb\"), person(\"Kirill\", \"Mueller\", role = \"ctb\"), person(\"Kohske\", \"Takahashi\", role = \"ctb\"), person(\"Lorenz\", \"Walthert\", role = \"ctb\"), person(\"Lucas\", \"Gallindo\", role = \"ctb\"), person(\"Marius\", \"Hofert\", role = \"ctb\"), person(\"Martin\", \"Modrák\", role = \"ctb\"), person(\"Michael\", \"Chirico\", role = \"ctb\"), person(\"Michael\", \"Friendly\", role = \"ctb\"), person(\"Michal\", \"Bojanowski\", role = \"ctb\"), person(\"Michel\", \"Kuhlmann\", role = \"ctb\"), person(\"Miller\", \"Patrick\", role = \"ctb\"), person(\"Nacho\", \"Caballero\", role = \"ctb\"), person(\"Nick\", \"Salkowski\", role = \"ctb\"), person(\"Niels Richard\", \"Hansen\", role = \"ctb\"), person(\"Noam\", \"Ross\", role = \"ctb\"), person(\"Obada\", \"Mahdi\", role = \"ctb\"), person(\"Pavel N.\", \"Krivitsky\", role = \"ctb\", comment=c(ORCID = \"0000-0002-9101-3362\")), person(\"Pedro\", \"Faria\", role = \"ctb\"), person(\"Qiang\", \"Li\", role = \"ctb\"), person(\"Ramnath\", \"Vaidyanathan\", role = \"ctb\"), person(\"Richard\", \"Cotton\", role = \"ctb\"), person(\"Robert\", \"Krzyzanowski\", role = \"ctb\"), person(\"Rodrigo\", \"Copetti\", role = \"ctb\"), person(\"Romain\", \"Francois\", role = \"ctb\"), person(\"Ruaridh\", \"Williamson\", role = \"ctb\"), person(\"Sagiru\", \"Mati\", role = \"ctb\", comment = c(ORCID = \"0000-0003-1413-3974\")), person(\"Scott\", \"Kostyshak\", role = \"ctb\"), person(\"Sebastian\", \"Meyer\", role = \"ctb\"), person(\"Sietse\", \"Brouwer\", role = \"ctb\"), person(c(\"Simon\", \"de\"), \"Bernard\", role = \"ctb\"), person(\"Sylvain\", \"Rousseau\", role = \"ctb\"), person(\"Taiyun\", \"Wei\", role = \"ctb\"), person(\"Thibaut\", \"Assus\", role = \"ctb\"), person(\"Thibaut\", \"Lamadon\", role = \"ctb\"), person(\"Thomas\", \"Leeper\", role = \"ctb\"), person(\"Tim\", \"Mastny\", role = \"ctb\"), person(\"Tom\", \"Torsney-Weir\", role = \"ctb\"), person(\"Trevor\", \"Davis\", role = \"ctb\"), person(\"Viktoras\", \"Veitas\", role = \"ctb\"), person(\"Weicheng\", \"Zhu\", role = \"ctb\"), person(\"Wush\", \"Wu\", role = \"ctb\"), person(\"Zachary\", \"Foster\", role = \"ctb\"), person(\"Zhian N.\", \"Kamvar\", role = \"ctb\", comment = c(ORCID = \"0000-0003-1458-7108\")), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Provides a general-purpose tool for dynamic report generation in R using Literate Programming techniques.",
+ "Depends": [
+ "R (>= 3.6.0)"
+ ],
+ "Imports": [
+ "evaluate (>= 0.15)",
+ "highr (>= 0.11)",
"methods",
- "R",
"tools",
- "xfun",
- "yaml"
- ]
+ "xfun (>= 0.52)",
+ "yaml (>= 2.1.19)"
+ ],
+ "Suggests": [
+ "bslib",
+ "DBI (>= 0.4-1)",
+ "digest",
+ "formatR",
+ "gifski",
+ "gridSVG",
+ "htmlwidgets (>= 0.7)",
+ "jpeg",
+ "JuliaCall (>= 0.11.1)",
+ "magick",
+ "litedown",
+ "markdown (>= 1.3)",
+ "otel",
+ "otelsdk",
+ "png",
+ "ragg",
+ "reticulate (>= 1.4)",
+ "rgl (>= 0.95.1201)",
+ "rlang",
+ "rmarkdown",
+ "sass",
+ "showtext",
+ "styler (>= 1.2.0)",
+ "targets (>= 0.6.0)",
+ "testit",
+ "tibble",
+ "tikzDevice (>= 0.10)",
+ "tinytex (>= 0.56)",
+ "webshot",
+ "rstudioapi",
+ "svglite"
+ ],
+ "License": "GPL",
+ "URL": "https://yihui.org/knitr/",
+ "BugReports": "https://github.com/yihui/knitr/issues",
+ "Encoding": "UTF-8",
+ "VignetteBuilder": "litedown, knitr",
+ "SystemRequirements": "Package vignettes based on R Markdown v2 or reStructuredText require Pandoc (http://pandoc.org). The function rst2pdf() requires rst2pdf (https://github.com/rst2pdf/rst2pdf).",
+ "Collate": "'block.R' 'cache.R' 'citation.R' 'hooks-html.R' 'plot.R' 'utils.R' 'defaults.R' 'concordance.R' 'engine.R' 'highlight.R' 'themes.R' 'header.R' 'hooks-asciidoc.R' 'hooks-chunk.R' 'hooks-extra.R' 'hooks-latex.R' 'hooks-md.R' 'hooks-rst.R' 'hooks-textile.R' 'hooks.R' 'otel.R' 'output.R' 'package.R' 'pandoc.R' 'params.R' 'parser.R' 'pattern.R' 'rocco.R' 'spin.R' 'table.R' 'template.R' 'utils-conversion.R' 'utils-rd2html.R' 'utils-string.R' 'utils-sweave.R' 'utils-upload.R' 'utils-vignettes.R' 'zzz.R'",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "no",
+ "Author": "Yihui Xie [aut, cre] (ORCID: , URL: https://yihui.org), Abhraneel Sarma [ctb], Adam Vogt [ctb], Alastair Andrew [ctb], Alex Zvoleff [ctb], Amar Al-Zubaidi [ctb], Andre Simon [ctb] (the CSS files under inst/themes/ were derived from the Highlight package http://www.andre-simon.de), Aron Atkins [ctb], Aaron Wolen [ctb], Ashley Manton [ctb], Atsushi Yasumoto [ctb] (ORCID: ), Ben Baumer [ctb], Brian Diggs [ctb], Brian Zhang [ctb], Bulat Yapparov [ctb], Cassio Pereira [ctb], Christophe Dervieux [ctb], David Hall [ctb], David Hugh-Jones [ctb], David Robinson [ctb], Doug Hemken [ctb], Duncan Murdoch [ctb], Elio Campitelli [ctb], Ellis Hughes [ctb], Emily Riederer [ctb], Fabian Hirschmann [ctb], Fitch Simeon [ctb], Forest Fang [ctb], Frank E Harrell Jr [ctb] (the Sweavel package at inst/misc/Sweavel.sty), Garrick Aden-Buie [ctb], Gregoire Detrez [ctb], Hadley Wickham [ctb], Hao Zhu [ctb], Heewon Jeon [ctb], Henrik Bengtsson [ctb], Hiroaki Yutani [ctb], Ian Lyttle [ctb], Hodges Daniel [ctb], Jacob Bien [ctb], Jake Burkhead [ctb], James Manton [ctb], Jared Lander [ctb], Jason Punyon [ctb], Javier Luraschi [ctb], Jeff Arnold [ctb], Jenny Bryan [ctb], Jeremy Ashkenas [ctb, cph] (the CSS file at inst/misc/docco-classic.css), Jeremy Stephens [ctb], Jim Hester [ctb], Joe Cheng [ctb], Johannes Ranke [ctb], John Honaker [ctb], John Muschelli [ctb], Jonathan Keane [ctb], JJ Allaire [ctb], Johan Toloe [ctb], Jonathan Sidi [ctb], Joseph Larmarange [ctb], Julien Barnier [ctb], Kaiyin Zhong [ctb], Kamil Slowikowski [ctb], Karl Forner [ctb], Kevin K. Smith [ctb], Kirill Mueller [ctb], Kohske Takahashi [ctb], Lorenz Walthert [ctb], Lucas Gallindo [ctb], Marius Hofert [ctb], Martin Modrák [ctb], Michael Chirico [ctb], Michael Friendly [ctb], Michal Bojanowski [ctb], Michel Kuhlmann [ctb], Miller Patrick [ctb], Nacho Caballero [ctb], Nick Salkowski [ctb], Niels Richard Hansen [ctb], Noam Ross [ctb], Obada Mahdi [ctb], Pavel N. Krivitsky [ctb] (ORCID: ), Pedro Faria [ctb], Qiang Li [ctb], Ramnath Vaidyanathan [ctb], Richard Cotton [ctb], Robert Krzyzanowski [ctb], Rodrigo Copetti [ctb], Romain Francois [ctb], Ruaridh Williamson [ctb], Sagiru Mati [ctb] (ORCID: ), Scott Kostyshak [ctb], Sebastian Meyer [ctb], Sietse Brouwer [ctb], Simon de Bernard [ctb], Sylvain Rousseau [ctb], Taiyun Wei [ctb], Thibaut Assus [ctb], Thibaut Lamadon [ctb], Thomas Leeper [ctb], Tim Mastny [ctb], Tom Torsney-Weir [ctb], Trevor Davis [ctb], Viktoras Veitas [ctb], Weicheng Zhu [ctb], Wush Wu [ctb], Zachary Foster [ctb], Zhian N. Kamvar [ctb] (ORCID: ), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Yihui Xie ",
+ "Repository": "CRAN"
},
"labeling": {
"Package": "labeling",
"Version": "0.4.3",
"Source": "Repository",
- "Requirements": [
- "graphics",
- "stats"
- ]
+ "Type": "Package",
+ "Title": "Axis Labeling",
+ "Date": "2023-08-29",
+ "Author": "Justin Talbot,",
+ "Maintainer": "Nuno Sempere ",
+ "Description": "Functions which provide a range of axis labeling algorithms.",
+ "License": "MIT + file LICENSE | Unlimited",
+ "Collate": "'labeling.R'",
+ "NeedsCompilation": "no",
+ "Imports": [
+ "stats",
+ "graphics"
+ ],
+ "Repository": "CRAN"
},
"later": {
"Package": "later",
- "Version": "1.4.8",
- "Source": "Repository",
- "Requirements": [
- "R",
- "Rcpp",
+ "Version": "1.4.5",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "Utilities for Scheduling Functions to Execute Later with Event Loops",
+ "Authors@R": "c( person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Charlie\", \"Gao\", , \"charlie.gao@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-0750-061X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")), person(\"Marcus\", \"Geelnard\", role = c(\"ctb\", \"cph\"), comment = \"TinyCThread library, https://tinycthread.github.io/\"), person(\"Evan\", \"Nemerson\", role = c(\"ctb\", \"cph\"), comment = \"TinyCThread library, https://tinycthread.github.io/\") )",
+ "Description": "Executes arbitrary R or C functions some time after the current time, after the R execution stack has emptied. The functions are scheduled in an event loop.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://later.r-lib.org, https://github.com/r-lib/later",
+ "BugReports": "https://github.com/r-lib/later/issues",
+ "Depends": [
+ "R (>= 3.5)"
+ ],
+ "Imports": [
+ "Rcpp (>= 1.0.10)",
"rlang"
- ]
+ ],
+ "Suggests": [
+ "knitr",
+ "nanonext",
+ "promises",
+ "rmarkdown",
+ "testthat (>= 3.0.0)"
+ ],
+ "LinkingTo": [
+ "Rcpp"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-07-18",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "yes",
+ "Author": "Winston Chang [aut] (ORCID: ), Joe Cheng [aut], Charlie Gao [aut, cre] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: ), Marcus Geelnard [ctb, cph] (TinyCThread library, https://tinycthread.github.io/), Evan Nemerson [ctb, cph] (TinyCThread library, https://tinycthread.github.io/)",
+ "Maintainer": "Charlie Gao ",
+ "Repository": "CRAN"
},
"lazyeval": {
"Package": "lazyeval",
- "Version": "0.2.3",
+ "Version": "0.2.2",
"Source": "Repository",
- "Requirements": [
- "R",
- "rlang"
- ]
+ "Title": "Lazy (Non-Standard) Evaluation",
+ "Description": "An alternative approach to non-standard evaluation using formulas. Provides a full implementation of LISP style 'quasiquotation', making it easier to generate code with other code.",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", ,\"hadley@rstudio.com\", c(\"aut\", \"cre\")), person(\"RStudio\", role = \"cph\") )",
+ "License": "GPL-3",
+ "LazyData": "true",
+ "Depends": [
+ "R (>= 3.1.0)"
+ ],
+ "Suggests": [
+ "knitr",
+ "rmarkdown (>= 0.2.65)",
+ "testthat",
+ "covr"
+ ],
+ "VignetteBuilder": "knitr",
+ "RoxygenNote": "6.1.1",
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [aut, cre], RStudio [cph]",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"lifecycle": {
"Package": "lifecycle",
"Version": "1.0.5",
"Source": "Repository",
- "Requirements": [
- "cli",
- "R",
- "rlang"
- ]
+ "Title": "Manage the Life Cycle of your Package Functions",
+ "Authors@R": "c( person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Manage the life cycle of your exported functions with shared conventions, documentation badges, and user-friendly deprecation warnings.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://lifecycle.r-lib.org/, https://github.com/r-lib/lifecycle",
+ "BugReports": "https://github.com/r-lib/lifecycle/issues",
+ "Depends": [
+ "R (>= 3.6)"
+ ],
+ "Imports": [
+ "cli (>= 3.4.0)",
+ "rlang (>= 1.1.0)"
+ ],
+ "Suggests": [
+ "covr",
+ "knitr",
+ "lintr (>= 3.1.0)",
+ "rmarkdown",
+ "testthat (>= 3.0.1)",
+ "tibble",
+ "tidyverse",
+ "tools",
+ "vctrs",
+ "withr",
+ "xml2"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate, usethis",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "no",
+ "Author": "Lionel Henry [aut, cre], Hadley Wickham [aut] (ORCID: ), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Lionel Henry ",
+ "Repository": "CRAN"
},
"magrittr": {
"Package": "magrittr",
- "Version": "2.0.5",
- "Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Version": "2.0.4",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "A Forward-Pipe Operator for R",
+ "Authors@R": "c( person(\"Stefan Milton\", \"Bache\", , \"stefan@stefanbache.dk\", role = c(\"aut\", \"cph\"), comment = \"Original author and creator of magrittr\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = \"cre\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Provides a mechanism for chaining commands with a new forward-pipe operator, %>%. This operator will forward a value, or the result of an expression, into the next function call/expression. There is flexible support for the type of right-hand side expressions. For more information, see package vignette. To quote Rene Magritte, \"Ceci n'est pas un pipe.\"",
+ "License": "MIT + file LICENSE",
+ "URL": "https://magrittr.tidyverse.org, https://github.com/tidyverse/magrittr",
+ "BugReports": "https://github.com/tidyverse/magrittr/issues",
+ "Depends": [
+ "R (>= 3.4.0)"
+ ],
+ "Suggests": [
+ "covr",
+ "knitr",
+ "rlang",
+ "rmarkdown",
+ "testthat"
+ ],
+ "VignetteBuilder": "knitr",
+ "ByteCompile": "Yes",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "yes",
+ "Author": "Stefan Milton Bache [aut, cph] (Original author and creator of magrittr), Hadley Wickham [aut], Lionel Henry [cre], Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Lionel Henry ",
+ "Repository": "CRAN"
},
"memoise": {
"Package": "memoise",
"Version": "2.0.1",
"Source": "Repository",
- "Requirements": [
- "cachem",
- "rlang"
- ]
+ "Title": "'Memoisation' of Functions",
+ "Authors@R": "c(person(given = \"Hadley\", family = \"Wickham\", role = \"aut\", email = \"hadley@rstudio.com\"), person(given = \"Jim\", family = \"Hester\", role = \"aut\"), person(given = \"Winston\", family = \"Chang\", role = c(\"aut\", \"cre\"), email = \"winston@rstudio.com\"), person(given = \"Kirill\", family = \"Müller\", role = \"aut\", email = \"krlmlr+r@mailbox.org\"), person(given = \"Daniel\", family = \"Cook\", role = \"aut\", email = \"danielecook@gmail.com\"), person(given = \"Mark\", family = \"Edmondson\", role = \"ctb\", email = \"r@sunholo.com\"))",
+ "Description": "Cache the results of a function so that when you call it again with the same arguments it returns the previously computed value.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://memoise.r-lib.org, https://github.com/r-lib/memoise",
+ "BugReports": "https://github.com/r-lib/memoise/issues",
+ "Imports": [
+ "rlang (>= 0.4.10)",
+ "cachem"
+ ],
+ "Suggests": [
+ "digest",
+ "aws.s3",
+ "covr",
+ "googleAuthR",
+ "googleCloudStorageR",
+ "httr",
+ "testthat"
+ ],
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.1.2",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut], Jim Hester [aut], Winston Chang [aut, cre], Kirill Müller [aut], Daniel Cook [aut], Mark Edmondson [ctb]",
+ "Maintainer": "Winston Chang ",
+ "Repository": "CRAN"
},
"mime": {
"Package": "mime",
"Version": "0.13",
"Source": "Repository",
- "Requirements": [
+ "Type": "Package",
+ "Title": "Map Filenames to MIME Types",
+ "Authors@R": "c( person(\"Yihui\", \"Xie\", role = c(\"aut\", \"cre\"), email = \"xie@yihui.name\", comment = c(ORCID = \"0000-0003-0645-5666\", URL = \"https://yihui.org\")), person(\"Jeffrey\", \"Horner\", role = \"ctb\"), person(\"Beilei\", \"Bian\", role = \"ctb\") )",
+ "Description": "Guesses the MIME type from a filename extension using the data derived from /etc/mime.types in UNIX-type systems.",
+ "Imports": [
"tools"
- ]
+ ],
+ "License": "GPL",
+ "URL": "https://github.com/yihui/mime",
+ "BugReports": "https://github.com/yihui/mime/issues",
+ "RoxygenNote": "7.3.2",
+ "Encoding": "UTF-8",
+ "NeedsCompilation": "yes",
+ "Author": "Yihui Xie [aut, cre] (, https://yihui.org), Jeffrey Horner [ctb], Beilei Bian [ctb]",
+ "Maintainer": "Yihui Xie ",
+ "Repository": "CRAN"
},
"officer": {
"Package": "officer",
- "Version": "0.7.6",
+ "Version": "0.7.3",
"Source": "Repository",
- "Requirements": [
+ "Type": "Package",
+ "Title": "Manipulation of Microsoft Word and PowerPoint Documents",
+ "Authors@R": "c( person(\"David\", \"Gohel\", , \"david.gohel@ardata.fr\", role = c(\"aut\", \"cre\")), person(\"Stefan\", \"Moog\", , \"moogs@gmx.de\", role = \"aut\"), person(\"Mark\", \"Heckmann\", , \"heckmann.mark@gmail.com\", role = \"aut\", comment = c(ORCID = \"0000-0002-0736-7417\")), person(\"ArData\", role = \"cph\"), person(\"Frank\", \"Hangler\", , \"frank@plotandscatter.com\", role = \"ctb\", comment = \"function body_replace_all_text\"), person(\"Liz\", \"Sander\", , \"lsander@civisanalytics.com\", role = \"ctb\", comment = \"several documentation fixes\"), person(\"Anton\", \"Victorson\", , \"anton@victorson.se\", role = \"ctb\", comment = \"fixes xml structures\"), person(\"Jon\", \"Calder\", , \"jonmcalder@gmail.com\", role = \"ctb\", comment = \"update vignettes\"), person(\"John\", \"Harrold\", , \"john.m.harrold@gmail.com\", role = \"ctb\", comment = \"function annotate_base\"), person(\"John\", \"Muschelli\", , \"muschellij2@gmail.com\", role = \"ctb\", comment = \"google doc compatibility\"), person(\"Bill\", \"Denney\", , \"wdenney@humanpredictions.com\", role = \"ctb\", comment = c(ORCID = \"0000-0002-5759-428X\", \"function as.matrix.rpptx\")), person(\"Nikolai\", \"Beck\", , \"beck.nikolai@gmail.com\", role = \"ctb\", comment = \"set speaker notes for .pptx documents\"), person(\"Greg\", \"Leleu\", , \"gregoire.leleu@gmail.com\", role = \"ctb\", comment = \"fields functionality in ppt\"), person(\"Majid\", \"Eismann\", role = \"ctb\"), person(\"Wahiduzzaman\", \"Khan\", role = \"ctb\", comment = \"vectorization of remove_slide\"), person(\"Hongyuan\", \"Jia\", , \"hongyuanjia@cqust.edu.cn\", role = \"ctb\", comment = c(ORCID = \"0000-0002-0075-8183\")), person(\"Michael\", \"Stackhouse\", , \"mike.stackhouse@atorusresearch.com\", role = \"ctb\") )",
+ "Description": "Access and manipulate 'Microsoft Word', 'RTF' and 'Microsoft PowerPoint' documents from R. The package focuses on tabular and graphical reporting from R; it also provides two functions that let users get document content into data objects. A set of functions lets add and remove images, tables and paragraphs of text in new or existing documents. The package does not require any installation of Microsoft products to be able to write Microsoft files.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://ardata-fr.github.io/officeverse/, https://davidgohel.github.io/officer/",
+ "BugReports": "https://github.com/davidgohel/officer/issues",
+ "Imports": [
"cli",
"dplyr",
"graphics",
@@ -552,455 +1762,1584 @@
"tidyr",
"utils",
"uuid",
- "xml2",
- "zip"
- ]
+ "xml2 (>= 1.1.0)",
+ "zip (>= 2.1.0)"
+ ],
+ "Suggests": [
+ "devEMF",
+ "doconv (>= 0.3.0)",
+ "gdtools",
+ "ggplot2",
+ "knitr",
+ "magick",
+ "rmarkdown",
+ "rsvg",
+ "testthat",
+ "withr"
+ ],
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "Collate": "'core_properties.R' 'custom_properties.R' 'defunct.R' 'dev-utils.R' 'docx_add.R' 'docx_comments.R' 'docx_cursor.R' 'docx_part.R' 'docx_replace.R' 'docx_section.R' 'docx_settings.R' 'docx_styles.R' 'docx_utils_funs.R' 'empty_content.R' 'formatting_properties.R' 'fortify_docx.R' 'fortify_pptx.R' 'knitr_utils.R' 'officer.R' 'ooxml.R' 'ooxml_block_objects.R' 'ooxml_run_objects.R' 'openxml_content_type.R' 'openxml_document.R' 'pack_folder.R' 'ph_location.R' 'post-proc.R' 'ppt_class_dir_collection.R' 'ppt_classes.R' 'ppt_notes.R' 'ppt_ph_dedupe_layout.R' 'ppt_ph_manipulate.R' 'ppt_ph_rename_layout.R' 'ppt_ph_with_methods.R' 'pptx_informations.R' 'pptx_layout_helper.R' 'pptx_matrix.R' 'utils.R' 'pptx_slide_manip.R' 'read_docx.R' 'docx_write.R' 'read_docx_styles.R' 'read_pptx.R' 'read_xlsx.R' 'relationship.R' 'rtf.R' 'shape_properties.R' 'shorcuts.R' 'docx_append_context.R' 'utils-xml.R' 'deprecated.R' 'zzz.R'",
+ "NeedsCompilation": "no",
+ "Author": "David Gohel [aut, cre], Stefan Moog [aut], Mark Heckmann [aut] (ORCID: ), ArData [cph], Frank Hangler [ctb] (function body_replace_all_text), Liz Sander [ctb] (several documentation fixes), Anton Victorson [ctb] (fixes xml structures), Jon Calder [ctb] (update vignettes), John Harrold [ctb] (function annotate_base), John Muschelli [ctb] (google doc compatibility), Bill Denney [ctb] (ORCID: , function as.matrix.rpptx), Nikolai Beck [ctb] (set speaker notes for .pptx documents), Greg Leleu [ctb] (fields functionality in ppt), Majid Eismann [ctb], Wahiduzzaman Khan [ctb] (vectorization of remove_slide), Hongyuan Jia [ctb] (ORCID: ), Michael Stackhouse [ctb]",
+ "Maintainer": "David Gohel ",
+ "Repository": "CRAN"
},
"openssl": {
"Package": "openssl",
- "Version": "2.4.2",
- "Source": "Repository",
- "Requirements": [
+ "Version": "2.3.4",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "Toolkit for Encryption, Signatures and Certificates Based on OpenSSL",
+ "Authors@R": "c(person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Oliver\", \"Keyes\", role = \"ctb\"))",
+ "Description": "Bindings to OpenSSL libssl and libcrypto, plus custom SSH key parsers. Supports RSA, DSA and EC curves P-256, P-384, P-521, and curve25519. Cryptographic signatures can either be created and verified manually or via x509 certificates. AES can be used in cbc, ctr or gcm mode for symmetric encryption; RSA for asymmetric (public key) encryption or EC for Diffie Hellman. High-level envelope functions combine RSA and AES for encrypting arbitrary sized data. Other utilities include key generators, hash functions (md5, sha1, sha256, etc), base64 encoder, a secure random number generator, and 'bignum' math methods for manually performing crypto calculations on large multibyte integers.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://jeroen.r-universe.dev/openssl",
+ "BugReports": "https://github.com/jeroen/openssl/issues",
+ "SystemRequirements": "OpenSSL >= 1.0.2",
+ "VignetteBuilder": "knitr",
+ "Imports": [
"askpass"
- ]
+ ],
+ "Suggests": [
+ "curl",
+ "testthat (>= 2.1.0)",
+ "digest",
+ "knitr",
+ "rmarkdown",
+ "jsonlite",
+ "jose",
+ "sodium"
+ ],
+ "RoxygenNote": "7.3.2",
+ "Encoding": "UTF-8",
+ "NeedsCompilation": "yes",
+ "Author": "Jeroen Ooms [aut, cre] (ORCID: ), Oliver Keyes [ctb]",
+ "Maintainer": "Jeroen Ooms ",
+ "Repository": "CRAN"
},
"otel": {
"Package": "otel",
"Version": "0.2.0",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Title": "OpenTelemetry R API",
+ "Authors@R": "person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\"))",
+ "Description": "High-quality, ubiquitous, and portable telemetry to enable effective observability. OpenTelemetry is a collection of tools, APIs, and SDKs used to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior. This package implements the OpenTelemetry API: . Use this package as a dependency if you want to instrument your R package for OpenTelemetry.",
+ "License": "MIT + file LICENSE",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2.9000",
+ "Depends": [
+ "R (>= 3.6.0)"
+ ],
+ "Suggests": [
+ "callr",
+ "cli",
+ "glue",
+ "jsonlite",
+ "otelsdk",
+ "processx",
+ "shiny",
+ "spelling",
+ "testthat (>= 3.0.0)",
+ "utils",
+ "withr"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "URL": "https://otel.r-lib.org, https://github.com/r-lib/otel",
+ "Additional_repositories": "https://github.com/r-lib/otelsdk/releases/download/devel",
+ "BugReports": "https://github.com/r-lib/otel/issues",
+ "NeedsCompilation": "no",
+ "Author": "Gábor Csárdi [aut, cre]",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"pillar": {
"Package": "pillar",
"Version": "1.11.1",
"Source": "Repository",
- "Requirements": [
- "cli",
+ "Title": "Coloured Formatting for Columns",
+ "Authors@R": "c(person(given = \"Kirill\", family = \"M\\u00fcller\", role = c(\"aut\", \"cre\"), email = \"kirill@cynkra.com\", comment = c(ORCID = \"0000-0002-1416-3412\")), person(given = \"Hadley\", family = \"Wickham\", role = \"aut\"), person(given = \"RStudio\", role = \"cph\"))",
+ "Description": "Provides 'pillar' and 'colonnade' generics designed for formatting columns of data using the full range of colours provided by modern terminals.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://pillar.r-lib.org/, https://github.com/r-lib/pillar",
+ "BugReports": "https://github.com/r-lib/pillar/issues",
+ "Imports": [
+ "cli (>= 2.3.0)",
"glue",
"lifecycle",
- "rlang",
- "utf8",
+ "rlang (>= 1.0.2)",
+ "utf8 (>= 1.1.0)",
"utils",
- "vctrs"
- ]
+ "vctrs (>= 0.5.0)"
+ ],
+ "Suggests": [
+ "bit64",
+ "DBI",
+ "debugme",
+ "DiagrammeR",
+ "dplyr",
+ "formattable",
+ "ggplot2",
+ "knitr",
+ "lubridate",
+ "nanotime",
+ "nycflights13",
+ "palmerpenguins",
+ "rmarkdown",
+ "scales",
+ "stringi",
+ "survival",
+ "testthat (>= 3.1.1)",
+ "tibble",
+ "units (>= 0.7.2)",
+ "vdiffr",
+ "withr"
+ ],
+ "VignetteBuilder": "knitr",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3.9000",
+ "Config/testthat/edition": "3",
+ "Config/testthat/parallel": "true",
+ "Config/testthat/start-first": "format_multi_fuzz, format_multi_fuzz_2, format_multi, ctl_colonnade, ctl_colonnade_1, ctl_colonnade_2",
+ "Config/autostyle/scope": "line_breaks",
+ "Config/autostyle/strict": "true",
+ "Config/gha/extra-packages": "units=?ignore-before-r=4.3.0",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "NeedsCompilation": "no",
+ "Author": "Kirill Mller [aut, cre] (ORCID: ), Hadley Wickham [aut], RStudio [cph]",
+ "Maintainer": "Kirill Mller ",
+ "Repository": "CRAN"
},
"pkgbuild": {
"Package": "pkgbuild",
"Version": "1.4.8",
"Source": "Repository",
- "Requirements": [
- "callr",
- "cli",
+ "Title": "Find Tools Needed to Build R Packages",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", role = \"aut\"), person(\"Jim\", \"Hester\", role = \"aut\"), person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Provides functions used to build R packages. Locates compilers needed to build R packages on various platforms and ensures the PATH is configured appropriately so R can use them.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://github.com/r-lib/pkgbuild, https://pkgbuild.r-lib.org",
+ "BugReports": "https://github.com/r-lib/pkgbuild/issues",
+ "Depends": [
+ "R (>= 3.5)"
+ ],
+ "Imports": [
+ "callr (>= 3.2.0)",
+ "cli (>= 3.4.0)",
"desc",
"processx",
- "R",
"R6"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "cpp11",
+ "knitr",
+ "Rcpp",
+ "rmarkdown",
+ "testthat (>= 3.2.0)",
+ "withr (>= 2.3.0)"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-04-30",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut], Jim Hester [aut], Gábor Csárdi [aut, cre], Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"pkgconfig": {
"Package": "pkgconfig",
"Version": "2.0.3",
"Source": "Repository",
- "Requirements": [
+ "Title": "Private Configuration for 'R' Packages",
+ "Author": "Gábor Csárdi",
+ "Maintainer": "Gábor Csárdi ",
+ "Description": "Set configuration options on a per-package basis. Options set by a given package only apply to that package, other packages are unaffected.",
+ "License": "MIT + file LICENSE",
+ "LazyData": "true",
+ "Imports": [
"utils"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "testthat",
+ "disposables (>= 1.0.3)"
+ ],
+ "URL": "https://github.com/r-lib/pkgconfig#readme",
+ "BugReports": "https://github.com/r-lib/pkgconfig/issues",
+ "Encoding": "UTF-8",
+ "NeedsCompilation": "no",
+ "Repository": "CRAN"
},
"plotly": {
"Package": "plotly",
- "Version": "4.12.1",
- "Source": "Repository",
- "Requirements": [
- "base64enc",
- "crosstalk",
- "data.table",
- "digest",
- "dplyr",
- "ggplot2",
- "htmltools",
- "htmlwidgets",
- "httr",
- "jsonlite",
+ "Version": "4.12.0",
+ "Source": "Repository",
+ "Title": "Create Interactive Web Graphics via 'plotly.js'",
+ "Authors@R": "c(person(\"Carson\", \"Sievert\", role = c(\"aut\", \"cre\"), email = \"cpsievert1@gmail.com\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Chris\", \"Parmer\", role = \"aut\", email = \"chris@plot.ly\"), person(\"Toby\", \"Hocking\", role = \"aut\", email = \"tdhock5@gmail.com\"), person(\"Scott\", \"Chamberlain\", role = \"aut\", email = \"myrmecocystus@gmail.com\"), person(\"Karthik\", \"Ram\", role = \"aut\", email = \"karthik.ram@gmail.com\"), person(\"Marianne\", \"Corvellec\", role = \"aut\", email = \"marianne.corvellec@igdore.org\", comment = c(ORCID = \"0000-0002-1994-3581\")), person(\"Pedro\", \"Despouy\", role = \"aut\", email = \"pedro@plot.ly\"), person(\"Salim\", \"Brüggemann\", role = \"ctb\", email = \"salim-b@pm.me\", comment = c(ORCID = \"0000-0002-5329-5987\")), person(\"Plotly Technologies Inc.\", role = \"cph\"))",
+ "License": "MIT + file LICENSE",
+ "Description": "Create interactive web graphics from 'ggplot2' graphs and/or a custom interface to the (MIT-licensed) JavaScript library 'plotly.js' inspired by the grammar of graphics.",
+ "URL": "https://plotly-r.com, https://github.com/plotly/plotly.R, https://plotly.com/r/",
+ "BugReports": "https://github.com/plotly/plotly.R/issues",
+ "Depends": [
+ "R (>= 3.5.0)",
+ "ggplot2 (>= 3.0.0)"
+ ],
+ "Imports": [
+ "tools",
+ "scales",
+ "httr (>= 1.3.0)",
+ "jsonlite (>= 1.6)",
"magrittr",
- "promises",
- "purrr",
- "R",
+ "digest",
+ "viridisLite",
+ "base64enc",
+ "htmltools (>= 0.3.6)",
+ "htmlwidgets (>= 1.5.2.9001)",
+ "tidyr (>= 1.0.0)",
"RColorBrewer",
- "rlang",
- "scales",
- "tibble",
- "tidyr",
- "tools",
+ "dplyr",
"vctrs",
- "viridisLite"
- ]
+ "tibble",
+ "lazyeval (>= 0.2.0)",
+ "rlang (>= 1.0.0)",
+ "crosstalk",
+ "purrr",
+ "data.table",
+ "promises"
+ ],
+ "Suggests": [
+ "MASS",
+ "maps",
+ "hexbin",
+ "ggthemes",
+ "GGally",
+ "ggalluvial",
+ "testthat",
+ "knitr",
+ "shiny (>= 1.1.0)",
+ "shinytest2",
+ "curl",
+ "rmarkdown",
+ "Cairo",
+ "broom",
+ "webshot",
+ "listviewer",
+ "dendextend",
+ "sf",
+ "png",
+ "IRdisplay",
+ "processx",
+ "plotlyGeoAssets",
+ "forcats",
+ "withr",
+ "palmerpenguins",
+ "rversions",
+ "reticulate",
+ "rsvg",
+ "ggridges"
+ ],
+ "LazyData": "true",
+ "RoxygenNote": "7.3.3",
+ "Encoding": "UTF-8",
+ "Config/Needs/check": "tidyverse/ggplot2, ggobi/GGally, rcmdcheck, devtools, reshape2, s2",
+ "NeedsCompilation": "no",
+ "Author": "Carson Sievert [aut, cre] (ORCID: ), Chris Parmer [aut], Toby Hocking [aut], Scott Chamberlain [aut], Karthik Ram [aut], Marianne Corvellec [aut] (ORCID: ), Pedro Despouy [aut], Salim Brüggemann [ctb] (ORCID: ), Plotly Technologies Inc. [cph]",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"plyr": {
"Package": "plyr",
"Version": "1.8.9",
"Source": "Repository",
- "Requirements": [
- "R",
+ "Title": "Tools for Splitting, Applying and Combining Data",
+ "Authors@R": "person(\"Hadley\", \"Wickham\", , \"hadley@rstudio.com\", role = c(\"aut\", \"cre\"))",
+ "Description": "A set of tools that solves a common set of problems: you need to break a big problem down into manageable pieces, operate on each piece and then put all the pieces back together. For example, you might want to fit a model to each spatial location or time point in your study, summarise data by panels or collapse high-dimensional arrays to simpler summary statistics. The development of 'plyr' has been generously supported by 'Becton Dickinson'.",
+ "License": "MIT + file LICENSE",
+ "URL": "http://had.co.nz/plyr, https://github.com/hadley/plyr",
+ "BugReports": "https://github.com/hadley/plyr/issues",
+ "Depends": [
+ "R (>= 3.1.0)"
+ ],
+ "Imports": [
+ "Rcpp (>= 0.11.0)"
+ ],
+ "Suggests": [
+ "abind",
+ "covr",
+ "doParallel",
+ "foreach",
+ "iterators",
+ "itertools",
+ "tcltk",
+ "testthat"
+ ],
+ "LinkingTo": [
"Rcpp"
- ]
+ ],
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "7.2.3",
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [aut, cre]",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"processx": {
"Package": "processx",
- "Version": "3.9.0",
- "Source": "Repository",
- "Requirements": [
- "ps",
- "R",
+ "Version": "3.8.6",
+ "Source": "Repository",
+ "Title": "Execute and Control System Processes",
+ "Authors@R": "c( person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\", \"cph\"), comment = c(ORCID = \"0000-0001-7098-9676\")), person(\"Winston\", \"Chang\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(\"Ascent Digital Services\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "Tools to run system processes in the background. It can check if a background process is running; wait on a background process to finish; get the exit status of finished processes; kill background processes. It can read the standard output and error of the processes, using non-blocking connections. 'processx' can poll a process for standard output or error, with a timeout. It can also poll several processes at once.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://processx.r-lib.org, https://github.com/r-lib/processx",
+ "BugReports": "https://github.com/r-lib/processx/issues",
+ "Depends": [
+ "R (>= 3.4.0)"
+ ],
+ "Imports": [
+ "ps (>= 1.2.0)",
"R6",
"utils"
- ]
+ ],
+ "Suggests": [
+ "callr (>= 3.7.3)",
+ "cli (>= 3.3.0)",
+ "codetools",
+ "covr",
+ "curl",
+ "debugme",
+ "parallel",
+ "rlang (>= 1.0.2)",
+ "testthat (>= 3.0.0)",
+ "webfakes",
+ "withr"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.1.9000",
+ "NeedsCompilation": "yes",
+ "Author": "Gábor Csárdi [aut, cre, cph] (), Winston Chang [aut], Posit Software, PBC [cph, fnd], Ascent Digital Services [cph, fnd]",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"promises": {
"Package": "promises",
"Version": "1.5.0",
"Source": "Repository",
- "Requirements": [
- "fastmap",
+ "Type": "Package",
+ "Title": "Abstractions for Promise-Based Asynchronous Programming",
+ "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Barret\", \"Schloerke\", , \"barret@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Charlie\", \"Gao\", , \"charlie.gao@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0002-0750-061X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Provides fundamental abstractions for doing asynchronous programming in R using promises. Asynchronous programming is useful for allowing a single R process to orchestrate multiple tasks in the background while also attending to something else. Semantics are similar to 'JavaScript' promises, but with a syntax that is idiomatic R.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rstudio.github.io/promises/, https://github.com/rstudio/promises",
+ "BugReports": "https://github.com/rstudio/promises/issues",
+ "Depends": [
+ "R (>= 4.1.0)"
+ ],
+ "Imports": [
+ "fastmap (>= 1.1.0)",
"later",
"lifecycle",
- "magrittr",
- "otel",
- "R",
+ "magrittr (>= 1.5)",
+ "otel (>= 0.2.0)",
"R6",
"rlang"
- ]
+ ],
+ "Suggests": [
+ "future (>= 1.21.0)",
+ "knitr",
+ "mirai",
+ "otelsdk (>= 0.2.0)",
+ "purrr",
+ "Rcpp",
+ "rmarkdown",
+ "spelling",
+ "testthat (>= 3.0.0)",
+ "vembedr"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "rsconnect, tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-05-27",
+ "Encoding": "UTF-8",
+ "Language": "en-US",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "no",
+ "Author": "Joe Cheng [aut], Barret Schloerke [aut, cre] (ORCID: ), Winston Chang [aut] (ORCID: ), Charlie Gao [aut] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Barret Schloerke ",
+ "Repository": "CRAN"
},
"ps": {
"Package": "ps",
- "Version": "1.9.3",
- "Source": "Repository",
- "Requirements": [
- "R",
+ "Version": "1.9.1",
+ "Source": "Repository",
+ "Title": "List, Query, Manipulate System Processes",
+ "Authors@R": "c( person(\"Jay\", \"Loden\", role = \"aut\"), person(\"Dave\", \"Daeschler\", role = \"aut\"), person(\"Giampaolo\", \"Rodola'\", role = \"aut\"), person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = c(\"aut\", \"cre\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "List, query and manipulate all system processes, on 'Windows', 'Linux' and 'macOS'.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://github.com/r-lib/ps, https://ps.r-lib.org/",
+ "BugReports": "https://github.com/r-lib/ps/issues",
+ "Depends": [
+ "R (>= 3.4)"
+ ],
+ "Imports": [
"utils"
- ]
+ ],
+ "Suggests": [
+ "callr",
+ "covr",
+ "curl",
+ "pillar",
+ "pingr",
+ "processx (>= 3.1.0)",
+ "R6",
+ "rlang",
+ "testthat (>= 3.0.0)",
+ "webfakes",
+ "withr"
+ ],
+ "Biarch": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "yes",
+ "Author": "Jay Loden [aut], Dave Daeschler [aut], Giampaolo Rodola' [aut], Gábor Csárdi [aut, cre], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Gábor Csárdi ",
+ "Repository": "CRAN"
},
"purrr": {
"Package": "purrr",
- "Version": "1.2.2",
+ "Version": "1.2.1",
"Source": "Repository",
- "Requirements": [
- "cli",
- "lifecycle",
- "magrittr",
- "R",
- "rlang",
- "vctrs"
- ]
+ "Title": "Functional Programming Tools",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"https://ror.org/03wc8by49\")) )",
+ "Description": "A complete and consistent functional programming toolkit for R.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://purrr.tidyverse.org/, https://github.com/tidyverse/purrr",
+ "BugReports": "https://github.com/tidyverse/purrr/issues",
+ "Depends": [
+ "R (>= 4.1)"
+ ],
+ "Imports": [
+ "cli (>= 3.6.1)",
+ "lifecycle (>= 1.0.3)",
+ "magrittr (>= 1.5.0)",
+ "rlang (>= 1.1.1)",
+ "vctrs (>= 0.6.3)"
+ ],
+ "Suggests": [
+ "carrier (>= 0.3.0)",
+ "covr",
+ "dplyr (>= 0.7.8)",
+ "httr",
+ "knitr",
+ "lubridate",
+ "mirai (>= 2.5.1)",
+ "rmarkdown",
+ "testthat (>= 3.0.0)",
+ "tibble",
+ "tidyselect"
+ ],
+ "LinkingTo": [
+ "cli"
+ ],
+ "VignetteBuilder": "knitr",
+ "Biarch": "true",
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate, tidyr",
+ "Config/testthat/edition": "3",
+ "Config/testthat/parallel": "TRUE",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [aut, cre] (ORCID: ), Lionel Henry [aut], Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"ragg": {
"Package": "ragg",
- "Version": "1.5.2",
+ "Version": "1.5.0",
"Source": "Repository",
- "Requirements": [
+ "Type": "Package",
+ "Title": "Graphic Devices Based on AGG",
+ "Authors@R": "c( person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Maxim\", \"Shemanarev\", role = c(\"aut\", \"cph\"), comment = \"Author of AGG\"), person(\"Tony\", \"Juricic\", , \"tonygeek@yahoo.com\", role = c(\"ctb\", \"cph\"), comment = \"Contributor to AGG\"), person(\"Milan\", \"Marusinec\", , \"milan@marusinec.sk\", role = c(\"ctb\", \"cph\"), comment = \"Contributor to AGG\"), person(\"Spencer\", \"Garrett\", role = \"ctb\", comment = \"Contributor to AGG\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Description": "Anti-Grain Geometry (AGG) is a high-quality and high-performance 2D drawing library. The 'ragg' package provides a set of graphic devices based on AGG to use as alternative to the raster devices provided through the 'grDevices' package.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://ragg.r-lib.org, https://github.com/r-lib/ragg",
+ "BugReports": "https://github.com/r-lib/ragg/issues",
+ "Imports": [
+ "systemfonts (>= 1.0.3)",
+ "textshaping (>= 0.3.0)"
+ ],
+ "Suggests": [
+ "covr",
+ "graphics",
+ "grid",
+ "testthat (>= 3.0.0)"
+ ],
+ "LinkingTo": [
"systemfonts",
"textshaping"
- ]
+ ],
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "ggplot2, devoid, magick, bench, tidyr, ggridges, hexbin, sessioninfo, pkgdown, tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-04-25",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "SystemRequirements": "freetype2, libpng, libtiff, libjpeg, libwebp, libwebpmux",
+ "NeedsCompilation": "yes",
+ "Author": "Thomas Lin Pedersen [cre, aut] (ORCID: ), Maxim Shemanarev [aut, cph] (Author of AGG), Tony Juricic [ctb, cph] (Contributor to AGG), Milan Marusinec [ctb, cph] (Contributor to AGG), Spencer Garrett [ctb] (Contributor to AGG), Posit Software, PBC [cph, fnd] (ROR: )",
+ "Repository": "CRAN"
},
"rappdirs": {
"Package": "rappdirs",
"Version": "0.3.4",
"Source": "Repository",
- "Requirements": [
- "R"
- ]
+ "Type": "Package",
+ "Title": "Application Directories: Determine Where to Save Data, Caches, and Logs",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"trl\", \"cre\", \"cph\")), person(\"Sridhar\", \"Ratnakumar\", role = \"aut\"), person(\"Trent\", \"Mick\", role = \"aut\"), person(\"ActiveState\", role = \"cph\", comment = \"R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs\"), person(\"Eddy\", \"Petrisor\", role = \"ctb\"), person(\"Trevor\", \"Davis\", role = c(\"trl\", \"aut\"), comment = c(ORCID = \"0000-0001-6341-4639\")), person(\"Gabor\", \"Csardi\", role = \"ctb\"), person(\"Gregory\", \"Jefferis\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "An easy way to determine which directories on the users computer you should use to save data, caches and logs. A port of Python's 'Appdirs' () to R.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rappdirs.r-lib.org, https://github.com/r-lib/rappdirs",
+ "BugReports": "https://github.com/r-lib/rappdirs/issues",
+ "Depends": [
+ "R (>= 4.1)"
+ ],
+ "Suggests": [
+ "covr",
+ "roxygen2",
+ "testthat (>= 3.2.0)",
+ "withr"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-05-05",
+ "Copyright": "Original python appdirs module copyright (c) 2010 ActiveState Software Inc. R port copyright Hadley Wickham, Posit, PBC. See file LICENSE for details.",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [trl, cre, cph], Sridhar Ratnakumar [aut], Trent Mick [aut], ActiveState [cph] (R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs), Eddy Petrisor [ctb], Trevor Davis [trl, aut] (ORCID: ), Gabor Csardi [ctb], Gregory Jefferis [ctb], Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
+ },
+ "renv": {
+ "Package": "renv",
+ "Version": "1.1.7",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "Project Environments",
+ "Authors@R": "c( person(\"Kevin\", \"Ushey\", role = c(\"aut\", \"cre\"), email = \"kevin@rstudio.com\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Hadley\", \"Wickham\", role = c(\"aut\"), email = \"hadley@rstudio.com\", comment = c(ORCID = \"0000-0003-4757-117X\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "A dependency management toolkit for R. Using 'renv', you can create and manage project-local R libraries, save the state of these libraries to a 'lockfile', and later restore your library as required. Together, these tools can help make your projects more isolated, portable, and reproducible.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rstudio.github.io/renv/, https://github.com/rstudio/renv",
+ "BugReports": "https://github.com/rstudio/renv/issues",
+ "Imports": [
+ "utils"
+ ],
+ "Suggests": [
+ "BiocManager",
+ "cli",
+ "compiler",
+ "covr",
+ "cpp11",
+ "curl",
+ "devtools",
+ "generics",
+ "gitcreds",
+ "jsonlite",
+ "jsonvalidate",
+ "knitr",
+ "miniUI",
+ "modules",
+ "packrat",
+ "pak",
+ "R6",
+ "remotes",
+ "reticulate",
+ "rmarkdown",
+ "rstudioapi",
+ "shiny",
+ "testthat",
+ "uuid",
+ "waldo",
+ "yaml",
+ "webfakes"
+ ],
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/testthat/parallel": "true",
+ "Config/testthat/start-first": "bioconductor,python,install,restore,snapshot,retrieve,remotes",
+ "NeedsCompilation": "no",
+ "Author": "Kevin Ushey [aut, cre] (ORCID: ), Hadley Wickham [aut] (ORCID: ), Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Kevin Ushey ",
+ "Repository": "CRAN"
},
"rlang": {
"Package": "rlang",
- "Version": "1.3.0",
- "Source": "Repository",
- "Requirements": [
- "R",
+ "Version": "1.1.7",
+ "Source": "Repository",
+ "Title": "Functions for Base Types and Core R and 'Tidyverse' Features",
+ "Description": "A toolbox for working with base types, core R features like the condition system, and core 'Tidyverse' features like tidy evaluation.",
+ "Authors@R": "c( person(\"Lionel\", \"Henry\", ,\"lionel@posit.co\", c(\"aut\", \"cre\")), person(\"Hadley\", \"Wickham\", ,\"hadley@posit.co\", \"aut\"), person(given = \"mikefc\", email = \"mikefc@coolbutuseless.com\", role = \"cph\", comment = \"Hash implementation based on Mike's xxhashlite\"), person(given = \"Yann\", family = \"Collet\", role = \"cph\", comment = \"Author of the embedded xxHash library\"), person(given = \"Posit, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "License": "MIT + file LICENSE",
+ "ByteCompile": "true",
+ "Biarch": "true",
+ "Depends": [
+ "R (>= 4.0.0)"
+ ],
+ "Imports": [
"utils"
- ]
+ ],
+ "Suggests": [
+ "cli (>= 3.1.0)",
+ "covr",
+ "crayon",
+ "desc",
+ "fs",
+ "glue",
+ "knitr",
+ "magrittr",
+ "methods",
+ "pillar",
+ "pkgload",
+ "rmarkdown",
+ "stats",
+ "testthat (>= 3.2.0)",
+ "tibble",
+ "usethis",
+ "vctrs (>= 0.2.3)",
+ "withr"
+ ],
+ "Enhances": [
+ "winch"
+ ],
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "URL": "https://rlang.r-lib.org, https://github.com/r-lib/rlang",
+ "BugReports": "https://github.com/r-lib/rlang/issues",
+ "Config/build/compilation-database": "true",
+ "Config/testthat/edition": "3",
+ "Config/Needs/website": "dplyr, tidyverse/tidytemplate",
+ "NeedsCompilation": "yes",
+ "Author": "Lionel Henry [aut, cre], Hadley Wickham [aut], mikefc [cph] (Hash implementation based on Mike's xxhashlite), Yann Collet [cph] (Author of the embedded xxHash library), Posit, PBC [cph, fnd]",
+ "Maintainer": "Lionel Henry ",
+ "Repository": "CRAN"
},
"rmarkdown": {
"Package": "rmarkdown",
- "Version": "2.32",
- "Source": "Repository",
- "Requirements": [
- "bslib",
- "evaluate",
- "fontawesome",
- "htmltools",
+ "Version": "2.30",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "Dynamic Documents for R",
+ "Authors@R": "c( person(\"JJ\", \"Allaire\", , \"jj@posit.co\", role = \"aut\"), person(\"Yihui\", \"Xie\", , \"xie@yihui.name\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0003-0645-5666\")), person(\"Christophe\", \"Dervieux\", , \"cderv@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-4474-2498\")), person(\"Jonathan\", \"McPherson\", , \"jonathan@posit.co\", role = \"aut\"), person(\"Javier\", \"Luraschi\", role = \"aut\"), person(\"Kevin\", \"Ushey\", , \"kevin@posit.co\", role = \"aut\"), person(\"Aron\", \"Atkins\", , \"aron@posit.co\", role = \"aut\"), person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Joe\", \"Cheng\", , \"joe@posit.co\", role = \"aut\"), person(\"Winston\", \"Chang\", , \"winston@posit.co\", role = \"aut\"), person(\"Richard\", \"Iannone\", , \"rich@posit.co\", role = \"aut\", comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Andrew\", \"Dunning\", role = \"ctb\", comment = c(ORCID = \"0000-0003-0464-5036\")), person(\"Atsushi\", \"Yasumoto\", role = c(\"ctb\", \"cph\"), comment = c(ORCID = \"0000-0002-8335-495X\", cph = \"Number sections Lua filter\")), person(\"Barret\", \"Schloerke\", role = \"ctb\"), person(\"Carson\", \"Sievert\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Devon\", \"Ryan\", , \"dpryan79@gmail.com\", role = \"ctb\", comment = c(ORCID = \"0000-0002-8549-0971\")), person(\"Frederik\", \"Aust\", , \"frederik.aust@uni-koeln.de\", role = \"ctb\", comment = c(ORCID = \"0000-0003-4900-788X\")), person(\"Jeff\", \"Allen\", , \"jeff@posit.co\", role = \"ctb\"), person(\"JooYoung\", \"Seo\", role = \"ctb\", comment = c(ORCID = \"0000-0002-4064-6012\")), person(\"Malcolm\", \"Barrett\", role = \"ctb\"), person(\"Rob\", \"Hyndman\", , \"Rob.Hyndman@monash.edu\", role = \"ctb\"), person(\"Romain\", \"Lesur\", role = \"ctb\"), person(\"Roy\", \"Storey\", role = \"ctb\"), person(\"Ruben\", \"Arslan\", , \"ruben.arslan@uni-goettingen.de\", role = \"ctb\"), person(\"Sergio\", \"Oller\", role = \"ctb\"), person(given = \"Posit Software, PBC\", role = c(\"cph\", \"fnd\")), person(, \"jQuery UI contributors\", role = c(\"ctb\", \"cph\"), comment = \"jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt\"), person(\"Mark\", \"Otto\", role = \"ctb\", comment = \"Bootstrap library\"), person(\"Jacob\", \"Thornton\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Bootstrap contributors\", role = \"ctb\", comment = \"Bootstrap library\"), person(, \"Twitter, Inc\", role = \"cph\", comment = \"Bootstrap library\"), person(\"Alexander\", \"Farkas\", role = c(\"ctb\", \"cph\"), comment = \"html5shiv library\"), person(\"Scott\", \"Jehl\", role = c(\"ctb\", \"cph\"), comment = \"Respond.js library\"), person(\"Ivan\", \"Sagalaev\", role = c(\"ctb\", \"cph\"), comment = \"highlight.js library\"), person(\"Greg\", \"Franko\", role = c(\"ctb\", \"cph\"), comment = \"tocify library\"), person(\"John\", \"MacFarlane\", role = c(\"ctb\", \"cph\"), comment = \"Pandoc templates\"), person(, \"Google, Inc.\", role = c(\"ctb\", \"cph\"), comment = \"ioslides library\"), person(\"Dave\", \"Raggett\", role = \"ctb\", comment = \"slidy library\"), person(, \"W3C\", role = \"cph\", comment = \"slidy library\"), person(\"Dave\", \"Gandy\", role = c(\"ctb\", \"cph\"), comment = \"Font-Awesome\"), person(\"Ben\", \"Sperry\", role = \"ctb\", comment = \"Ionicons\"), person(, \"Drifty\", role = \"cph\", comment = \"Ionicons\"), person(\"Aidan\", \"Lister\", role = c(\"ctb\", \"cph\"), comment = \"jQuery StickyTabs\"), person(\"Benct Philip\", \"Jonsson\", role = c(\"ctb\", \"cph\"), comment = \"pagebreak Lua filter\"), person(\"Albert\", \"Krewinkel\", role = c(\"ctb\", \"cph\"), comment = \"pagebreak Lua filter\") )",
+ "Description": "Convert R Markdown documents into a variety of formats.",
+ "License": "GPL-3",
+ "URL": "https://github.com/rstudio/rmarkdown, https://pkgs.rstudio.com/rmarkdown/",
+ "BugReports": "https://github.com/rstudio/rmarkdown/issues",
+ "Depends": [
+ "R (>= 3.0)"
+ ],
+ "Imports": [
+ "bslib (>= 0.2.5.1)",
+ "evaluate (>= 0.13)",
+ "fontawesome (>= 0.5.0)",
+ "htmltools (>= 0.5.1)",
"jquerylib",
"jsonlite",
- "knitr",
+ "knitr (>= 1.43)",
"methods",
- "R",
- "tinytex",
+ "tinytex (>= 0.31)",
"tools",
"utils",
- "xfun",
- "yaml"
- ]
+ "xfun (>= 0.36)",
+ "yaml (>= 2.1.19)"
+ ],
+ "Suggests": [
+ "digest",
+ "dygraphs",
+ "fs",
+ "rsconnect",
+ "downlit (>= 0.4.0)",
+ "katex (>= 1.4.0)",
+ "sass (>= 0.4.0)",
+ "shiny (>= 1.6.0)",
+ "testthat (>= 3.0.3)",
+ "tibble",
+ "vctrs",
+ "cleanrmd",
+ "withr (>= 2.4.2)",
+ "xml2"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "rstudio/quillt, pkgdown",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "SystemRequirements": "pandoc (>= 1.14) - http://pandoc.org",
+ "NeedsCompilation": "no",
+ "Author": "JJ Allaire [aut], Yihui Xie [aut, cre] (ORCID: ), Christophe Dervieux [aut] (ORCID: ), Jonathan McPherson [aut], Javier Luraschi [aut], Kevin Ushey [aut], Aron Atkins [aut], Hadley Wickham [aut], Joe Cheng [aut], Winston Chang [aut], Richard Iannone [aut] (ORCID: ), Andrew Dunning [ctb] (ORCID: ), Atsushi Yasumoto [ctb, cph] (ORCID: , cph: Number sections Lua filter), Barret Schloerke [ctb], Carson Sievert [ctb] (ORCID: ), Devon Ryan [ctb] (ORCID: ), Frederik Aust [ctb] (ORCID: ), Jeff Allen [ctb], JooYoung Seo [ctb] (ORCID: ), Malcolm Barrett [ctb], Rob Hyndman [ctb], Romain Lesur [ctb], Roy Storey [ctb], Ruben Arslan [ctb], Sergio Oller [ctb], Posit Software, PBC [cph, fnd], jQuery UI contributors [ctb, cph] (jQuery UI library; authors listed in inst/rmd/h/jqueryui/AUTHORS.txt), Mark Otto [ctb] (Bootstrap library), Jacob Thornton [ctb] (Bootstrap library), Bootstrap contributors [ctb] (Bootstrap library), Twitter, Inc [cph] (Bootstrap library), Alexander Farkas [ctb, cph] (html5shiv library), Scott Jehl [ctb, cph] (Respond.js library), Ivan Sagalaev [ctb, cph] (highlight.js library), Greg Franko [ctb, cph] (tocify library), John MacFarlane [ctb, cph] (Pandoc templates), Google, Inc. [ctb, cph] (ioslides library), Dave Raggett [ctb] (slidy library), W3C [cph] (slidy library), Dave Gandy [ctb, cph] (Font-Awesome), Ben Sperry [ctb] (Ionicons), Drifty [cph] (Ionicons), Aidan Lister [ctb, cph] (jQuery StickyTabs), Benct Philip Jonsson [ctb, cph] (pagebreak Lua filter), Albert Krewinkel [ctb, cph] (pagebreak Lua filter)",
+ "Maintainer": "Yihui Xie ",
+ "Repository": "CRAN"
},
"rvg": {
"Package": "rvg",
- "Version": "0.4.2",
- "Source": "Repository",
- "Requirements": [
- "gdtools",
+ "Version": "0.4.0",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "R Graphics Devices for 'Office' Vector Graphics Output",
+ "Authors@R": "c( person(\"David\", \"Gohel\", , \"david.gohel@ardata.fr\", role = c(\"aut\", \"cre\")), person(\"ArData\", role = \"cph\"), person(\"Bob\", \"Rudis\", role = \"ctb\", comment = \"the javascript code used by function set_attr\"), person(\"Francois\", \"Brunetti\", , \"francois.brunetti@lysis-consultants.fr\", role = \"ctb\", comment = \"clipping algorithms\") )",
+ "Description": "Vector Graphics devices for 'Microsoft PowerPoint' and 'Microsoft Excel'. Functions extending package 'officer' are provided to embed 'DrawingML' graphics into 'Microsoft PowerPoint' presentations and 'Microsoft Excel' workbooks.",
+ "License": "GPL-3",
+ "URL": "https://ardata-fr.github.io/officeverse/, https://davidgohel.github.io/rvg/",
+ "BugReports": "https://github.com/davidgohel/rvg/issues",
+ "Depends": [
+ "R (>= 3.0)"
+ ],
+ "Imports": [
+ "gdtools (>= 0.3.3)",
"grDevices",
- "officer",
- "R",
- "Rcpp",
+ "officer (>= 0.6.2)",
+ "Rcpp (>= 0.12.12)",
"rlang",
"systemfonts",
- "xml2"
- ]
+ "xml2 (>= 1.0.0)"
+ ],
+ "Suggests": [
+ "grid",
+ "testthat"
+ ],
+ "LinkingTo": [
+ "Rcpp",
+ "systemfonts"
+ ],
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3",
+ "SystemRequirements": "libpng",
+ "NeedsCompilation": "yes",
+ "Author": "David Gohel [aut, cre], ArData [cph], Bob Rudis [ctb] (the javascript code used by function set_attr), Francois Brunetti [ctb] (clipping algorithms)",
+ "Maintainer": "David Gohel ",
+ "Repository": "CRAN"
},
"sass": {
"Package": "sass",
"Version": "0.4.10",
"Source": "Repository",
- "Requirements": [
- "fs",
- "htmltools",
+ "Type": "Package",
+ "Title": "Syntactically Awesome Style Sheets ('Sass')",
+ "Description": "An 'SCSS' compiler, powered by the 'LibSass' library. With this, R developers can use variables, inheritance, and functions to generate dynamic style sheets. The package uses the 'Sass CSS' extension language, which is stable, powerful, and CSS compatible.",
+ "Authors@R": "c( person(\"Joe\", \"Cheng\", , \"joe@rstudio.com\", \"aut\"), person(\"Timothy\", \"Mastny\", , \"tim.mastny@gmail.com\", \"aut\"), person(\"Richard\", \"Iannone\", , \"rich@rstudio.com\", \"aut\", comment = c(ORCID = \"0000-0003-3925-190X\")), person(\"Barret\", \"Schloerke\", , \"barret@rstudio.com\", \"aut\", comment = c(ORCID = \"0000-0001-9986-114X\")), person(\"Carson\", \"Sievert\", , \"carson@rstudio.com\", c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-4958-2844\")), person(\"Christophe\", \"Dervieux\", , \"cderv@rstudio.com\", c(\"ctb\"), comment = c(ORCID = \"0000-0003-4474-2498\")), person(family = \"RStudio\", role = c(\"cph\", \"fnd\")), person(family = \"Sass Open Source Foundation\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Greter\", \"Marcel\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Mifsud\", \"Michael\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Hampton\", \"Catlin\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Natalie\", \"Weizenbaum\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Chris\", \"Eppstein\", role = c(\"ctb\", \"cph\"), comment = \"LibSass library\"), person(\"Adams\", \"Joseph\", role = c(\"ctb\", \"cph\"), comment = \"json.cpp\"), person(\"Trifunovic\", \"Nemanja\", role = c(\"ctb\", \"cph\"), comment = \"utf8.h\") )",
+ "License": "MIT + file LICENSE",
+ "URL": "https://rstudio.github.io/sass/, https://github.com/rstudio/sass",
+ "BugReports": "https://github.com/rstudio/sass/issues",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "SystemRequirements": "GNU make",
+ "Imports": [
+ "fs (>= 1.2.4)",
+ "rlang (>= 0.4.10)",
+ "htmltools (>= 0.5.1)",
"R6",
- "rappdirs",
- "rlang"
- ]
+ "rappdirs"
+ ],
+ "Suggests": [
+ "testthat",
+ "knitr",
+ "rmarkdown",
+ "withr",
+ "shiny",
+ "curl"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/testthat/edition": "3",
+ "NeedsCompilation": "yes",
+ "Author": "Joe Cheng [aut], Timothy Mastny [aut], Richard Iannone [aut] (), Barret Schloerke [aut] (), Carson Sievert [aut, cre] (), Christophe Dervieux [ctb] (), RStudio [cph, fnd], Sass Open Source Foundation [ctb, cph] (LibSass library), Greter Marcel [ctb, cph] (LibSass library), Mifsud Michael [ctb, cph] (LibSass library), Hampton Catlin [ctb, cph] (LibSass library), Natalie Weizenbaum [ctb, cph] (LibSass library), Chris Eppstein [ctb, cph] (LibSass library), Adams Joseph [ctb, cph] (json.cpp), Trifunovic Nemanja [ctb, cph] (utf8.h)",
+ "Maintainer": "Carson Sievert ",
+ "Repository": "CRAN"
},
"scales": {
"Package": "scales",
"Version": "1.4.0",
"Source": "Repository",
- "Requirements": [
+ "Title": "Scale Functions for Visualization",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Dana\", \"Seidel\", role = \"aut\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Graphical scales map data to aesthetics, and provide methods for automatically determining breaks and labels for axes and legends.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://scales.r-lib.org, https://github.com/r-lib/scales",
+ "BugReports": "https://github.com/r-lib/scales/issues",
+ "Depends": [
+ "R (>= 4.1)"
+ ],
+ "Imports": [
"cli",
- "farver",
+ "farver (>= 2.0.3)",
"glue",
"labeling",
"lifecycle",
- "R",
"R6",
"RColorBrewer",
- "rlang",
+ "rlang (>= 1.1.0)",
"viridisLite"
- ]
+ ],
+ "Suggests": [
+ "bit64",
+ "covr",
+ "dichromat",
+ "ggplot2",
+ "hms (>= 0.5.0)",
+ "stringi",
+ "testthat (>= 3.0.0)"
+ ],
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-04-23",
+ "Encoding": "UTF-8",
+ "LazyLoad": "yes",
+ "RoxygenNote": "7.3.2",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut], Thomas Lin Pedersen [cre, aut] (), Dana Seidel [aut], Posit Software, PBC [cph, fnd] (03wc8by49)",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"stringi": {
"Package": "stringi",
- "Version": "1.8.9",
- "Source": "Repository",
- "Requirements": [
- "R",
- "stats",
+ "Version": "1.8.7",
+ "Source": "Repository",
+ "Date": "2025-03-27",
+ "Title": "Fast and Portable Character String Processing Facilities",
+ "Description": "A collection of character string/text/natural language processing tools for pattern searching (e.g., with 'Java'-like regular expressions or the 'Unicode' collation algorithm), random string generation, case mapping, string transliteration, concatenation, sorting, padding, wrapping, Unicode normalisation, date-time formatting and parsing, and many more. They are fast, consistent, convenient, and - thanks to 'ICU' (International Components for Unicode) - portable across all locales and platforms. Documentation about 'stringi' is provided via its website at and the paper by Gagolewski (2022, ).",
+ "URL": "https://stringi.gagolewski.com/, https://github.com/gagolews/stringi, https://icu.unicode.org/",
+ "BugReports": "https://github.com/gagolews/stringi/issues",
+ "SystemRequirements": "ICU4C (>= 61, optional)",
+ "Type": "Package",
+ "Depends": [
+ "R (>= 3.4)"
+ ],
+ "Imports": [
"tools",
- "utils"
- ]
+ "utils",
+ "stats"
+ ],
+ "Biarch": "TRUE",
+ "License": "file LICENSE",
+ "Authors@R": "c(person(given = \"Marek\", family = \"Gagolewski\", role = c(\"aut\", \"cre\", \"cph\"), email = \"marek@gagolewski.com\", comment = c(ORCID = \"0000-0003-0637-6028\")), person(given = \"Bartek\", family = \"Tartanus\", role = \"ctb\"), person(\"Unicode, Inc. and others\", role=\"ctb\", comment = \"ICU4C source code, Unicode Character Database\") )",
+ "RoxygenNote": "7.3.2",
+ "Encoding": "UTF-8",
+ "NeedsCompilation": "yes",
+ "Author": "Marek Gagolewski [aut, cre, cph] (), Bartek Tartanus [ctb], Unicode, Inc. and others [ctb] (ICU4C source code, Unicode Character Database)",
+ "Maintainer": "Marek Gagolewski ",
+ "License_is_FOSS": "yes",
+ "Repository": "CRAN"
},
"stringr": {
"Package": "stringr",
"Version": "1.6.0",
"Source": "Repository",
- "Requirements": [
+ "Title": "Simple, Consistent Wrappers for Common String Operations",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\", \"cph\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\")) )",
+ "Description": "A consistent, simple and easy to use set of wrappers around the fantastic 'stringi' package. All function and argument names (and positions) are consistent, all functions deal with \"NA\"'s and zero length vectors in the same way, and the output from one function is easy to feed into the input of another.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://stringr.tidyverse.org, https://github.com/tidyverse/stringr",
+ "BugReports": "https://github.com/tidyverse/stringr/issues",
+ "Depends": [
+ "R (>= 4.1.0)"
+ ],
+ "Imports": [
"cli",
- "glue",
- "lifecycle",
+ "glue (>= 1.6.1)",
+ "lifecycle (>= 1.0.3)",
"magrittr",
- "R",
- "rlang",
- "stringi",
- "vctrs"
- ]
+ "rlang (>= 1.0.0)",
+ "stringi (>= 1.5.3)",
+ "vctrs (>= 0.4.0)"
+ ],
+ "Suggests": [
+ "covr",
+ "dplyr",
+ "gt",
+ "htmltools",
+ "htmlwidgets",
+ "knitr",
+ "rmarkdown",
+ "testthat (>= 3.0.0)",
+ "tibble"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/potools/style": "explicit",
+ "Config/testthat/edition": "3",
+ "Encoding": "UTF-8",
+ "LazyData": "true",
+ "RoxygenNote": "7.3.3",
+ "NeedsCompilation": "no",
+ "Author": "Hadley Wickham [aut, cre, cph], Posit Software, PBC [cph, fnd]",
+ "Maintainer": "Hadley Wickham ",
+ "Repository": "CRAN"
},
"svglite": {
"Package": "svglite",
"Version": "2.2.2",
"Source": "Repository",
- "Requirements": [
+ "Title": "An 'SVG' Graphics Device",
+ "Authors@R": "c( person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = \"aut\"), person(\"Lionel\", \"Henry\", , \"lionel@posit.co\", role = \"aut\"), person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"T Jake\", \"Luciani\", , \"jake@apache.org\", role = \"aut\"), person(\"Matthieu\", \"Decorde\", , \"matthieu.decorde@ens-lyon.fr\", role = \"aut\"), person(\"Vaudor\", \"Lise\", , \"lise.vaudor@ens-lyon.fr\", role = \"aut\"), person(\"Tony\", \"Plate\", role = \"ctb\", comment = \"Early line dashing code\"), person(\"David\", \"Gohel\", role = \"ctb\", comment = \"Line dashing code and early raster code\"), person(\"Yixuan\", \"Qiu\", role = \"ctb\", comment = \"Improved styles; polypath implementation\"), person(\"Håkon\", \"Malmedal\", role = \"ctb\", comment = \"Opacity code\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "A graphics device for R that produces 'Scalable Vector Graphics'. 'svglite' is a fork of the older 'RSvgDevice' package.",
+ "License": "GPL (>= 2)",
+ "URL": "https://svglite.r-lib.org, https://github.com/r-lib/svglite",
+ "BugReports": "https://github.com/r-lib/svglite/issues",
+ "Depends": [
+ "R (>= 4.1)"
+ ],
+ "Imports": [
"base64enc",
"cli",
- "cpp11",
"lifecycle",
- "R",
- "rlang",
+ "rlang (>= 1.1.0)",
+ "systemfonts (>= 1.3.0)",
+ "textshaping (>= 0.3.0)"
+ ],
+ "Suggests": [
+ "covr",
+ "fontquiver (>= 0.2.0)",
+ "htmltools",
+ "knitr",
+ "rmarkdown",
+ "testthat (>= 3.0.0)",
+ "xml2 (>= 1.0.0)"
+ ],
+ "LinkingTo": [
+ "cpp11",
"systemfonts",
"textshaping"
- ]
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-04-25",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "SystemRequirements": "libpng",
+ "NeedsCompilation": "yes",
+ "Author": "Hadley Wickham [aut], Lionel Henry [aut], Thomas Lin Pedersen [cre, aut] (ORCID: ), T Jake Luciani [aut], Matthieu Decorde [aut], Vaudor Lise [aut], Tony Plate [ctb] (Early line dashing code), David Gohel [ctb] (Line dashing code and early raster code), Yixuan Qiu [ctb] (Improved styles; polypath implementation), Håkon Malmedal [ctb] (Opacity code), Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"sys": {
"Package": "sys",
"Version": "3.4.3",
"Source": "Repository",
- "Requirements": []
+ "Type": "Package",
+ "Title": "Powerful and Reliable Tools for Running System Commands in R",
+ "Authors@R": "c(person(\"Jeroen\", \"Ooms\", role = c(\"aut\", \"cre\"), email = \"jeroenooms@gmail.com\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Gábor\", \"Csárdi\", , \"csardi.gabor@gmail.com\", role = \"ctb\"))",
+ "Description": "Drop-in replacements for the base system2() function with fine control and consistent behavior across platforms. Supports clean interruption, timeout, background tasks, and streaming STDIN / STDOUT / STDERR over binary or text connections. Arguments on Windows automatically get encoded and quoted to work on different locales.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://jeroen.r-universe.dev/sys",
+ "BugReports": "https://github.com/jeroen/sys/issues",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.1.1",
+ "Suggests": [
+ "unix (>= 1.4)",
+ "spelling",
+ "testthat"
+ ],
+ "Language": "en-US",
+ "NeedsCompilation": "yes",
+ "Author": "Jeroen Ooms [aut, cre] (), Gábor Csárdi [ctb]",
+ "Maintainer": "Jeroen Ooms ",
+ "Repository": "CRAN"
},
"systemfonts": {
"Package": "systemfonts",
- "Version": "1.3.2",
- "Source": "Repository",
- "Requirements": [
+ "Version": "1.3.1",
+ "Source": "Repository",
+ "Type": "Package",
+ "Title": "System Native Font Finding",
+ "Authors@R": "c( person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Jeroen\", \"Ooms\", , \"jeroen@berkeley.edu\", role = \"aut\", comment = c(ORCID = \"0000-0002-4035-0289\")), person(\"Devon\", \"Govett\", role = \"aut\", comment = \"Author of font-manager\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Provides system native access to the font catalogue. As font handling varies between systems it is difficult to correctly locate installed fonts across different operating systems. The 'systemfonts' package provides bindings to the native libraries on Windows, macOS and Linux for finding font files that can then be used further by e.g. graphic devices. The main use is intended to be from compiled code but 'systemfonts' also provides access from R.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://github.com/r-lib/systemfonts, https://systemfonts.r-lib.org",
+ "BugReports": "https://github.com/r-lib/systemfonts/issues",
+ "Depends": [
+ "R (>= 3.2.0)"
+ ],
+ "Imports": [
"base64enc",
- "cpp11",
"grid",
"jsonlite",
"lifecycle",
- "R",
"tools",
"utils"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "farver",
+ "ggplot2",
+ "graphics",
+ "knitr",
+ "ragg",
+ "rmarkdown",
+ "svglite",
+ "testthat (>= 2.1.0)"
+ ],
+ "LinkingTo": [
+ "cpp11 (>= 0.2.1)"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/build/compilation-database": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/usethis/last-upkeep": "2025-04-23",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "SystemRequirements": "fontconfig, freetype2",
+ "NeedsCompilation": "yes",
+ "Author": "Thomas Lin Pedersen [aut, cre] (ORCID: ), Jeroen Ooms [aut] (ORCID: ), Devon Govett [aut] (Author of font-manager), Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"textshaping": {
"Package": "textshaping",
- "Version": "1.0.5",
- "Source": "Repository",
- "Requirements": [
- "cpp11",
+ "Version": "1.0.4",
+ "Source": "Repository",
+ "Title": "Bindings to the 'HarfBuzz' and 'Fribidi' Libraries for Text Shaping",
+ "Authors@R": "c( person(\"Thomas Lin\", \"Pedersen\", , \"thomas.pedersen@posit.co\", role = c(\"cre\", \"aut\"), comment = c(ORCID = \"0000-0002-5147-4711\")), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Provides access to the text shaping functionality in the 'HarfBuzz' library and the bidirectional algorithm in the 'Fribidi' library. 'textshaping' is a low-level utility package mainly for graphic devices that expands upon the font tool-set provided by the 'systemfonts' package.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://github.com/r-lib/textshaping",
+ "BugReports": "https://github.com/r-lib/textshaping/issues",
+ "Depends": [
+ "R (>= 3.2.0)"
+ ],
+ "Imports": [
"lifecycle",
- "R",
"stats",
"stringi",
- "systemfonts",
+ "systemfonts (>= 1.3.0)",
"utils"
- ]
+ ],
+ "Suggests": [
+ "covr",
+ "grDevices",
+ "grid",
+ "knitr",
+ "rmarkdown",
+ "testthat (>= 3.0.0)"
+ ],
+ "LinkingTo": [
+ "cpp11 (>= 0.2.1)",
+ "systemfonts (>= 1.0.0)"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/build/compilation-database": "true",
+ "Config/testthat/edition": "3",
+ "Config/usethis/last-upkeep": "2025-04-23",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.2",
+ "SystemRequirements": "freetype2, harfbuzz, fribidi",
+ "NeedsCompilation": "yes",
+ "Author": "Thomas Lin Pedersen [cre, aut] (ORCID: ), Posit Software, PBC [cph, fnd] (ROR: )",
+ "Maintainer": "Thomas Lin Pedersen ",
+ "Repository": "CRAN"
},
"tibble": {
"Package": "tibble",
"Version": "3.3.1",
"Source": "Repository",
- "Requirements": [
+ "Title": "Simple Data Frames",
+ "Authors@R": "c( person(\"Kirill\", \"Mller\", , \"kirill@cynkra.com\", role = c(\"aut\", \"cre\"), comment = c(ORCID = \"0000-0002-1416-3412\")), person(\"Hadley\", \"Wickham\", , \"hadley@rstudio.com\", role = \"aut\"), person(\"Romain\", \"Francois\", , \"romain@r-enthusiasts.com\", role = \"ctb\"), person(\"Jennifer\", \"Bryan\", , \"jenny@rstudio.com\", role = \"ctb\"), person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"), comment = c(ROR = \"03wc8by49\")) )",
+ "Description": "Provides a 'tbl_df' class (the 'tibble') with stricter checking and better formatting than the traditional data frame.",
+ "License": "MIT + file LICENSE",
+ "URL": "https://tibble.tidyverse.org/, https://github.com/tidyverse/tibble",
+ "BugReports": "https://github.com/tidyverse/tibble/issues",
+ "Depends": [
+ "R (>= 3.4.0)"
+ ],
+ "Imports": [
"cli",
- "lifecycle",
+ "lifecycle (>= 1.0.0)",
"magrittr",
"methods",
- "pillar",
+ "pillar (>= 1.8.1)",
"pkgconfig",
- "R",
- "rlang",
+ "rlang (>= 1.0.2)",
"utils",
- "vctrs"
- ]
+ "vctrs (>= 0.5.0)"
+ ],
+ "Suggests": [
+ "bench",
+ "bit64",
+ "blob",
+ "brio",
+ "callr",
+ "DiagrammeR",
+ "dplyr",
+ "evaluate",
+ "formattable",
+ "ggplot2",
+ "here",
+ "hms",
+ "htmltools",
+ "knitr",
+ "lubridate",
+ "nycflights13",
+ "pkgload",
+ "purrr",
+ "rmarkdown",
+ "stringi",
+ "testthat (>= 3.0.2)",
+ "tidyr",
+ "withr"
+ ],
+ "VignetteBuilder": "knitr",
+ "Config/autostyle/rmd": "false",
+ "Config/autostyle/scope": "line_breaks",
+ "Config/autostyle/strict": "true",
+ "Config/Needs/website": "tidyverse/tidytemplate",
+ "Config/testthat/edition": "3",
+ "Config/testthat/parallel": "true",
+ "Config/testthat/start-first": "vignette-formats, as_tibble, add, invariants",
+ "Config/usethis/last-upkeep": "2025-06-07",
+ "Encoding": "UTF-8",
+ "RoxygenNote": "7.3.3.9000",
+ "NeedsCompilation": "yes",
+ "Author": "Kirill M