R/roxygenize-needs.R

Defines functions rd_backref_sources rd_outdated needs_roxygenize

Documented in needs_roxygenize

#' Check if documentation needs to be updated
#'
#' @description
#' A lightweight check that compares modification times of `.Rd` files in
#' `man/` with the source files listed in their backrefs. This is much faster
#' than running [roxygenize()] but can suffer from both false negatives (e.g.
#' if an inherited documentation topic has changed) and false positives (e.g.
#' if a source file was modified but the change doesn't affect the
#' documentation).
#'
#' @inheritParams roxygenize
#' @param quiet If `TRUE`, suppresses the message listing out-of-date
#'   man pages.
#' @return A logical value, invisibly. `TRUE` if any man pages appear
#'   to be out of date; `FALSE` otherwise.
#' @export
#' @examples
#' \dontrun{
#' needs_roxygenize()
#' }
needs_roxygenize <- function(package.dir = ".", quiet = FALSE) {
  check_string(package.dir)
  check_bool(quiet)

  base_path <- normalizePath(package.dir)
  man_path <- file.path(base_path, "man")
  rd_files <- sort(dir(man_path, pattern = "\\.Rd$", full.names = TRUE))
  outdated <- map_lgl(rd_files, rd_outdated, base_path = base_path)
  out_of_date <- basename(rd_files[outdated])

  if (length(out_of_date) > 0 && !quiet) {
    cli::cli_inform(c(
      "!" = "{length(out_of_date)} man page{?s} may be out of date:",
      set_names(out_of_date, "*")
    ))
  }

  invisible(length(out_of_date) > 0)
}

rd_outdated <- function(rd_file, base_path) {
  lines <- read_lines(rd_file, n = 10)
  source_files <- rd_backref_sources(lines, base_path)
  if (length(source_files) == 0) {
    return(FALSE)
  }

  if (!all(file.exists(source_files))) {
    return(TRUE)
  }

  rd_mtime <- file.mtime(rd_file)
  source_mtimes <- file.mtime(source_files)
  any(source_mtimes > rd_mtime)
}

rd_backref_sources <- function(lines, base_path) {
  if (length(lines) == 0 || !check_made_by(lines[[1]])) {
    return(character())
  }

  regexp <- "^%\\s*(Please edit documentation in|  )"
  lines <- lines[grepl(regexp, lines)]
  if (length(lines) == 0) {
    return(character())
  }

  lines <- gsub("^%(\\s*Please edit documentation in)?", "", lines)
  files <- unlist(strsplit(lines, ","))
  files <- trimws(files)
  files <- files[nzchar(files)]

  file.path(base_path, files)
}

Try the roxygen2 package in your browser

Any scripts or data that you put into this service are public.

roxygen2 documentation built on May 1, 2026, 5:06 p.m.