bun-docx 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -18
- package/dist/index.js +5716 -1934
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,11 +90,15 @@ docx wc FILE [LOCATOR] [--accepted | --baseline | --current] [--json]
|
|
|
90
90
|
docx outline FILE [--style-prefix S] [--json]
|
|
91
91
|
docx styles FILE [--used] [--at STYLEID] [--json] # the style catalog (not in the body) — what --style NAMEs exist
|
|
92
92
|
docx styles --catalog [--json] # built-in styles you can apply on demand (Title, Heading1–9, Quote, …), no FILE needed
|
|
93
|
+
docx styles set FILE --at STYLEID [--bold --color HEX --size PT --font NAME --space-before PT --indent-left IN …] # restyle every paragraph/run that uses the style
|
|
94
|
+
docx styles create FILE STYLEID [--type paragraph|character] [--name "…"] [--based-on STYLEID] [--next STYLEID] [formatting] # define a new custom style
|
|
93
95
|
docx render FILE [--out DIR] [--engine word|libreoffice|auto] [--dpi N] [--pages 1-N] [--format png|jpg]
|
|
94
96
|
|
|
95
97
|
docx comments list FILE [--include-resolved] [--thread cN]
|
|
96
98
|
docx footnotes list FILE
|
|
97
99
|
docx endnotes list FILE
|
|
100
|
+
docx headers list FILE
|
|
101
|
+
docx footers list FILE
|
|
98
102
|
docx images list FILE
|
|
99
103
|
docx hyperlinks list FILE
|
|
100
104
|
docx track-changes list FILE
|
|
@@ -111,15 +115,37 @@ normal edits in place, `read --ast` is the lossless view, and `docx sections` /
|
|
|
111
115
|
(only when a value differs from the document default, so a plain document stays
|
|
112
116
|
clean):
|
|
113
117
|
|
|
118
|
+
- **Per-paragraph style/spacing/indent** — the most common annotation — rides a
|
|
119
|
+
`<!-- docx:p pN style="Caption" align="center" space-after="6pt" line-spacing="1" indent-left="0.25in" -->`
|
|
120
|
+
note, emitted deviation-only (only the attrs that differ from the style/document
|
|
121
|
+
default). Each attribute maps to the matching `edit`/`insert` flag (`--style`,
|
|
122
|
+
`--alignment`, `--space-before`/`--space-after`, `--line-spacing`,
|
|
123
|
+
`--indent-left`/`--indent-right`/`--first-line`/`--hanging`), so an agent reads a
|
|
124
|
+
value and re-applies it. The paragraph's locator rides this note as its leading `pN`
|
|
125
|
+
token, so an annotated paragraph does NOT also get a bare `<!-- pN -->` (only
|
|
126
|
+
undeviating paragraphs get the bare locator). Full properties are in `read --ast`.
|
|
114
127
|
- **Section breaks** render as `<!-- docx:section sN cols="2" type="continuous" -->`
|
|
115
128
|
on their own line — never a bare `---` (that's a thematic break, and emitting it
|
|
116
129
|
for a section silently turned layout into border paragraphs). A hand-authored
|
|
117
130
|
`---` now unambiguously means a thematic break.
|
|
118
|
-
- **Page geometry** rides a leading `<!-- docx:page orientation="landscape"
|
|
131
|
+
- **Page geometry** rides a leading `<!-- docx:page sN orientation="landscape"
|
|
119
132
|
size="…in" margins="…in" text-width="…in" -->` note when the page deviates from
|
|
120
|
-
US-Letter-portrait-1″ — `text-width` is the usable column width
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
US-Letter-portrait-1″ — `text-width` is the usable column width, and the leading
|
|
134
|
+
`sN` is the section to re-apply against. A `varies="by-section"` attribute is added
|
|
135
|
+
when a later section's page setup differs from the leading one — and in that case
|
|
136
|
+
the note fires **even if page 1 is plain default Letter-portrait-1″** (it then shows
|
|
137
|
+
just `text-width` + `varies="by-section"`), warning that the geometry shown describes
|
|
138
|
+
only the leading section; use `read --ast` for every section's exact geometry.
|
|
139
|
+
Exact twips are in `read --ast` (on each
|
|
140
|
+
section break: `pageWidth`/`pageHeight`/`pageOrientation`/`margin*`). Set it for the
|
|
141
|
+
WHOLE document with `docx sections --orientation/--size/--margins` (no `--at` →
|
|
142
|
+
every section gets it, so a multi-section doc doesn't leave the trailing section
|
|
143
|
+
behind), one section with `docx sections --at sN …`, or at `create` time; under
|
|
144
|
+
track-changes it records as one `<w:sectPrChange>` per section (accept/reject in Word).
|
|
145
|
+
Changing margins/size also **auto-realigns right-edge tab columns** (résumé
|
|
146
|
+
dates/locations): a LEFT tab calibrated to the old margins would overflow and wrap
|
|
147
|
+
at the new width, so page setup converts each to a RIGHT tab flush at the new
|
|
148
|
+
margin and reports how many it fixed — no second `--tabs right` step needed.
|
|
123
149
|
- **Tables** carry a leading `<!-- docx:table t0 widths="1,2,3in" borders="double" -->`
|
|
124
150
|
when columns are uneven or borders deviate from the default, plus a per-cell
|
|
125
151
|
`<!-- docx:cell t0:r0c0 gridSpan="2" vMerge="continue" shading="FFE699" -->`
|
|
@@ -130,25 +156,47 @@ clean):
|
|
|
130
156
|
`float`/`wrap`/`align`/`overflow` only when they deviate (an inline, in-bounds
|
|
131
157
|
image shows just its size). `overflow` flags an image wider than the usable text
|
|
132
158
|
column (`ImageRun.floating`/`wrap`/`align` + EMU extents in `read --ast`).
|
|
159
|
+
- **Headers / footers** surface as `<!-- docx:header text="Quarterly Report" -->`
|
|
160
|
+
/ `<!-- docx:footer text="Page {page} of {pages}" -->` notes (the `type` attr
|
|
161
|
+
appears only for `first`/`even`). Fields read as tokens — `{page}` `{pages}`
|
|
162
|
+
`{date}` `{time}` `{styleref:NAME}` `{filename}` `{title}` `{author}` (`{time}`
|
|
163
|
+
read-only). A marginal that's
|
|
164
|
+
the same on every section rides the top; one that **differs by section** renders at
|
|
165
|
+
that section's **start** (alongside the `docx:section` note, which also renders at
|
|
166
|
+
the section's start with `applies-to="… (below)"`), so each hint reads right before
|
|
167
|
+
the content it governs. The text lives in the comment attribute
|
|
168
|
+
so the importer drops it (it can't re-inject into the body); full entries are in
|
|
169
|
+
`read --ast` under `headers`/`footers` (`Marginal[]`). Set with `docx
|
|
170
|
+
headers`/`docx footers`.
|
|
171
|
+
- **Track-changes state** rides a head `<!-- docx:track-changes on -->` line when the
|
|
172
|
+
document's tracking toggle is enabled (deviation-only — off emits nothing), so an
|
|
173
|
+
agent sees that subsequent edits will be redlined without inspecting `settings.xml`.
|
|
174
|
+
Toggle it with `docx track-changes FILE on|off`; the three tracked-change read views
|
|
175
|
+
(`--accepted`/`--current`/`--baseline`) are covered under the review loop below.
|
|
133
176
|
|
|
134
177
|
### Mutate (change FILE in place; `--dry-run`, `-v` everywhere; `-o PATH` on every mutator except `create`, whose positional FILE is already the output)
|
|
135
178
|
|
|
136
179
|
```sh
|
|
137
|
-
docx create FILE [--title T] [--author A] [--text "..." | --text-file PATH | --from PATH.md | --from -] [--force]
|
|
180
|
+
docx create FILE [--title T] [--author A] [--text "..." | --text-file PATH | --from PATH.md | --from -] [--orientation O] [--size SIZE] [--margins M] [--header "..."] [--footer "..." | --page-numbers] [--force]
|
|
138
181
|
docx insert FILE (--after | --before) LOCATOR <content> # LOCATOR = pN | tN | sN | tN:rRcC:pK
|
|
139
182
|
docx insert FILE (--at-start | --at-end) <content> # no locator — prepend / append to the document
|
|
140
183
|
docx edit FILE --at LOCATOR <content> # LOCATOR = pN | pN:S-E | pN-pM | sN | eqN | tN:rRcC:pK[:S-E]
|
|
141
|
-
docx delete FILE --at LOCATOR # LOCATOR = pN | pN-pM | tN | sN
|
|
142
|
-
docx sections FILE --at LOCATOR --columns N [--type T]
|
|
184
|
+
docx delete FILE --at LOCATOR # LOCATOR = pN | pN-pM | tN | sN | tN:rRcC:pK (cell paragraph)
|
|
185
|
+
docx sections FILE [--at LOCATOR] [--columns N] [--type T] [--orientation O] [--size SIZE] [--margins M] # LOCATOR = pN-pM | pN (wrap a range in N columns) | sN (edit one section's columns/type/page geometry). Multi-column layout AND page setup live HERE. PAGE GEOMETRY (margins/orientation/size) with NO --at applies to the WHOLE document (every section); --at sN targets one. Columns/type need --at.
|
|
143
186
|
docx styles set-default-font FILE "Font Name" [--size N] [--all] # document-wide font: sets styles.xml docDefaults + theme major/minor; --all also repoints styles/runs that pin their own font
|
|
144
|
-
docx replace FILE PATTERN REPLACEMENT [--regex] [--ignore-case] [--all] [--limit N] [--current | --baseline] [--exact] [--track] [--dry-run]
|
|
187
|
+
docx replace FILE PATTERN REPLACEMENT [--at pN] [--regex] [--ignore-case] [--all] [--limit N] [--current | --baseline] [--exact] [--track] [--dry-run]
|
|
188
|
+
# Keeps the run's formatting (bold/font) and any tabs — the no-rebuild way to fill a
|
|
189
|
+
# formatted/tabbed template line (e.g. "**Org Name**⇥Date"); don't hand-build --runs to refill it.
|
|
190
|
+
# --at pN (or a cell paragraph tT:rRcC:pN) CONFINES the replace to one paragraph — use it when the
|
|
191
|
+
# SAME placeholder repeats across the doc (a résumé's "City, State" in every entry) and you want THE
|
|
192
|
+
# one in a specific paragraph, instead of find → edit --at pN:S-E span surgery. Batch entries take "at" too.
|
|
145
193
|
|
|
146
194
|
# Batch — apply many changes from ONE read (no re-reading between edits). Keys
|
|
147
195
|
# on each JSONL line mirror the command's flags; all locators address the doc as
|
|
148
196
|
# read. insert/edit also accept --batch - to read JSONL from stdin.
|
|
149
197
|
docx edit FILE --batch fills.jsonl # { at, <one of: text|clear|markdown|runs|code|task>, style?, … }
|
|
150
198
|
docx insert FILE --batch additions.jsonl # { after|before, <content>, style?, color?, … }
|
|
151
|
-
docx replace FILE --batch script.jsonl # { pattern, replacement, regex?, all?, limit?, … } applied in order
|
|
199
|
+
docx replace FILE --batch script.jsonl # { pattern, replacement, at?, regex?, all?, limit?, … } applied in order ("at" scopes that entry to one paragraph)
|
|
152
200
|
docx delete FILE --batch drop.jsonl # { at } per line — whole blocks (pN/tN/cell), resolved live-first
|
|
153
201
|
|
|
154
202
|
# All four of insert/edit/delete/replace accept --track to record that one
|
|
@@ -157,12 +205,23 @@ docx delete FILE --batch drop.jsonl # { at } per line — whole blocks (
|
|
|
157
205
|
# insert/edit content selectors (run "docx insert --help" / "docx edit --help" for the full list):
|
|
158
206
|
# --text "..." [--style NAME] [--alignment A] [--color HEX] [--bold] [--italic] [--url URL]
|
|
159
207
|
# (a newline in --text becomes a line break <w:br/>, a tab becomes <w:tab/> — verse/addresses stay line-per-line)
|
|
208
|
+
# paragraph spacing/indent (insert + edit, alone or with content, per-entry in --batch, across a range):
|
|
209
|
+
# --space-before PT --space-after PT --line-spacing N(=1|1.5|2|single|double, or 15pt / "15pt atLeast")
|
|
210
|
+
# --indent-left IN --indent-right IN --first-line IN --hanging IN (points / inches; first-line ⊥ hanging;
|
|
211
|
+
# left/right/first-line accept a negative value to outdent into the margin; hanging stays non-negative)
|
|
212
|
+
# Under track-changes these record a tracked <w:pPrChange> (accept/reject in Word) — even when they ride
|
|
213
|
+
# along with --text; read surfaces them as a deviation-only <!-- docx:p … space-after="6pt" --> hint.
|
|
160
214
|
# edit --tabs right fix a line whose tabbed-over content WRAPS (read flags it as `docx:layout … warn`,
|
|
161
215
|
# and prints ONE consolidated fix-all summary at the top): swaps the fragile LEFT tab for a RIGHT tab
|
|
162
216
|
# flush at the margin so a long value (e.g. a city) never wraps. Rides along with --text, works
|
|
163
217
|
# per-entry in --batch, and on a RANGE (edit --at pN-pM --tabs right) cures every tab line at once.
|
|
164
|
-
# edit --text ""
|
|
165
|
-
#
|
|
218
|
+
# edit --text "" REMOVES the line (same as `delete`; a table cell's last paragraph is blanked, not
|
|
219
|
+
# deleted, so the cell stays valid). In --batch, `{"at":"pN","text":""}` or `{"at":"pN","delete":true}`
|
|
220
|
+
# removes a line — so a form-fill is ONE sweep: fill the cells with values, drop the leftover
|
|
221
|
+
# placeholder lines. Use `--runs '[]'` to blank a paragraph but keep an empty spacer. (Empty
|
|
222
|
+
# `--text` can't ride along with --clear/run-formatting/--style/--alignment/--tabs — those exit
|
|
223
|
+
# with a USAGE error; use `--runs '[]'` to keep a formatted empty spacer instead.) A SPAN's
|
|
224
|
+
# `--text ""` (pN:S-E) still deletes just those characters.
|
|
166
225
|
# --runs '[{"type":"text","text":"X","bold":true}]'
|
|
167
226
|
# --text-file PATH # (insert/create) LITERAL multi-paragraph text, NOT parsed — every char verbatim,
|
|
168
227
|
# each newline = a new paragraph. For prose GFM would corrupt: "3. note" stays "3.", *x* / [t](u) / bare URLs / {++x++} untouched.
|
|
@@ -170,6 +229,13 @@ docx delete FILE --batch drop.jsonl # { at } per line — whole blocks (
|
|
|
170
229
|
# --code "..." | --code-file PATH [--language LANG]
|
|
171
230
|
# --equation "x^2 + y^2" [--display] (insert; edit also accepts --inline)
|
|
172
231
|
# --clear bold,italic,highlight,color,size,font,…|all (edit; strip run formatting, keep text)
|
|
232
|
+
# --bold --italic --underline --strike --color HEX --highlight NAME --shade HEX --font NAME --size PT
|
|
233
|
+
# --caps --smallcaps --superscript --subscript (edit; SET run formatting on EXISTING text —
|
|
234
|
+
# the inverse of --clear. Alone they format a span/paragraph/range in place; with --text they
|
|
235
|
+
# fill AND format. Like --clear, applied directly — not recorded as a tracked change.)
|
|
236
|
+
# NOTE: in a single no-content call (or one --batch entry) these run-format SET flags and the
|
|
237
|
+
# paragraph properties (--style/--alignment/--space-*/--line-spacing/--indent-*/--first-line/
|
|
238
|
+
# --hanging/--tabs) can't ride together — use separate calls/entries, or add --text to set both.
|
|
173
239
|
# --task checked|unchecked | --list bullet|ordered [--list-level N] (insert)
|
|
174
240
|
# --task checked|unchecked (edit, flip in place)
|
|
175
241
|
# --table --rows N --cols N [--widths "A,B,C"] [--table-width V] [--borders S] [--layout L] (insert)
|
|
@@ -190,6 +256,17 @@ docx endnotes add FILE --at pN[:offset] (--text "..." | --runs JSON | --mark
|
|
|
190
256
|
docx endnotes edit FILE --at enN (--text "..." | --runs JSON | --markdown TEXT)
|
|
191
257
|
docx endnotes delete FILE --at enN
|
|
192
258
|
|
|
259
|
+
# Headers & footers (one shared impl — "marginals"). Default placement is every
|
|
260
|
+
# page, all sections (--at sN targets one). Content: ONE primary source, except
|
|
261
|
+
# --text + one field = two-zone (text left, field right at a content-edge tab).
|
|
262
|
+
docx headers set FILE [--at sN] [--type default|first|even | --first-page | --even | --odd] \
|
|
263
|
+
[--text "..."] [--align left|center|right] \
|
|
264
|
+
[--page-number [--of-pages] | --date [--date-format FMT] | --style-ref STYLE | --field filename|title|author] \
|
|
265
|
+
[--track] [--author NAME]
|
|
266
|
+
docx headers clear FILE [--at sN] [--type T | --first-page | --even | --odd]
|
|
267
|
+
docx footers set FILE … # identical flags, kind=footer (e.g. --page-number --of-pages → "Page X of Y")
|
|
268
|
+
docx footers clear FILE …
|
|
269
|
+
|
|
193
270
|
docx images extract FILE --to DIR [--at imgN] # --to = output directory; --at picks one image
|
|
194
271
|
docx images replace FILE --at imgN --with ./new.png
|
|
195
272
|
docx images delete FILE --at imgN
|
|
@@ -208,14 +285,22 @@ docx tables unmerge FILE --at tN:rRcC
|
|
|
208
285
|
docx tables borders FILE --at tN [--style single|double|none] [--size N] [--color HEX]
|
|
209
286
|
|
|
210
287
|
docx track-changes on|off FILE
|
|
288
|
+
docx track-changes list FILE [--json]
|
|
211
289
|
docx track-changes accept FILE (--at tcN [--at tcM ...] | --at revN | --all)
|
|
212
290
|
docx track-changes reject FILE (--at tcN [--at tcM ...] | --at revN | --all)
|
|
213
|
-
|
|
214
|
-
#
|
|
291
|
+
docx track-changes apply FILE [--accept H ...] [--reject H ...]
|
|
292
|
+
# `list` defaults to a text table, one LOGICAL change per line (revN collapses a del+ins
|
|
293
|
+
# pair onto one line); `--json` for the raw array. A del+ins REPLACE pair shares a
|
|
294
|
+
# "group": "revN"; `--at revN` accepts/rejects both halves in one call.
|
|
295
|
+
# To FINALIZE a review (accept some, reject the rest), use `apply` — it takes both decision
|
|
296
|
+
# lists in ONE call, resolved against the original ids, so nothing renumbers mid-operation
|
|
297
|
+
# and the file is never left half-finalized. Doing it as separate accept then reject calls
|
|
298
|
+
# renumbers the ids between them. After a subset accept/reject/apply, the confirmation
|
|
299
|
+
# re-lists what remains with its renumbered handles.
|
|
215
300
|
```
|
|
216
301
|
|
|
217
302
|
> **One rule to memorize: addressing an existing thing is always `--at`.**
|
|
218
|
-
> `comments reply/resolve/delete`, `footnotes/endnotes edit/delete`, `images extract/replace/delete`, `hyperlinks replace/delete`, `tables *`, `track-changes accept/reject`, `edit`, and `delete` all take `--at LOCATOR`. The exceptions are positional or directional by nature: `insert` uses `--after`/`--before LOCATOR` (or `--at-start`/`--at-end` for the document boundaries, no locator); `read` slices with `--from`/`--to LOCATOR`; `wc` takes a positional `[LOCATOR]`; `find`/`replace` take a positional `QUERY`/`PATTERN
|
|
303
|
+
> `comments reply/resolve/delete`, `footnotes/endnotes edit/delete`, `images extract/replace/delete`, `hyperlinks replace/delete`, `tables *`, `track-changes accept/reject`, `edit`, and `delete` all take `--at LOCATOR`. The exceptions are positional or directional by nature: `insert` uses `--after`/`--before LOCATOR` (or `--at-start`/`--at-end` for the document boundaries, no locator); `read` slices with `--from`/`--to LOCATOR`; `wc` takes a positional `[LOCATOR]`; `find`/`replace` take a positional `QUERY`/`PATTERN` (and `replace` accepts an optional `--at pN` to *confine* the substitution to one paragraph). `images extract --to DIR` is an *output directory*, not a locator.
|
|
219
304
|
|
|
220
305
|
## Output contract
|
|
221
306
|
|
|
@@ -235,13 +320,13 @@ The CLI is built for non-interactive agents. **Exit code is the success signal**
|
|
|
235
320
|
| Command class | Default stdout on success | `--verbose` |
|
|
236
321
|
| ------------- | ------------------------- | ----------- |
|
|
237
322
|
| **Mutator that mints a new handle** — `comments add`→`cN`, `comments reply`→`cN`, `footnotes/endnotes add`→`fnN`/`enN`, `hyperlinks add`→`linkN`, `insert`→the new `pN` | the bare locator(s), **one per line** (a multi-block `--markdown` insert prints several) | full `{ok:true,…}` ack |
|
|
238
|
-
| **Mutator with no new handle** — `edit`, `delete`, `replace`, `create`, `comments resolve/delete`, `images replace/delete`, `hyperlinks replace/delete`, `footnotes/endnotes edit/delete`, `tables *`, `track-changes accept/reject` & toggle | **one-line confirmation** — `<operation> <target>` (e.g. `edit t1:r0c1:p0`, `edit 7 changes`, `replace 0 occurrences replaced`) (exit `0`) | full `{ok:true,…}` ack |
|
|
323
|
+
| **Mutator with no new handle** — `edit`, `delete`, `replace`, `create`, `comments resolve/delete`, `images replace/delete`, `hyperlinks replace/delete`, `footnotes/endnotes edit/delete`, `headers/footers set/clear`, `tables *`, `track-changes accept/reject` & toggle | **one-line confirmation** — `<operation> <target>` (e.g. `edit t1:r0c1:p0`, `edit 7 changes`, `replace 0 occurrences replaced`) (exit `0`) | full `{ok:true,…}` ack |
|
|
239
324
|
| `find` | matched span locators, one per line (no matches → nothing, exit `0`) | `--json` → `{ totalMatches, query, view, matches:[…], normalizedQuery? }` |
|
|
240
325
|
| `wc` | the bare count (whole-doc adds a tab-separated `sections` column, like `wc`) | `--json` → `{ words, scope, view, sections? }` |
|
|
241
326
|
| `outline` | indented `LOCATOR⇥TEXT` tree (two spaces per level) | `--json` → nested `[{ id, locator, level, style, text, children }]` |
|
|
242
|
-
| `read` | GFM Markdown
|
|
327
|
+
| `read` | GFM Markdown; each paragraph carries its `pN` locator once — a trailing bare `<!-- pN -->` on plain paragraphs, or the leading token of its `<!-- docx:p pN … -->` note when one is emitted | `--ast` → the JSON AST body (`docx info schema`) |
|
|
243
328
|
| `render` | image paths, one per line | `--verbose` → `{ok, operation, path, engine, output, pages}` |
|
|
244
|
-
| `* list` (all
|
|
329
|
+
| `* list` (all eight `list` verbs) | a **bare JSON array**; each item's `id` is its `--at` handle | — |
|
|
245
330
|
|
|
246
331
|
`--dry-run` always prints a preview object (no `ok`) and writes nothing; it wins over `-o/--output`.
|
|
247
332
|
|
|
@@ -254,6 +339,7 @@ Locators come in two flavors. **Positional block ids** (`pN`, `tN`, `sN`) are de
|
|
|
254
339
|
| `pN` / `tN` / `sN` (block ids) | `docx read FILE` (the `<!-- pN -->` trailers), `docx read FILE --ast`, `docx outline FILE` (heading `pN`s), or `docx render` page images | `read`, `edit`, `insert`, `delete`, `wc`, `find` results |
|
|
255
340
|
| `cN` (comment) | `docx comments list FILE` | `comments reply/resolve/delete --at` |
|
|
256
341
|
| `fnN` / `enN` (foot/endnote) | `docx footnotes list FILE` / `docx endnotes list FILE` | `footnotes/endnotes edit/delete --at` |
|
|
342
|
+
| `hdrN` / `ftrN` (header/footer) | `docx headers list FILE` / `docx footers list FILE` (or `read --ast`) | addressed by section+type, not the id: `headers/footers set --at sN --type T` |
|
|
257
343
|
| `imgN` (image) | `docx images list FILE` | `images extract/replace/delete --at` |
|
|
258
344
|
| `linkN` (hyperlink) | `docx hyperlinks list FILE` | `hyperlinks replace/delete --at` |
|
|
259
345
|
| `tcN` (tracked change) | `docx track-changes list FILE` | `track-changes accept/reject --at` |
|
|
@@ -285,7 +371,7 @@ cN imgN linkN fnN enN tcN eqN entity ids (comment / image / hyper
|
|
|
285
371
|
| ---- | ----------- |
|
|
286
372
|
| `pN`, `tN`, `sN`, `tN:rRcC:pK` (blocks) | `read --from/--to`, `insert --after/--before`, `wc`, `comments add` |
|
|
287
373
|
| `pN`, `pN:S-E`, `pN-pM`, `sN`, `eqN`, `tN:rRcC:pK`, `tN:rRcC:pK:S-E` | `edit --at` (span/cell forms strip or replace just that range) |
|
|
288
|
-
| `pN`, `pN-pM`, `tN`, `sN` | `delete --at` |
|
|
374
|
+
| `pN`, `pN-pM`, `tN`, `sN`, `tN:rRcC:pK` | `delete --at` |
|
|
289
375
|
| `pN:S-E`, `pN:S-pM:E`, `tN:rRcC:pK:S-E` (spans) | `comments add --at`, `hyperlinks add --at` (single paragraph), `find`/`wc` results |
|
|
290
376
|
| `pN[:offset]` (point) | `footnotes/endnotes add --at` |
|
|
291
377
|
| `cN` / `fnN` / `enN` / `imgN` / `linkN` / `tcN` (entities) | the matching noun's `--at` (the `c`/`fn`/`en`/`img`/`link`/`tc` prefix is optional) |
|
|
@@ -342,6 +428,8 @@ docx track-changes accept doc.docx --at tc0 --at tc2 # or --all
|
|
|
342
428
|
|
|
343
429
|
**Document-wide font.** `docx styles set-default-font FILE "Times New Roman"` sets the font in the two places a font actually lives — `word/styles.xml` `<w:docDefaults>` (the formal default) *and* the theme font scheme (`word/theme/theme1.xml`, major + minor `<a:latin>`), since real Word docs resolve their fonts *through* the theme and touching only one silently loses to the other. Body text and theme-following headings both adopt it; styles or runs that pin their own font (a code block's monospace, a deliberately-Arial run) are preserved and named in the ack, with `--all` to repoint even those. `--size N` sets the default size on the same write.
|
|
344
430
|
|
|
431
|
+
**Edit & create styles.** `docx styles set FILE --at Heading1 --color 1F4E79 --size 16 --bold` rewrites the *style definition* in `word/styles.xml`, so every paragraph or run that uses the style picks up the change at once ("make all Heading 1s green") — the same run-/paragraph-formatting flags as `edit` (color/font/size/highlight/underline/caps + alignment/spacing/indentation for paragraph styles). `docx styles create FILE Callout --color C00000 --bold` mints a new paragraph or character style that `insert/edit --style Callout` can then apply. Editing an un-materialized built-in (`--at Heading3` on a doc that never used it) provisions it first; a paragraph with its own *direct* formatting keeps it (the override wins — the definition edit never touches the body). Style edits are **not** tracked changes even under track-changes — matching Word, which applies style-definition edits to `styles.xml` directly with no redline.
|
|
432
|
+
|
|
345
433
|
**Run formatting beyond bold/italic.** Properties markdown has no native syntax for — text color, theme color, highlight, shading, underline (all 18 styles + color), super/subscript, small/all caps, font, and size — are emitted as the **HTML a markdown reader actually renders**, so the output looks right in GitHub, VS Code, Obsidian, and browsers (Pandoc `[text]{…}` spans render as literal brackets in all of those). `read` emits semantic tags where they exist — `<mark>overdue</mark>`, `<sup>x</sup>`, `<sub>2</sub>` — a `<span style="color:#C00000">…</span>` for the CSS-expressible properties, and `data-*` attributes for the OOXML-only ones CSS can't express (theme colors, underline styles); `insert/edit --markdown` parses them back losslessly, and a leading `<!-- docx:base font="Arial" size="8pt" -->` note declares the document's dominant font/size once so the body isn't buried in per-run repetition. Bold/italic/strike/code/links stay native (`**`/`*`/`~~`/`` ` ``/`[](…)`). Because the inline-surgery transform scans whole sibling sequences, a CriticMarkup marker or span can straddle other formatting — `{++**bold insertion**++}` is tracked correctly. An invalid enum value (e.g. a bogus highlight name) fails with a clear error rather than silently vanishing. Inserted plain content inherits the surrounding paragraph's font/size so it blends in.
|
|
346
434
|
|
|
347
435
|
**Visual verification.** `docx render` is the only command that needs an external runtime: it drives Microsoft Word (macOS via `osascript`, Windows via PowerShell COM — the ground-truth renderer) or LibreOffice (`soffice`, cross-platform) to produce a PDF, then rasterizes in-process via the bundled `@hyzyla/pdfium` WASM package — no poppler/pdftoppm/ImageMagick needed. Agents that consume PNGs use this to verify edits, diff accept/reject before-vs-after, or generate screenshots.
|