-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 新增 word-builder-swift — Swift fluent API 直接寫 .docx(類 docx.js) #71
Description
Problem
Original text(來自對話 2026-04-06):
「我其實想要做的就是也能做到 nodejs 那種寫 word 的程式而已」
「我其實今天看到有人用 js 結果做出很漂亮的 word,我很驚訝」
「好,所以我要用 word-builder-swift 吧」
— Source: 2026-04-06 設計討論對話
使用者希望 macdoc 生態中擁有類似 Node.js docx.js 的能力 — 用程式碼直接建構 .docx 檔案,取代手動操作 Word 或透過 che-word-mcp 的互動式 tool calls。
目前 macdoc 的 ooxml-swift 已具備完整的 OOXML writer 能力(DocxWriter + Document/Paragraph/Run/Table/Image model),但僅作為內部 converter 後端(md-to-word, html-to-word, tex-to-docx)使用,沒有對外暴露成「直接可用的 builder API」。
Type
feature
Expected
使用者可以在 Swift code 裡這樣寫:
import WordBuilderSwift
let doc = Document()
.heading(1, "Q1 季報")
.paragraph { p in
p.text("營收成長 ")
p.text("15%", bold: true)
}
try doc.write(to: URL(fileURLWithPath: "report.docx"))Actual
目前若要用 Swift 寫 .docx,必須直接 import OOXMLSwift 並手動建構 model:
import OOXMLSwift
var doc = WordDocument()
var props = ParagraphProperties()
props.style = "Heading1"
doc.appendParagraph(Paragraph(text: "Q1 季報", properties: props))
let runs: [Run] = [
Run(text: "營收成長 "),
Run(text: "15%", properties: RunProperties(bold: true))
]
doc.appendParagraph(Paragraph(runs: runs))
try DocxWriter.write(doc, to: url)需要手動建 RunProperties() / ParagraphProperties()、記住 style 名稱字串("Heading1")、沒有 fluent chaining,學習曲線較高。
Impact
Positive:
- 降低「用 Swift 程式化產生 .docx」的門檻,對齊 docx.js 的開發者體驗
- 為 macdoc 補上一個新的 source format:不是文件格式,而是「Swift code 作為來源」
- 可作為 md-to-word / html-to-word 等 converter 內部的共用 builder 層,未來可重構集中化
Risks / Open Questions:
- 需要先用 ooxml-swift 現有 API 寫幾份真實範例,才知道 wrapper 該長什麼樣(避免先寫抽象、後發現不合身)
- 可能不需要新 package,僅寫 USAGE.md + 範例就足夠(待驗證)
- 命名是否沿用
*-mac街道命名原則(e.g.,word-builder-mac)
Exploration Summary
已探勘 ooxml-swift 和 md-to-word-swift 現況:
| 檢查項 | 狀態 |
|---|---|
DocxWriter.write(_:to:) public API |
✅ 已存在 |
WordDocument / Paragraph / Run / Table / Image / Style model |
✅ 完整 |
ParagraphProperties / RunProperties(bold/italic/color/font/alignment...) |
✅ 完整 |
document.appendParagraph(_:) |
✅ 存在 |
| 對外 fluent builder API | ❌ 缺 |
預估 wrapper 厚度:~200-400 行 Swift(薄層糖衣)
相關檔案:
packages/ooxml-swift/Sources/OOXMLSwift/IO/DocxWriter.swift(534 行,寫入入口)packages/ooxml-swift/Sources/OOXMLSwift/Models/Document.swift(1997 行)packages/ooxml-swift/Sources/OOXMLSwift/Models/Paragraph.swift(322 行)packages/ooxml-swift/Sources/OOXMLSwift/Models/Run.swift(206 行)packages/md-to-word-swift/Sources/MDToWord/MarkdownASTWalker.swift(使用範例,L90 / L104 / L124)packages/md-to-word-swift/Sources/MDToWord/MarkdownToWordConverter.swift(L33 呼叫DocxWriter.write)
Proposed Approaches
| 選項 | 做法 | 成本 |
|---|---|---|
| A. 零 package | 寫 USAGE.md + 3-5 個真實範例到 ooxml-swift README | 0 |
| B. 薄 wrapper | 新 package word-builder-swift,只加 fluent builder + helper |
~300 行 |
| C. 厚 wrapper | B + 重構 md-to-word / html-to-word 改用 builder | ~800 行 + 改現有 converter |
建議路徑:先走 A 驗證真實使用情境,做 3-5 份「漂亮的 .docx」出來,用過幾次再決定要不要做 B。避免先寫抽象、後發現不合身。