Skip to content

feat: R package that emits WordBuilderSwift scripts from R analysis results #88

@kiki830621

Description

@kiki830621

Problem

Original text:
「我記得我有一個想要用 swift 腳本來做成 word 的想法,我在想是不是可以寫一個 R 的 package 可以直接從分析結果整理成 swift 的 docx 腳本?」
— Source: Claude Code session 2026-04-19

word-builder-swift 0.9.0 (#71) shipped a fluent Swift API for programmatically building .docx — a Swift-side equivalent of docx.js. R users doing statistical analysis still generate Word reports through older toolchains (officer, flextable, rmarkdownpandoc) that have their own quirks and limited styling control.

Proposal: an R package that serialises R analysis artefacts (data frames, ggplot2 plots, model summaries, character vectors, lists) into a runnable .swift script that imports WordBuilderSwift and emits a .docx. The R function call shells out to swift run, captures the produced .docx, and returns its path to R.

Type

feature

Motivation

  • Unifies the "analysis in R, formatted report in Swift" pipeline. R stays the analytical engine; Swift owns layout/styling.
  • Keeps word-builder-swift as the single canonical .docx writer across the macdoc ecosystem — R integration becomes "just another caller," not a parallel DOCX generator.
  • The produced .swift file is a first-class artefact — committable, re-runnable, reviewable, diffable against last week's report. Beats "black-box PDF" reproducibility by a wide margin.
  • Forces a clean R ↔ Swift type mapping (data.frame → Table, ggplot → ImageRun when that lands in Phase 2, character heading → Paragraph(heading:), etc.) — exercising word-builder-swift's API surface and surfacing Phase 2/3 needs.

Expected

R user writes:

library(wordBuilder)  # or whatever the package ends up named

doc <- word_document()
doc <- add_heading(doc, "Q1 Report", level = 1)
doc <- add_paragraph(doc, paste("Revenue grew", scales::percent(0.15)))
doc <- add_table(doc, mtcars[1:5, ])
doc <- add_plot(doc, ggplot(mtcars, aes(mpg, hp)) + geom_point())

render(doc, output = "q1-report.docx")
# Internally:
#   1. Emits q1-report.swift (calls WordBuilderSwift)
#   2. Emits any plot as media/{png}
#   3. `swift run --package-path <tempdir> q1-report.swift`
#   4. Returns path to q1-report.docx

The intermediate q1-report.swift is retained (not deleted) so users can:

  • Read / edit it for fine-grained control
  • Check it into git alongside R analysis code
  • Re-run Swift-side without re-running R

Actual

No such package exists. R users wanting .docx output today use:

  • officer + flextable — most common, but styling API is idiosyncratic, Windows-biased, and has long-standing table-inside-body quirks
  • rmarkdown → pandoc — converts markdown to docx, but loses fine control over run-level formatting
  • Manual copy-paste from R → Word (still the most common "pipeline" in practice)

None of these produce a reviewable intermediate artefact like the Swift script approach would.

Impact

Positive:

  • New R-side audience for word-builder-swift (feat: 新增 word-builder-swift — Swift fluent API 直接寫 .docx(類 docx.js) #71) — forces the API to be good enough for scientific/statistical reporting, which often exposes gaps early
  • APA-style reporting becomes easier — R already has great citation/bibliography tooling (bibtex, citr); combined with bib-apa-*-swift the Swift-side emission can consume that
  • Reports become rerunnable single-file artefacts (the .swift) — superior reproducibility story vs. black-box .docx
  • Potentially drives Phase 2 priorities for word-builder-swift (headers/footers, numbering, images — all high-value for scientific reports)

Negative / risk:

  • Platform: Swift toolchain is required on the R user's machine. macOS native; Linux requires swift.org toolchain; Windows is painful. Scope is macOS-first, explicitly.
  • Dependency surface: R package pulls in nothing extra (pure R + shelling to Swift), but runtime needs swift binary on $PATH. Document prominently.
  • Performance: each render() call compiles the generated Swift file (~5–20s for a fresh compile, cached after). Acceptable for "run once per report" workflow; bad for "iterate 50 times" — mitigation: provide a persistent compile cache or a long-lived SPM project under ~/.wordBuilder/.

Scope (Phase 1 MVP)

  • R package (proposed name: wordBuilder, rswiftdocx, or docx.swift — open for bikeshed)
  • API mirrors word-builder-swift idioms where sensible: word_document(), add_heading(), add_paragraph(), add_text_run(), add_table()
  • Code generator: R state → .swift file using WordBuilderSwift
  • Shell-out runner: swift run the generated file, return .docx path
  • Type mapping Phase 1: character → heading/paragraph, data.frame → Table (no styling), list of character → mixed runs
  • Test suite: R-side unit tests (generated .swift matches golden files) + integration test (runs Swift, reads-back .docx via officer to assert content)
  • Vignette: "Your first report" translating an existing R markdown example

Scope (later phases, explicitly out)

  • ggplot2 → image embedding (needs word-builder-swift Phase 2 ImageRun)
  • Table styling / APA format (needs word-builder-swift Phase 2 Styles)
  • Cross-references / citations (needs Phase 2 hyperlinks + bookmarks)
  • Windows support (revisit when Swift/Windows matures)

Open design questions (for diagnosis)

  1. Repo location: PsychQuant/r-word-builder? Separate org? CRAN vs GitHub-only?
  2. Package name: any opinion? Short + searchable matters more than clever.
  3. Runner abstraction: should render() call macdoc's convert subcommand, or swift run directly on the generated file? (Former keeps macdoc as the single binary surface; latter is more direct.)
  4. Intermediate .swift retention: default retain vs default cleanup? Users likely want both modes.
  5. ggplot → image: wait for word-builder-swift Phase 2 ImageRun, or inline image embedding as raw OOXML in Phase 1 R-side? Probably wait — scope creep.
  6. Relationship to existing R → docx packages: compete with officer, or position as "officer for Swift users who want reviewable intermediates"?
  7. Testing strategy: how to assert generated .swift correctness without running Swift in every R CI (Swift toolchain install is slow)? Golden-file comparison + periodic end-to-end runs?

Related

Current Status

Phase: diagnosed
Last updated: 2026-04-22 by idd-diagnose (batch)


Current Status

Phase: diagnosed / MVP Spectra proposal ready
Last updated: 2026-05-02 by Codex

Key Decisions

  • feat: R package that emits WordBuilderSwift scripts from R analysis results #88 should start as a separate PsychQuant R package MVP, not macdoc CLI work.
  • Working package name: wordbuilder.
  • MVP API covers word_document(), add_heading(), add_paragraph(), add_text_run(), add_table(), and render().
  • render() generates Swift directly, runs Swift through a persistent package cache, and retains the generated .swift artifact by default.
  • Routine tests should use generated-Swift golden files; Swift compile/readback tests are marked as local or periodic integration tests.

Spectra Proposal

  • Change: r-word-builder-mvp
  • PR: Propose R wordbuilder MVP #96
  • Files: openspec/changes/r-word-builder-mvp/proposal.md, design.md, tasks.md, and specs/r-word-builder-mvp/spec.md
  • Validation passed: spectra analyze r-word-builder-mvp --json, spectra validate r-word-builder-mvp, and git diff --check -- openspec/changes/r-word-builder-mvp

Blocking

  • Waiting for PR Propose R wordbuilder MVP #96 review/merge.
  • After the proposal is accepted, next action is creating/using the implementation repository and applying r-word-builder-mvp there or mirroring the accepted tasks into that repo.

Commits

  • cd12010 docs: propose r word-builder mvp

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions