Skip to contents

Extracts comments, tracked changes, and reconstructed paragraph redlines directly from Microsoft Word (`.docx`) files and maintains a collaborative review workflow in a formatted multi-sheet Excel workbook and UTF-8 CSV files.

Supports multi-reviewer workflows with per-reviewer fork files (`review_tracker_<reviewer>.xlsx`), live Excel formulas, dropdown data validations, conditional formatting, non-destructive merging across document revisions, and analytical compute graph ordering.

Usage

docx_review_extract(
  input_dir = NULL,
  output_dir = NULL,
  tracker = "review_tracker.xlsx",
  min_revision_length = 2,
  fork_reviewers = NULL,
  signoff_reviewers = NULL,
  documents_sheet_mode = NULL,
  manifest_path = NULL,
  verbose = FALSE,
  docx_limits = NULL,
  fork_mode = NULL
)

Arguments

input_dir

Character path to a directory containing `.docx` files, or to a single `.docx` file. Defaults to the first folder of `review_config()$input_dirs` that holds `.docx` files (none is configured by default), else the current working directory.

output_dir

Character path to the directory where review tracker workbooks and CSV files should be saved. If `NULL` (default), uses `<input_dir>/review_extract` (or `<input_dir>` if it is already named `review_extract`).

tracker

Character filename for the master Excel workbook. Defaults to `"review_tracker.xlsx"`.

min_revision_length

Integer minimum character count required to record a tracked change. Defaults to `2`.

fork_reviewers

Character vector of reviewer identifiers who receive their own single-reviewer fork workbooks and whose per-comment sign-offs roll up into each document's `resolved` status. Defaults to `review_config()$fork_reviewers` (generic placeholders unless a project has called review_config to configure real reviewer ids).

signoff_reviewers

Character vector of document-level sign-off reviewer identifiers (e.g. a final PI read), tracked on the master workbook's "Documents" sheet and not counted toward `resolved`; they appear in no fork workbook. Defaults to `review_config()$signoff_reviewers`.

documents_sheet_mode

One of `"columns"` or `"per_reviewer"`; see review_config. Defaults to `review_config()$documents_sheet_mode`.

manifest_path

Optional character path to `reports_to_render.xlsx`. If `NULL`, the function looks for it in the folder set with `review_config(analysis_dir = )` (nothing is searched when none is set). `"auto"` also looks, when that finds nothing, for `reports_to_render.xlsx` in the input folder and its two parents (and in the working directory), in the folder itself and in `analysis/<folder>/`; the most recent one wins. Pipeline stages come from that manifest and from `review_config()$pipeline_catalog`; with neither, documents are not assigned to a stage (stage `"Unknown / Extra"`) and are listed by file name.

verbose

Logical indicating whether to print detailed progress messages. Defaults to `FALSE`.

docx_limits

NULL (the defaults) or a named list limiting what is done with each .docx, which is an untrusted zip archive: max_entries (entries in the archive, default 10,000), max_total_bytes (summed uncompressed size, default 2 GiB) and max_xml_bytes (uncompressed size of any one XML part that is read, default 100 MiB). The listing is checked before anything is extracted, only the parts that are read are extracted, and a file over a limit is reported in $errors instead of being read. Inf switches a limit off. The session-wide options review.docx_max_entries, review.docx_max_bytes and review.docx_max_xml_bytes set the defaults.

fork_mode

"redacted" (default, review_config()$fork_mode) or "collaborative"; see review_config. In collaborative mode every fork workbook also carries the other fork reviewers' sign-off and note columns (read-only: only a reviewer's own columns are merged back).

Value

An object of class `cbe_review_extract`, which is a named list containing:

comments

A tibble of merged comment records.

revisions

A tibble of merged raw tracked changes.

redlines

A tibble of reconstructed paragraph before/after redlines.

documents

A tibble of document-level summary metrics and review statuses.

docxwalk

A tibble crosswalking reviewed DOCX files to source `.qmd` and rendered outputs.

summary

A tibble summarizing recurring comments across documents.

errors

A tibble of any processing errors encountered.

paths

A named list of generated file paths.

Details

What is read. Comments (word/comments.xml, with reply threads and the resolved flag from word/commentsExtended.xml) and the tracked changes and comment ranges of the main document body (word/document.xml). A text box is read once and counts as part of the paragraph that holds it, so paragraph numbers are Word's.

What is not read. Tracked changes and comment ranges in footnotes, endnotes, headers and footers are not extracted, and a comment anchored in one of them is listed with no paragraph number and no selected text. They are not dropped silently: when one of those parts holds either, a single warning names the files, the parts and how many there are, so that they can be reviewed in Word.

Merging a new round into the tracker. A comment is identified by what it says, not by its Word comment id (Word renumbers the ids when it saves). A comment continues an existing row of the same file only when its text is the same (compared without regard to whitespace); among rows with the same text the one with the same author and date is taken first, then one with the same author (or an author missing on one side), preferring the same comment id and then the nearest paragraph. A comment whose text changed is a new comment: the row it replaces is kept, marked Prior Round / Not in docx, when it holds a sign-off or a note. Rows of documents that left the folder, or that could not be read in this run, are kept the same way.

Reviewer forks. A reviewer's edits in their fork workbook (review_tracker_<id>.xlsx) are merged back by file and comment (or suggested change). Only cells the reviewer changed since the fork was written are taken (each fork records what it was written with on a hidden sheet), so a sign-off typed into the master workbook is not undone by a fork that left the cell alone. If both were changed to different values the fork's value is kept and a warning lists the cells; the previous master is in the backups folder.

Files that are not readable Word documents (empty, not a ZIP archive, no word/document.xml, or an XML error) are listed in $errors and on the Errors sheet and reported in one warning; Word's ~$ lock files are ignored. A run that finds no readable document creates and backs up nothing.

Examples

if (FALSE) { # \dontrun{
# Configure real reviewer identities once per project (kept out of source
# control), then run extraction with no further reviewer arguments needed:
review_config(fork_reviewers = c("alice", "bob", "carol"), signoff_reviewers = "lead_pi")
# Optionally describe your own pipeline stages, so documents are ordered and
# labelled by stage (the package ships none):
review_config(pipeline_catalog = list(
  list(stem = "overview", heading = 1, name = "Overview"),
  list(stem = "model_fit", heading = 2, name = "Model fitting")
))
res <- docx_review_extract("path/to/reviewed_docx", verbose = TRUE)
print(res)
} # }