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: verified
Last updated: 2026-04-22 by idd-diagnose (batch)


Current Status

Phase: verified / 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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions