{"id":15051457,"url":"https://github.com/jorischau/checkglobals","last_synced_at":"2026-04-02T02:37:34.726Z","repository":{"id":171320220,"uuid":"647452250","full_name":"JorisChau/checkglobals","owner":"JorisChau","description":"Find (missing) dependencies in R-source code","archived":false,"fork":false,"pushed_at":"2023-06-29T14:33:59.000Z","size":718,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-11-20T16:00:30.838Z","etag":null,"topics":["package-dependencies","r","static-code-analysis"],"latest_commit_sha":null,"homepage":"https://jorischau.github.io/checkglobals/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JorisChau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-05-30T20:17:15.000Z","updated_at":"2024-03-29T09:38:20.040Z","dependencies_parsed_at":"2023-06-30T09:16:16.809Z","dependency_job_id":null,"html_url":"https://github.com/JorisChau/checkglobals","commit_stats":null,"previous_names":["jorischau/checkglobals"],"tags_count":1,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JorisChau%2Fcheckglobals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JorisChau%2Fcheckglobals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JorisChau%2Fcheckglobals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JorisChau%2Fcheckglobals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JorisChau","download_url":"https://codeload.github.com/JorisChau/checkglobals/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242988072,"owners_count":20217538,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["package-dependencies","r","static-code-analysis"],"created_at":"2024-09-24T21:35:43.769Z","updated_at":"2025-12-29T12:28:38.377Z","avatar_url":"https://github.com/JorisChau.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n# {checkglobals}\n\n\u003c!-- badges: start --\u003e\n\n[![CRAN\nversion](https://www.r-pkg.org/badges/version/checkglobals)](https://cran.r-project.org/package=checkglobals)\n[![R-CMD-check](https://github.com/JorisChau/checkglobals/workflows/R-CMD-check/badge.svg)](https://github.com/JorisChau/checkglobals/actions)\n[![codecov](https://codecov.io/gh/JorisChau/checkglobals/branch/master/graph/badge.svg)](https://app.codecov.io/gh/JorisChau/checkglobals)\n[![status](https://tinyverse.netlify.app/badge/checkglobals)](https://CRAN.R-project.org/package=checkglobals)\n\u003c!-- badges: end --\u003e\n\nThe minimal {checkglobals}-package allows to approximately detect global\nand imported functions or variables from R-source code or R-packages by\nstatically inspecting the internal syntax trees of the code,\n(i.e. [static code\nanalysis](https://en.wikipedia.org/wiki/Static_program_analysis)). The\naim of this package is to serve as a fast and light-weight alternative\nto `codetools::findGlobals()` to check R-packages or R-scripts for\nmissing function imports and/or variable definitions on-the-fly without\nthe need for package installation or code execution. The code inspection\nprocedures are implemented using R’s internal C API for efficiency, and\nno external R-package dependencies are strictly required, only\n[cli](https://CRAN.R-project.org/package=cli) and\n[knitr](https://CRAN.R-project.org/package=knitr) are suggested for\ninteractive use and checking Rmd documents respectively.\n\n## Installation\n\n``` r\n# Install latest release from CRAN:\ninstall.packages(\"checkglobals\")\n\n# Install the development version from GitHub:\n# install.packages(\"devtools\")\ndevtools::install_github(\"JorisChau/checkglobals\")\n```\n\n## Example usage\n\n### R-scripts\n\nThe {checkglobals}-package contains a single wrapper function\n`checkglobals()` to inspect R-scripts, folders, R-code strings or\nR-packages. Individual R-scripts can be scanned for global variables and\nimported functions using the `file` argument:\n\n\u003cimg src=\"./README/screen01.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n\u003cbr\u003e\n\nThe R-script in this example contains a simple R-Shiny application\navailable at\n\u003chttps://raw.githubusercontent.com/rstudio/shiny-examples/main/004-mpg/app.R\u003e.\n\n#### Printed output\n\nPrinting the S3-object returned by `checkglobals()` outputs: 1. the\n*name* and *location* of all unrecognized global variables; and 2. the\n*name* and *location* of all detected imported functions grouped by\nR-package.\n\nThe *location* `app.R#36` lists the R-file name (`app.R`) and line\nnumber (`36`) of the detected variable or function. If\n[cli](https://CRAN.R-project.org/package=cli) is installed and\ncli-hyperlinks are supported, clicking the *location* links opens the\nsource file pointing to the given line number. The bars and counts\nbehind the imported package names highlight the number of function calls\ndetected from each package. This information can be used to get a better\nsense of the importance of an imported package and how much effort it\nwould take to remove it as a dependency.\n\nTo inspect only the detected global variables or imported functions,\nindex the S3-object by its `globals` (`chk$globals`) or `imports`\n(`chk$imports`) components. For instance, we can print detailed source\ncode references of the unrecognized global variables with:\n\n\u003cimg src=\"./README/screen02.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n#### Remote files\n\nInstead of a local file, the `file` argument in `checkglobals()` can\nalso be a remote file location (e.g. a server or the web), in which case\nthe remote file is first downloaded as a temporary file with\n`download.file()`.\n\n\u003cimg src=\"./README/screen03.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n### R Markdown files\n\nThe `file` argument in `checkglobals()` also accepts R Markdown (`.Rmd`\nor `.Rmarkdown`) file locations. For R Markdown files, the R code chunks\nare first extracted into a temporary R-script with `knitr::purl()`,\nwhich is then analyzed by `checkglobals()`:\n\n\u003cimg src=\"./README/screen04.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n\u003cbr\u003e\n\n**Note**: R-packages that are imported or loaded, but have no detected\nfunction imports are displayed with an *n/a* reference. This can happen\nwhen `checkglobals()` falsely ignores one or more imported functions\nfrom the given package or when the package is not actually needed as a\ndependency. In both cases this is useful information to have. In the\nabove example, `tibble` is loaded in order to use `tribble()`, but the\n`tribble()` function is also exported by `dplyr`, so it shows up under\nthe `dplyr` imports instead.\n\n### Folders\n\nFolders containing R-scripts can be scanned with the `dir` argument in\n`checkglobals()`, which inspects all R-scripts present in `dir`. The\nfollowing example scans an R-Shiny app folder containing a `ui.R` and\n`server.R` file (source:\n\u003chttps://github.com/rstudio/shiny-examples/tree/main/018-datatable-options\u003e),\n\n\u003cimg src=\"./README/screen05.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n\u003cbr\u003e\n\n**Note**: if imports are detected from an R-package not installed in the\ncurrent R-session, an alert is printed as in the example above. Function\ncalls accessing the missing R-package explicitly, using e.g. `::` or\n`:::`, can still be fully identified as imports by `checkglobals()`.\nFunction calls with no reference to the missing R-package will be listed\nas unrecognized globals.\n\n### R-packages\n\nR-package folders can be scanned with the `pkg` argument in\n`checkglobals()`. Conceptually, `checkglobals()` scans all files in the\n`/R` folder of the package and contrasts the detected (unrecognized)\nglobals and imports against the imports listed in the NAMESPACE file of\nthe package. R-scripts present elsewhere in the package (e.g. in the\n`/inst` folder) are **not** analyzed, as these are not coupled to the\npackage NAMESPACE file. To illustrate, we can run `checkglobals()` on\nits own package folder:\n\n\u003cimg src=\"./README/screen06.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n#### Bundled R-packages\n\nInstead of local R-package folders, the `pkg` argument also accepts file\npaths to bundled source R-packages (tar.gz). This can either be a tar.gz\npackage on the local filesystem, or a remote file location, such as the\nweb (similar to the `file` argument).\n\n##### Local filesystem:\n\n\u003cimg src=\"./README/screen07.svg\" width=\"85%\" style=\"display: block; margin: auto;\" /\u003e\n\n##### Remote file location:\n\n\u003cimg src=\"./README/screen08a.svg\" width=\"85%\" style='margin-left:70px' style=\"display: block; margin: auto;\" /\u003e\n\u003cimg src=\"./README/screen08b.svg\" width=\"85%\" style='margin-top:-20px;margin-left:70px' style=\"display: block; margin: auto;\" /\u003e\n\n\u003cbr\u003e\n\n**Remark**: if `checkglobals()` is called without a `file`, `dir`,\n`text` or `pkg` argument, the function is run in the current working\ndirectory. If the current working directory is an R-package folder, this\nis identical to `checkglobals(pkg = \".\")`, otherwise the behavior is the\nsame as `checkglobals(dir = \".\")`.\n\n### Programmatic use\n\nSeveral methods (e.g. `as.data.frame`, `as.matrix` or `as.character`)\nare available to cast the S3-objects returned by `checkglobals()` to\ncommon R-objects. This can be useful for further programmatic use of the\nreturned output:\n\n``` r\nchk \u003c- checkglobals::checkglobals(pkg = \"../checkglobals\")\n\n## data.frame with globals/imports \nas.data.frame(chk)\n#\u003e                  name package   type\n#\u003e 1          ansi_align     cli import\n#\u003e 2          ansi_nchar     cli import\n#\u003e 3        ansi_strtrim     cli import\n#\u003e 4         ansi_trimws     cli import\n#\u003e 5   cli_alert_success     cli import\n#\u003e 6   cli_alert_warning     cli import\n#\u003e 7              cli_h1     cli import\n#\u003e 8      code_highlight     cli import\n#\u003e 9            col_blue     cli import\n#\u003e 10          col_green     cli import\n#\u003e 11           col_grey     cli import\n#\u003e 12            col_red     cli import\n#\u003e 13          col_white     cli import\n#\u003e 14         col_yellow     cli import\n#\u003e 15      console_width     cli import\n#\u003e 16         style_bold     cli import\n#\u003e 17    style_hyperlink     cli import\n#\u003e 18       style_italic     cli import\n#\u003e 19             symbol     cli import\n#\u003e 20               tree     cli import\n#\u003e 21               purl   knitr import\n#\u003e 22      download.file   utils import\n#\u003e 23 installed.packages   utils import\n#\u003e 24             relist   utils import\n#\u003e 25              untar   utils import\n\n## vector of package dependencies\ncheckglobals::as_vector(chk)[[\"package\"]]\n#\u003e [1] \"cli\"   \"knitr\" \"utils\"\n```\n\n## Known limitations\n\nBelow is a non-exhaustive list of known limitations of the static code\nanalysis performed by `checkglobals()` to keep in mind for practical\nuse. These are cases that are either too ambiguous or complex to be\nanalyzed without evaluation of the code itself, where `checkglobals()`\nfails to recognize a variable name (false negative) or falsely detects a\nglobal variable when it should not (false positive).\n\n#### Character variable/function names\n\n``` r\n## this works (character arguments are recognized as functions)\ncheckglobals(text = 'do.call(args = list(1), what = \"median\")')\ncheckglobals(text = 'Map(\"g\", 1, n = 1)')\ncheckglobals(text = 'stats::aggregate(x ~ ., data = y, FUN = \"g\")')\n\n## this doesn't work (evaluation is required)\ncheckglobals(text = 'g \u003c- \"f\"; Map(g, 1, n = 1)')\ncheckglobals(text = \"eval(substitute(g))\") ## same for ~, expression, quote, bquote, Quote, etc.\n```\n\n``` r\n## this works (calling a function in an exotic way)\ncheckglobals(text = '\"head\"(1:10)')\ncheckglobals(text = '`::`(\"utils\", \"head\")(1:10)')\ncheckglobals(text = 'list(\"function\" = utils::head)$`function`(1:10)')\n\n## this doesn't work (evaluation is required)\ncheckglobals(text = 'get(\"head\")(1:10)')\ncheckglobals(text = 'methods::getMethod(\"f\", signature = \"ANY\")')\n```\n\n#### Package loading\n\n``` r\n## this works (simple evaluation of package names)\ncheckglobals(text = 'attachNamespace(\"utils\"); head(1:10)')\ncheckglobals(text = 'pkg \u003c- \"utils\"; library(pkg, character.only = TRUE); head(1:10)')\n\n## this doesn't work (more complex evaluation is required)\ncheckglobals(text = 'pkg \u003c- function() \"utils\"; library(pkg(), character.only = TRUE); head(1:10)')\ncheckglobals(text = 'loadPkg \u003c- library; loadPkg(utils)')\ncheckglobals(text = 'box::use(utils[...])')\n```\n\n#### Unknown symbols\n\n``` r\n## this works (special functions self, private, super are recognized)\ncheckglobals(text = 'R6::R6Class(\"cl\",\n                   public = list(\n                     initialize = function(...) self$f(...),\n                     f = function(...) private$p\n                   ),\n                   private = list(\n                     p = list()\n                   ))')\n\n## this doesn't work (data masking)\ncheckglobals(text = 'transform(mtcars, mpg2 = mpg^2)')\ncheckglobals(text = 'attach(iris); print(Sepal.Width)')\n```\n\n#### Lazy evaluation\n\n``` r\n## this works (basic lazy evaluation)\ncheckglobals(text = '{\n    addy \u003c- function(y) x + y \n    x \u003c- 0\n    addy(1)\n}')\ncheckglobals(\n  text = 'function() { \n    on.exit(rm(x))\n    x \u003c- 0 \n}')\n\n## this doesn't work (lazy evaluation in external functions)\ncheckglobals(\n  text = 'server \u003c- function(input, output) {\n    add1x \u003c- shiny::reactive({\n      add1(input$x)\n    })\n    add1 \u003c- function(x) x + 1  \n  }')\n```\n\n## Useful references\n\nOther useful functions and R-packages with design goals and/or\nfunctionality related to {checkglobals} include:\n\n- `codetools::findGlobals()`, detects global variables from R-scripts\n  via static code analysis. This and other *codetools* functions\n  underlie the source code checks run by `R CMD check`.\n- [globals](https://CRAN.R-project.org/package=globals), R-package by H.\n  Bengtsson providing a re-implementation of the functions in\n  *codetools* to identify global variables using various strategies for\n  export in parallel computations.\n- `renv::dependencies()`, detects R-package dependencies by scanning all\n  R-files in a project for imported functions or packages via static\n  code analysis.\n- [lintr](https://CRAN.R-project.org/package=lintr), R-package by J.\n  Hester and others to perform general static code analysis in R\n  projects. `lintr::object_usage_linter()` provides a wrapper of\n  `codetools::checkUsage()` to detect global variables similar to\n  `R CMD check`.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorischau%2Fcheckglobals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjorischau%2Fcheckglobals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorischau%2Fcheckglobals/lists"}