docrev 0.11.1 → 0.11.3

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.
Files changed (144) hide show
  1. package/.gitattributes +1 -1
  2. package/CHANGELOG.md +207 -197
  3. package/PLAN-tables-and-postprocess.md +850 -850
  4. package/README.md +433 -433
  5. package/bin/rev.js +11 -11
  6. package/bin/rev.ts +145 -145
  7. package/completions/rev.bash +127 -127
  8. package/completions/rev.ps1 +210 -210
  9. package/completions/rev.zsh +207 -207
  10. package/dist/lib/annotations.d.ts.map +1 -1
  11. package/dist/lib/annotations.js +28 -0
  12. package/dist/lib/annotations.js.map +1 -1
  13. package/dist/lib/build.d.ts +28 -0
  14. package/dist/lib/build.d.ts.map +1 -1
  15. package/dist/lib/build.js +81 -4
  16. package/dist/lib/build.js.map +1 -1
  17. package/dist/lib/commands/comments.d.ts.map +1 -1
  18. package/dist/lib/commands/comments.js +58 -28
  19. package/dist/lib/commands/comments.js.map +1 -1
  20. package/dist/lib/commands/context.d.ts +1 -0
  21. package/dist/lib/commands/context.d.ts.map +1 -1
  22. package/dist/lib/commands/context.js +1 -0
  23. package/dist/lib/commands/context.js.map +1 -1
  24. package/dist/lib/commands/core.d.ts.map +1 -1
  25. package/dist/lib/commands/core.js +25 -8
  26. package/dist/lib/commands/core.js.map +1 -1
  27. package/dist/lib/commands/response.js +1 -1
  28. package/dist/lib/commands/response.js.map +1 -1
  29. package/dist/lib/commands/utilities.js +164 -164
  30. package/dist/lib/commands/word-tools.js +8 -8
  31. package/dist/lib/grammar.js +3 -3
  32. package/dist/lib/import.d.ts +14 -0
  33. package/dist/lib/import.d.ts.map +1 -1
  34. package/dist/lib/import.js +23 -0
  35. package/dist/lib/import.js.map +1 -1
  36. package/dist/lib/input.d.ts +67 -0
  37. package/dist/lib/input.d.ts.map +1 -0
  38. package/dist/lib/input.js +164 -0
  39. package/dist/lib/input.js.map +1 -0
  40. package/dist/lib/macro-filter.lua +201 -201
  41. package/dist/lib/pdf-comments.js +44 -44
  42. package/dist/lib/plugins.js +57 -57
  43. package/dist/lib/pptx-color-filter.lua +37 -37
  44. package/dist/lib/pptx-themes.js +115 -115
  45. package/dist/lib/response.d.ts +1 -1
  46. package/dist/lib/response.d.ts.map +1 -1
  47. package/dist/lib/response.js +5 -2
  48. package/dist/lib/response.js.map +1 -1
  49. package/dist/lib/schema.d.ts.map +1 -1
  50. package/dist/lib/schema.js +8 -2
  51. package/dist/lib/schema.js.map +1 -1
  52. package/dist/lib/spelling.js +2 -2
  53. package/dist/lib/templates.js +387 -387
  54. package/dist/lib/themes.js +51 -51
  55. package/eslint.config.js +27 -27
  56. package/lib/anchor-match.ts +307 -307
  57. package/lib/annotations.ts +695 -664
  58. package/lib/build.ts +2047 -1956
  59. package/lib/citations.ts +160 -160
  60. package/lib/commands/build.ts +885 -885
  61. package/lib/commands/citations.ts +515 -515
  62. package/lib/commands/comments.ts +1077 -1050
  63. package/lib/commands/context.ts +185 -176
  64. package/lib/commands/core.ts +328 -309
  65. package/lib/commands/doi.ts +451 -451
  66. package/lib/commands/file-ops.ts +372 -372
  67. package/lib/commands/history.ts +320 -320
  68. package/lib/commands/index.ts +87 -87
  69. package/lib/commands/init.ts +259 -259
  70. package/lib/commands/merge-resolve.ts +378 -378
  71. package/lib/commands/preview.ts +178 -178
  72. package/lib/commands/project-info.ts +244 -244
  73. package/lib/commands/quality.ts +517 -517
  74. package/lib/commands/response.ts +454 -454
  75. package/lib/commands/section-boundaries.ts +82 -82
  76. package/lib/commands/sections.ts +451 -451
  77. package/lib/commands/sync.ts +689 -689
  78. package/lib/commands/text-ops.ts +449 -449
  79. package/lib/commands/utilities.ts +448 -448
  80. package/lib/commands/verify-anchors.ts +272 -272
  81. package/lib/commands/word-tools.ts +340 -340
  82. package/lib/comment-realign.ts +99 -99
  83. package/lib/config.ts +84 -84
  84. package/lib/crossref.ts +781 -781
  85. package/lib/csl.ts +191 -191
  86. package/lib/dependencies.ts +132 -132
  87. package/lib/diff-engine.ts +465 -465
  88. package/lib/doi-cache.ts +115 -115
  89. package/lib/doi.ts +879 -879
  90. package/lib/equations.ts +506 -506
  91. package/lib/errors.ts +350 -350
  92. package/lib/format.ts +541 -541
  93. package/lib/git.ts +326 -326
  94. package/lib/grammar.ts +303 -303
  95. package/lib/image-registry.ts +180 -180
  96. package/lib/import.ts +932 -906
  97. package/lib/input.ts +174 -0
  98. package/lib/journals.ts +543 -543
  99. package/lib/macro-filter.lua +201 -201
  100. package/lib/macros.ts +273 -273
  101. package/lib/merge.ts +633 -633
  102. package/lib/ooxml.ts +768 -768
  103. package/lib/orcid.ts +144 -144
  104. package/lib/pdf-comments.ts +263 -263
  105. package/lib/pdf-import.ts +524 -524
  106. package/lib/plugins.ts +362 -362
  107. package/lib/postprocess.ts +188 -188
  108. package/lib/pptx-color-filter.lua +37 -37
  109. package/lib/pptx-template.ts +469 -469
  110. package/lib/pptx-themes.ts +483 -483
  111. package/lib/protect-restore.ts +520 -520
  112. package/lib/rate-limiter.ts +127 -127
  113. package/lib/response.ts +200 -197
  114. package/lib/restore-references.ts +240 -240
  115. package/lib/review.ts +327 -327
  116. package/lib/schema.ts +494 -488
  117. package/lib/scientific-words.ts +73 -73
  118. package/lib/sections.ts +428 -428
  119. package/lib/slides.ts +756 -756
  120. package/lib/spelling.ts +334 -334
  121. package/lib/templates.ts +526 -526
  122. package/lib/themes.ts +742 -742
  123. package/lib/trackchanges.ts +166 -166
  124. package/lib/tui.ts +450 -450
  125. package/lib/types.ts +546 -546
  126. package/lib/undo.ts +250 -250
  127. package/lib/utils.ts +69 -69
  128. package/lib/variables.ts +179 -179
  129. package/lib/word-extraction.ts +525 -525
  130. package/lib/word.ts +526 -526
  131. package/lib/wordcomments.ts +789 -789
  132. package/package.json +1 -1
  133. package/scripts/postbuild.js +47 -47
  134. package/skill/REFERENCE.md +550 -550
  135. package/skill/SKILL.md +302 -302
  136. package/tsconfig.json +26 -26
  137. package/types/index.d.ts +531 -531
  138. package/issues.md +0 -180
  139. package/site/assets/extra.css +0 -208
  140. package/site/commands.html +0 -926
  141. package/site/configuration.html +0 -469
  142. package/site/index.html +0 -288
  143. package/site/troubleshooting.html +0 -461
  144. package/site/workflow.html +0 -518
package/.gitattributes CHANGED
@@ -1 +1 @@
1
- dist/** linguist-generated
1
+ dist/** linguist-generated
package/CHANGELOG.md CHANGED
@@ -1,197 +1,207 @@
1
- # Changelog
2
-
3
- All notable changes to docrev will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [0.11.1] - 2026-07-05
9
-
10
- ### Added
11
- - **`rev build docx --dual --show-changes` emits tracked changes and threaded comments in one file (#6).** The standard "return to senior author" artifact my `{++..++}`/`{--..--}` edits as Word tracked changes alongside the reviewer's `{>>..<<}` comments with my threaded replies now builds as a single `<title>-changes.docx`. Previously the two were mutually exclusive: `--show-changes` dropped comments, `--dual` accepted all changes. A new `buildReviewedDocx` runs one pandoc pass through the full filter chain, then threads comments into the same file. Add `--reference <docx>` to realign comment anchors first.
12
-
13
- ### Changed
14
- - **Track changes now use pandoc-native `w:ins`/`w:del` revisions.** `--show-changes` (and `rev apply`) previously injected revision XML by string-replacing text markers, which nested `<w:ins>`/`<w:del>` inside `<w:t>` (malformed OOXML) and bypassed crossref/citeproc/the reference-doc. CriticMarkup is now converted to pandoc `.insertion`/`.deletion` spans and emitted as well-formed run-level revisions through the full filter chain.
15
-
16
- ## [0.11.0] - 2026-07-05
17
-
18
- ### Changed
19
- - **Parser-backed OOXML layer, unified placement engine, boundary hardening.** One structural OOXML tokenizer (`lib/ooxml.ts`) now backs every Word reader and the comment injector, collapsing the divergent `extractCommentAnchors`/`extractWordComments` paths onto a single namespace-aware engine (matches WordprocessingML by URI, decodes entities, excludes `instrText` field codes, enumerates footnote/endnote parts, finds runs structurally). Section comment placement is offset-first, with proportional estimates demoted to a flagged last resort surfaced by `sync`. Rate-limiter gains a per-request timeout and HTTP-date `Retry-After` parsing; `checkDoi` reports unreachable distinctly from invalid; PPTX post-processing failures warn instead of being swallowed.
20
-
21
- ## [0.10.2] - 2026-06-22
22
-
23
- ### Fixed
24
- - **`rev init` now derives subsection headers too (#5 Bug B).** 0.10.1 fixed first-heading-at-any-level only for the `rev.yaml`-derived path; `generateConfig` (the `rev init` -> `sections.yaml` path) still used H1-only extraction, so a project initialised with `rev init` left a `## 1.2 Objectives` file headed `Sec2` and folded its content into the preceding section on sync. `generateConfig` and `splitAnnotatedPaper` now use the first heading at any level.
25
- - **Comments routed to non-keyword sections are no longer silently dropped (#5 Bug C).** The main `sync` flow routed comments with a hardcoded keyword list (abstract/intro/methods/results/discussion/conclusion); sections named e.g. `Objectives` or `Annex 2` got no boundary and their comments were discarded while the summary still reported every comment as placed. Comment routing now uses the same heading-based `computeSectionBoundaries` as `sync --comments-only`.
26
- - **Sections absent (as prose) from the reviewed document are left untouched (#5 Bug C).** A section that appears only as a bare heading with no body — e.g. when a "no-annex" export is synced against the full project — was diffed against empty content and rewritten to near-empty. Such sections are now reported as `untouched` and left on disk unchanged.
27
-
28
- ### Changed
29
- - **Truthful sync summary (#5 Bug C).** The summary now reports `N of M comments placed`, plus `already present`, `unmatched`, and `not routed to any synced section` counts (from `insertCommentsIntoMarkdown`'s `outStats`), instead of asserting that the raw extracted count was placed.
30
- - The main `sync` flow and `sync --comments-only` now share one comment-routing path, removing the divergent keyword-search boundary logic.
31
-
32
- ## [0.10.1] - 2026-06-05
33
-
34
- ### Fixed
35
- - **`sync`/`verify-anchors`/`split` no longer require a separate `sections.yaml`.** `build` and `status` read the `sections:` list from `rev.yaml`, but the sync-side commands demanded a `sections.yaml` and aborted with `Config not found` on a perfectly valid `rev.yaml`-only project. They now resolve the section config from a single source of truth: an explicit `sections.yaml` is used when present (to override headers/aliases/order), otherwise the config is derived from `rev.yaml`'s `sections:` list. Running `rev init` first is no longer necessary.
36
- - **Derived section headers honor the file's first heading at any level.** A section file that leads with a subsection (e.g. `02_objectives.md` starting with `## 1.2 Objectives`) now derives the header `1.2 Objectives` (via the new `extractFirstHeading`), so it matches the corresponding docx heading and routes to its own file instead of being folded into the preceding section. `extractHeader` keeps its H1-only contract for existing callers.
37
-
38
- ### Added
39
- - `resolveSectionsConfig(dir, configFile?)` and `deriveSectionsFromRev(dir)` in `lib/sections.ts`, with tests.
40
-
41
- ## [0.10.0] - 2026-05-20
42
-
43
- ### Added
44
- - **Placeholder macros.** Built-in `\tofill{X}` renders as bold orange `[X]` across DOCX, PDF/TeX/Beamer, and HTML — drop the LaTeX-style command anywhere in a section file and the build expands it per format. No more copying a `tofill_filter.lua` + `\providecommand` boilerplate into each project. Users can add their own one-argument macros under `macros:` in `rev.yaml` (color, bold/italic, bracket wrap, prefix/suffix, per-format overrides). See `docs/configuration.md` for the schema.
45
- - **`lib/macros.ts` + `lib/macro-filter.lua`** registry-style implementation. Built-ins and user macros merge by name; user entries override built-ins. The lua filter loads its macro list from a JSON sidecar via the `DOCREV_MACROS_FILE` env var.
46
-
47
- ### Fixed
48
- - **Silent DOCX color drop.** Pandoc 3.x's docx writer does NOT honor `Span` with `style="color: #..."`, so a lua filter returning `pandoc.Span(pandoc.Strong(...), pandoc.Attr("", {}, {style="color: #C2410C"}))` produced zero `<w:color>` runs and the highlight vanished. The new filter emits raw OpenXML `<w:r>` nodes directly (the same pattern as the existing `pptx-color-filter.lua`), which produces real colored runs in Word.
49
- - **Silent DOCX paragraph drop.** Wrapping a `\tofill{X}` line in raw LaTeX like `\noindent \textit{\small ...}` made pandoc drop the entire paragraph from DOCX output, including the `\tofill` inside. The built-in `\providecommand` + lua-filter mechanism removes the need for any wrapper at all — placeholders survive every format.
50
- - **Filter path resolution on Windows paths with spaces.** `lib/build.ts` resolved `pptx-color-filter.lua` via `new URL(import.meta.url).pathname`, which returns URL-encoded `%20` for spaces, so `fs.existsSync` silently returned false on paths like `C:\Users\Gilles Colling\...`. Switched both pptx and macro filter resolution to `fileURLToPath`. PPTX color highlighting now actually works under default installs on user-named directories.
51
- - **Lua filter not shipped to runtime.** `scripts/postbuild.js` left `.lua` files in `lib/` only; the compiled `dist/lib/build.js` looked for them next to itself. PPTX colour filter (and now the macro filter) are now copied to `dist/lib/` during build.
52
-
53
- ### Notes for `\tofill` migration
54
- Projects that ship their own `tofill_filter.lua` and `\providecommand{\tofill}{...}` in a custom header keep working docrev's preamble uses `\providecommand`, so user `\renewcommand` (or pre-existing `\providecommand`) takes priority. To migrate, delete the local lua filter and any markdown wrappers like `\noindent \textit{\small ...}`; docrev's built-in covers all three formats. Override the color or style by adding the macro under `macros:` in `rev.yaml`.
55
-
56
- ## [0.9.11] - 2026-04-30
57
-
58
- ### Fixed
59
- - **Single-section comment placement.** `computeSectionBoundaries` left the last section's `end` at `Number.MAX_SAFE_INTEGER`, which collapsed the proportional-position math in `insertCommentsIntoMarkdown` to ~0. Every comment whose anchor wasn't in the first 200 chars of the markdown stacked at position 0. Now caps the last boundary's `end` at `fullDocText.length`, passed in from sync and verify-anchors.
60
- - **Re-sync duplicated comments.** `sync --comments-only` re-inserted every comment on each invocation, producing `{>>R1<<}{>>R1<<}{>>R1<<}…` over time. `insertCommentsIntoMarkdown` now scans ±200 chars around the target for an identical `{>>author: text<<}` block and skips insertion when found.
61
- - **Threading content destruction.** `prepareMarkdownWithMarkers`'s whitespace-consumption loops captured `charBefore` once outside the loop, so a single leading space caused `removeStart` to walk to position 0 and `slice()` to delete every preceding paragraph. Replaced with a one-char check.
62
- - **Multi-run anchor injection.** Pandoc splits a single anchor across multiple `<w:r>` blocks whenever it applies styling mid-anchor — smart-quote substitution, `*italic*`, `` `code` ``, `**bold**` all trigger this. The single-run scan in `injectCommentsAtMarkers` grabbed the start marker's `<w:t>`, looked for the end marker inside it, found nothing, and silently skipped the comment. New multi-run path splits the start run at the start marker, keeps middle runs verbatim, splits the end run at the end marker, and rebuilds with `commentRangeStart`/`commentRangeEnd` around the styled anchor portions.
63
- - **Nested-bracket anchors.** `prepareMarkdownWithMarkers` used `\[([^\]]+)\]\{\.mark\}` for the trailing anchor group, so any inner `]` (e.g. `[[0..9]]{.mark}`, `[*italic*]{.mark}`) terminated the match prematurely. Replaced with a manual balanced-bracket walker that handles arbitrary nesting depth and verifies a `{.mark}` suffix.
64
- - **Orphan-`[` over-stripping.** `stripAnnotations`'s orphan cleanup used `\[(?![^\[\]]*\])`, treating any inner `[` as a barrier and stripping the outer `[` of nested forms. Loosened to `\[(?![^\]\n]*\])`: an `[` is orphan only when no `]` follows before end of line.
65
-
66
- ### Changed
67
- - `sync --comments-only` summary distinguishes `placed` / `already present` / `unmatched` instead of subtracting before/after counts. Re-syncs now report "6 already present (skipped to avoid duplication)" instead of misreporting them as fully placed or fully unmatched. New `outStats` channel from `insertCommentsIntoMarkdown`.
68
-
69
- ## [0.9.10] - 2026-04-30
70
-
71
- ### Fixed
72
- - `stripAnnotations` stripped `[anchor]{.mark}` spans even when `keepComments=true`, leaving the dual-build marker generator with no anchor text and collapsing every multi-word anchor to a single fallback word in the rebuilt docx. Now preserves anchor spans that belong to retained `{>>...<<}` comments.
73
- - Comments authored at the very start of a Word section landed before the markdown file's `# Heading` line and rendered in the previous section. Added `pushPastSectionHeading` so position-0 comments advance to the first body paragraph of the section they were authored in.
74
- - Empty-anchor comments fell through to proportional placement even when before/after context uniquely identified the position, landing mid-word or splitting unrelated phrases. Context match now runs first; proportional placement is the fallback.
75
- - When an anchor appeared multiple times in the search window (repeated phrasing, formulaic prose), `insertCommentsIntoMarkdown` always picked the first occurrence. Now picks the occurrence closest to the docx-derived insert position.
76
-
77
- ## [0.9.7] - 2026-04-29
78
-
79
- ### Added
80
- - `rev sync --comments-only` — import only Word comments at fuzzy-matched anchors, leaving prose byte-identical. Use when the markdown was revised between sending the docx out for review and receiving it back; applying track changes from a stale draft would clobber newer edits.
81
- - `rev verify-anchors <docx>` — drift report classifying every comment as `clean` / `drift` / `context-only` / `ambiguous` / `unmatched` against the current section markdown. Pair with `--comments-only` to plan placement before sync. Supports `--json` for scripting.
82
- - `extractHeadings()` in `word-extraction.ts` read heading paragraphs directly from `<w:pStyle>` styles, returning text + level + position in the same coordinate system as comment anchors.
83
- - Shared `lib/commands/section-boundaries.ts` single source of truth that maps `sections.yaml` to docx text positions, used by both sync and verify-anchors.
84
- - Shared `lib/anchor-match.ts` pure anchor-matching primitives (`findAnchorInText`, `stripCriticMarkup`, `classifyStrategy`) so sync (insertion) and verify-anchors (drift reporting) use the same fallback strategies.
85
- - New tests: `test/anchor-match.test.js` (11 cases covering each fallback strategy and the quality classifier).
86
-
87
- ### Fixed
88
- - **Section detection mistook prose for headings.** The old keyword finder scanned the concatenated body text and would match "results across countries" as the Results heading or skip the real Methods heading because the structured-abstract label `Methods:` lost its colon during text-run concatenation. Replaced with paragraph-style-based heading extraction, so boundaries now reflect actual heading paragraphs. Affects the new commands; the existing sync flow already used pandoc-derived headings and was unaffected.
89
- - `stripCriticMarkup` regex used `[^<]*` and silently failed on comments containing `<` characters (e.g. `pre-industrial trade (<1825)`). Switched to non-greedy `[\s\S]*?`.
90
- - `insertCommentsIntoMarkdown` always prepended a leading space when there was no anchor, accumulating multiple spaces when several comments shared a position 0 anchor. Removed the heuristic; comments insert at exact position so prose stays byte-identical except for the inserted blocks.
91
- - `verify-anchors` crashed with a stack trace when given a non-docx file (e.g. an `.md` path). Now reports a friendly error.
92
-
93
- ### Changed
94
- - New flag is `--comments-only` (positive form). The originally proposed `--no-overwrite` was dropped because Commander assigns `--no-X` to `options.x === false` rather than `options.noX === true`, which made the flag silently ignored.
95
- - `insertCommentsIntoMarkdown` now accepts `wrapAnchor?: boolean` (default `true`). When `false`, comment blocks are inserted next to the anchor without `[anchor]{.mark}` wrapping. `--comments-only` uses this so multiple comments sharing an anchor (e.g. 6 reviewers commenting on the same word) no longer produce nested broken CriticMarkup.
96
-
97
- ## [0.7.1] - 2025-01-02
98
-
99
- ### Added
100
- - Writing Markdown guide in docs (tables, equations, citations, cross-refs)
101
- - Grid table syntax documentation for merged cells
102
-
103
- ### Changed
104
- - README restructured for better scannability (490 290 lines)
105
- - Install section moved up for faster onboarding
106
- - Added Highlights section with quick feature overview
107
- - Condensed overlapping sections
108
-
109
- ## [0.7.0] - 2025-01-02
110
-
111
- ### Added
112
- - API rate limiting with exponential backoff for Crossref/DataCite/doi.org APIs
113
- - Windows support in CI matrix
114
- - Architecture documentation for contributors (`ARCHITECTURE.md`)
115
- - Exclusion patterns for cross-reference false positives (e.g., "Table of Contents")
116
- - Timeout support for PDF extraction (30s default)
117
-
118
- ### Changed
119
- - Consolidated YAML dependencies (removed `js-yaml`, using `yaml` package only)
120
- - Improved annotation false positive detection (code blocks, URLs, LaTeX patterns)
121
- - Enhanced error messages for Word import and PDF extraction
122
- - Updated User-Agent strings for API requests
123
- - Improved README with problem statement and quick example
124
-
125
- ### Fixed
126
- - CI lint step now checks all command files separately
127
- - Windows temp directory paths in tests
128
-
129
- ## [0.3.2] - 2024-12-29
130
-
131
- ### Added
132
- - Full TypeScript type definitions (`types/index.d.ts`)
133
- - GitHub Actions CI workflow (Node 18/20/22)
134
- - ESM subpath exports for all library modules
135
- - CLI integration tests (26 tests)
136
- - Comprehensive test coverage: 419 tests across 18 modules
137
-
138
- ### Fixed
139
- - DOI skip detection: `% no-doi` comments now correctly apply only to the next entry
140
-
141
- ### Changed
142
- - Added `engines` field requiring Node.js >=18.0.0
143
- - Updated README with badges (npm, CI, Node.js, License)
144
-
145
- ## [0.3.1] - 2024-12-28
146
-
147
- ### Fixed
148
- - Equation extraction test assertions
149
- - Minor bug fixes
150
-
151
- ## [0.3.0] - 2024-12-27
152
-
153
- ### Added
154
- - DOI validation via Crossref and DataCite APIs (`rev doi check`)
155
- - DOI lookup for missing entries (`rev doi lookup`)
156
- - DOI fetch and add commands (`rev doi fetch`, `rev doi add`)
157
- - Citation validation against bibliography (`rev citations`)
158
- - LaTeX equation extraction (`rev equations list`)
159
- - Word equation import OMML → LaTeX (`rev equations from-word`)
160
- - Response letter generation (`rev response`)
161
- - Journal validation profiles (`rev validate --journal`)
162
- - Advanced figure/table reference patterns (Figs. 1-3, Fig. 1a-c)
163
-
164
- ### Changed
165
- - Improved cross-reference pattern detection
166
- - Enhanced Word import with better section splitting
167
-
168
- ## [0.2.1] - 2024-12-26
169
-
170
- ### Added
171
- - Table of contents option (`rev build --toc`)
172
- - CSV export for comments (`rev comments --export`)
173
- - Anonymize command for blind review (`rev anonymize`)
174
- - Formatting utilities (tables, boxes, spinners)
175
-
176
- ## [0.2.0] - 2024-12-25
177
-
178
- ### Added
179
- - Integrated build system (`rev build pdf/docx/tex`)
180
- - Comment reply functionality (`rev reply`)
181
- - Word document bootstrap (`rev import` creates project from .docx)
182
- - Section-aware import (`rev sections`)
183
- - Cross-reference migration (`rev migrate`)
184
-
185
- ### Changed
186
- - Renamed project to docrev
187
- - Published to npm
188
-
189
- ## [0.1.0] - 2024-12-24
190
-
191
- ### Added
192
- - Initial release
193
- - CriticMarkup annotation parsing
194
- - Word ↔ Markdown round-trips
195
- - Interactive review TUI (`rev review`)
196
- - Comment management (`rev comments`, `rev resolve`)
197
- - Project templates (`rev new`)
1
+ # Changelog
2
+
3
+ All notable changes to docrev will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.11.3] - 2026-07-08
9
+
10
+ ### Fixed
11
+ - **`rev status` / `rev comments` (and the whole `[file]`-taking class) now read `.docx` files correctly instead of reporting silent garbage (#8).** These commands used to `readFileSync(file, 'utf-8')` every argument and regex the bytes for CriticMarkup. A `.docx` is a binary ZIP, so a Word document full of tracked changes and comments came back as "No annotations found" / "No comments found" — or an unstable, plausible-looking wrong count from an accidental byte-match in the DEFLATE stream, with no error. A new front door (`lib/input.ts`) detects a Word document by extension **and** by ZIP magic + `word/document.xml` (catching a mis-extensioned `.docx`), and routes it through the existing OOXML/pandoc reader so `rev status` / `rev comments` / `rev todo` / `rev next` / `rev first` / `rev reply-doc` / `rev response` / `rev strip` report the real insertions, deletions, substitutions, and comments the same numbers a subsequent `rev import` produces. In-place editors (`rev review` / `accept` / `reject` / `resolve` / `reply` / interactive `comments`) refuse a `.docx` with a pointer to `rev import` rather than corrupting it. As a backstop, the annotation parsers (`parseAnnotations` / `countAnnotations` / `getComments` / `stripAnnotations` / `hasAnnotations`) now reject binary input loudly, so the whole class can never silently regress.
12
+
13
+ ## [0.11.2] - 2026-07-06
14
+
15
+ ### Fixed
16
+ - **`pdf.header` / `pdf.footer` are now injected into the PDF build (#7).** The schema documented `pdf.header` / `pdf.footer`, but the build never read them, so any user-supplied LaTeX preamble (custom fonts, `fancyhdr` running headers, `lineno` line numbers) was silently dropped from `rev build pdf` — no error, no warning. `runPandoc` now resolves `pdf.header` / `pdf.footer` (file paths relative to the project root) and passes them to pandoc with `-H`, the same channel the macros preamble and annotated-comments path use. A file named but not found is reported as a warning instead of dropped. An inline `header-includes:` block (pandoc's native key, at the top level or under `pdf:`) is also honored by writing it to a temp `.tex`. The preamble applies to `pdf`, `tex`, and `beamer` builds and to the annotated `_comments.pdf`.
17
+
18
+ ## [0.11.1] - 2026-07-05
19
+
20
+ ### Added
21
+ - **`rev build docx --dual --show-changes` emits tracked changes and threaded comments in one file (#6).** The standard "return to senior author" artifact — my `{++..++}`/`{--..--}` edits as Word tracked changes alongside the reviewer's `{>>..<<}` comments with my threaded replies — now builds as a single `<title>-changes.docx`. Previously the two were mutually exclusive: `--show-changes` dropped comments, `--dual` accepted all changes. A new `buildReviewedDocx` runs one pandoc pass through the full filter chain, then threads comments into the same file. Add `--reference <docx>` to realign comment anchors first.
22
+
23
+ ### Changed
24
+ - **Track changes now use pandoc-native `w:ins`/`w:del` revisions.** `--show-changes` (and `rev apply`) previously injected revision XML by string-replacing text markers, which nested `<w:ins>`/`<w:del>` inside `<w:t>` (malformed OOXML) and bypassed crossref/citeproc/the reference-doc. CriticMarkup is now converted to pandoc `.insertion`/`.deletion` spans and emitted as well-formed run-level revisions through the full filter chain.
25
+
26
+ ## [0.11.0] - 2026-07-05
27
+
28
+ ### Changed
29
+ - **Parser-backed OOXML layer, unified placement engine, boundary hardening.** One structural OOXML tokenizer (`lib/ooxml.ts`) now backs every Word reader and the comment injector, collapsing the divergent `extractCommentAnchors`/`extractWordComments` paths onto a single namespace-aware engine (matches WordprocessingML by URI, decodes entities, excludes `instrText` field codes, enumerates footnote/endnote parts, finds runs structurally). Section comment placement is offset-first, with proportional estimates demoted to a flagged last resort surfaced by `sync`. Rate-limiter gains a per-request timeout and HTTP-date `Retry-After` parsing; `checkDoi` reports unreachable distinctly from invalid; PPTX post-processing failures warn instead of being swallowed.
30
+
31
+ ## [0.10.2] - 2026-06-22
32
+
33
+ ### Fixed
34
+ - **`rev init` now derives subsection headers too (#5 Bug B).** 0.10.1 fixed first-heading-at-any-level only for the `rev.yaml`-derived path; `generateConfig` (the `rev init` -> `sections.yaml` path) still used H1-only extraction, so a project initialised with `rev init` left a `## 1.2 Objectives` file headed `Sec2` and folded its content into the preceding section on sync. `generateConfig` and `splitAnnotatedPaper` now use the first heading at any level.
35
+ - **Comments routed to non-keyword sections are no longer silently dropped (#5 Bug C).** The main `sync` flow routed comments with a hardcoded keyword list (abstract/intro/methods/results/discussion/conclusion); sections named e.g. `Objectives` or `Annex 2` got no boundary and their comments were discarded while the summary still reported every comment as placed. Comment routing now uses the same heading-based `computeSectionBoundaries` as `sync --comments-only`.
36
+ - **Sections absent (as prose) from the reviewed document are left untouched (#5 Bug C).** A section that appears only as a bare heading with no body e.g. when a "no-annex" export is synced against the full project was diffed against empty content and rewritten to near-empty. Such sections are now reported as `untouched` and left on disk unchanged.
37
+
38
+ ### Changed
39
+ - **Truthful sync summary (#5 Bug C).** The summary now reports `N of M comments placed`, plus `already present`, `unmatched`, and `not routed to any synced section` counts (from `insertCommentsIntoMarkdown`'s `outStats`), instead of asserting that the raw extracted count was placed.
40
+ - The main `sync` flow and `sync --comments-only` now share one comment-routing path, removing the divergent keyword-search boundary logic.
41
+
42
+ ## [0.10.1] - 2026-06-05
43
+
44
+ ### Fixed
45
+ - **`sync`/`verify-anchors`/`split` no longer require a separate `sections.yaml`.** `build` and `status` read the `sections:` list from `rev.yaml`, but the sync-side commands demanded a `sections.yaml` and aborted with `Config not found` on a perfectly valid `rev.yaml`-only project. They now resolve the section config from a single source of truth: an explicit `sections.yaml` is used when present (to override headers/aliases/order), otherwise the config is derived from `rev.yaml`'s `sections:` list. Running `rev init` first is no longer necessary.
46
+ - **Derived section headers honor the file's first heading at any level.** A section file that leads with a subsection (e.g. `02_objectives.md` starting with `## 1.2 Objectives`) now derives the header `1.2 Objectives` (via the new `extractFirstHeading`), so it matches the corresponding docx heading and routes to its own file instead of being folded into the preceding section. `extractHeader` keeps its H1-only contract for existing callers.
47
+
48
+ ### Added
49
+ - `resolveSectionsConfig(dir, configFile?)` and `deriveSectionsFromRev(dir)` in `lib/sections.ts`, with tests.
50
+
51
+ ## [0.10.0] - 2026-05-20
52
+
53
+ ### Added
54
+ - **Placeholder macros.** Built-in `\tofill{X}` renders as bold orange `[X]` across DOCX, PDF/TeX/Beamer, and HTML drop the LaTeX-style command anywhere in a section file and the build expands it per format. No more copying a `tofill_filter.lua` + `\providecommand` boilerplate into each project. Users can add their own one-argument macros under `macros:` in `rev.yaml` (color, bold/italic, bracket wrap, prefix/suffix, per-format overrides). See `docs/configuration.md` for the schema.
55
+ - **`lib/macros.ts` + `lib/macro-filter.lua`** — registry-style implementation. Built-ins and user macros merge by name; user entries override built-ins. The lua filter loads its macro list from a JSON sidecar via the `DOCREV_MACROS_FILE` env var.
56
+
57
+ ### Fixed
58
+ - **Silent DOCX color drop.** Pandoc 3.x's docx writer does NOT honor `Span` with `style="color: #..."`, so a lua filter returning `pandoc.Span(pandoc.Strong(...), pandoc.Attr("", {}, {style="color: #C2410C"}))` produced zero `<w:color>` runs and the highlight vanished. The new filter emits raw OpenXML `<w:r>` nodes directly (the same pattern as the existing `pptx-color-filter.lua`), which produces real colored runs in Word.
59
+ - **Silent DOCX paragraph drop.** Wrapping a `\tofill{X}` line in raw LaTeX like `\noindent \textit{\small ...}` made pandoc drop the entire paragraph from DOCX output, including the `\tofill` inside. The built-in `\providecommand` + lua-filter mechanism removes the need for any wrapper at all placeholders survive every format.
60
+ - **Filter path resolution on Windows paths with spaces.** `lib/build.ts` resolved `pptx-color-filter.lua` via `new URL(import.meta.url).pathname`, which returns URL-encoded `%20` for spaces, so `fs.existsSync` silently returned false on paths like `C:\Users\Gilles Colling\...`. Switched both pptx and macro filter resolution to `fileURLToPath`. PPTX color highlighting now actually works under default installs on user-named directories.
61
+ - **Lua filter not shipped to runtime.** `scripts/postbuild.js` left `.lua` files in `lib/` only; the compiled `dist/lib/build.js` looked for them next to itself. PPTX colour filter (and now the macro filter) are now copied to `dist/lib/` during build.
62
+
63
+ ### Notes for `\tofill` migration
64
+ Projects that ship their own `tofill_filter.lua` and `\providecommand{\tofill}{...}` in a custom header keep working — docrev's preamble uses `\providecommand`, so user `\renewcommand` (or pre-existing `\providecommand`) takes priority. To migrate, delete the local lua filter and any markdown wrappers like `\noindent \textit{\small ...}`; docrev's built-in covers all three formats. Override the color or style by adding the macro under `macros:` in `rev.yaml`.
65
+
66
+ ## [0.9.11] - 2026-04-30
67
+
68
+ ### Fixed
69
+ - **Single-section comment placement.** `computeSectionBoundaries` left the last section's `end` at `Number.MAX_SAFE_INTEGER`, which collapsed the proportional-position math in `insertCommentsIntoMarkdown` to ~0. Every comment whose anchor wasn't in the first 200 chars of the markdown stacked at position 0. Now caps the last boundary's `end` at `fullDocText.length`, passed in from sync and verify-anchors.
70
+ - **Re-sync duplicated comments.** `sync --comments-only` re-inserted every comment on each invocation, producing `{>>R1<<}{>>R1<<}{>>R1<<}…` over time. `insertCommentsIntoMarkdown` now scans ±200 chars around the target for an identical `{>>author: text<<}` block and skips insertion when found.
71
+ - **Threading content destruction.** `prepareMarkdownWithMarkers`'s whitespace-consumption loops captured `charBefore` once outside the loop, so a single leading space caused `removeStart` to walk to position 0 and `slice()` to delete every preceding paragraph. Replaced with a one-char check.
72
+ - **Multi-run anchor injection.** Pandoc splits a single anchor across multiple `<w:r>` blocks whenever it applies styling mid-anchor — smart-quote substitution, `*italic*`, `` `code` ``, `**bold**` all trigger this. The single-run scan in `injectCommentsAtMarkers` grabbed the start marker's `<w:t>`, looked for the end marker inside it, found nothing, and silently skipped the comment. New multi-run path splits the start run at the start marker, keeps middle runs verbatim, splits the end run at the end marker, and rebuilds with `commentRangeStart`/`commentRangeEnd` around the styled anchor portions.
73
+ - **Nested-bracket anchors.** `prepareMarkdownWithMarkers` used `\[([^\]]+)\]\{\.mark\}` for the trailing anchor group, so any inner `]` (e.g. `[[0..9]]{.mark}`, `[*italic*]{.mark}`) terminated the match prematurely. Replaced with a manual balanced-bracket walker that handles arbitrary nesting depth and verifies a `{.mark}` suffix.
74
+ - **Orphan-`[` over-stripping.** `stripAnnotations`'s orphan cleanup used `\[(?![^\[\]]*\])`, treating any inner `[` as a barrier and stripping the outer `[` of nested forms. Loosened to `\[(?![^\]\n]*\])`: an `[` is orphan only when no `]` follows before end of line.
75
+
76
+ ### Changed
77
+ - `sync --comments-only` summary distinguishes `placed` / `already present` / `unmatched` instead of subtracting before/after counts. Re-syncs now report "6 already present (skipped to avoid duplication)" instead of misreporting them as fully placed or fully unmatched. New `outStats` channel from `insertCommentsIntoMarkdown`.
78
+
79
+ ## [0.9.10] - 2026-04-30
80
+
81
+ ### Fixed
82
+ - `stripAnnotations` stripped `[anchor]{.mark}` spans even when `keepComments=true`, leaving the dual-build marker generator with no anchor text and collapsing every multi-word anchor to a single fallback word in the rebuilt docx. Now preserves anchor spans that belong to retained `{>>...<<}` comments.
83
+ - Comments authored at the very start of a Word section landed before the markdown file's `# Heading` line and rendered in the previous section. Added `pushPastSectionHeading` so position-0 comments advance to the first body paragraph of the section they were authored in.
84
+ - Empty-anchor comments fell through to proportional placement even when before/after context uniquely identified the position, landing mid-word or splitting unrelated phrases. Context match now runs first; proportional placement is the fallback.
85
+ - When an anchor appeared multiple times in the search window (repeated phrasing, formulaic prose), `insertCommentsIntoMarkdown` always picked the first occurrence. Now picks the occurrence closest to the docx-derived insert position.
86
+
87
+ ## [0.9.7] - 2026-04-29
88
+
89
+ ### Added
90
+ - `rev sync --comments-only` import only Word comments at fuzzy-matched anchors, leaving prose byte-identical. Use when the markdown was revised between sending the docx out for review and receiving it back; applying track changes from a stale draft would clobber newer edits.
91
+ - `rev verify-anchors <docx>` drift report classifying every comment as `clean` / `drift` / `context-only` / `ambiguous` / `unmatched` against the current section markdown. Pair with `--comments-only` to plan placement before sync. Supports `--json` for scripting.
92
+ - `extractHeadings()` in `word-extraction.ts` — read heading paragraphs directly from `<w:pStyle>` styles, returning text + level + position in the same coordinate system as comment anchors.
93
+ - Shared `lib/commands/section-boundaries.ts` — single source of truth that maps `sections.yaml` to docx text positions, used by both sync and verify-anchors.
94
+ - Shared `lib/anchor-match.ts` pure anchor-matching primitives (`findAnchorInText`, `stripCriticMarkup`, `classifyStrategy`) so sync (insertion) and verify-anchors (drift reporting) use the same fallback strategies.
95
+ - New tests: `test/anchor-match.test.js` (11 cases covering each fallback strategy and the quality classifier).
96
+
97
+ ### Fixed
98
+ - **Section detection mistook prose for headings.** The old keyword finder scanned the concatenated body text and would match "results across countries" as the Results heading or skip the real Methods heading because the structured-abstract label `Methods:` lost its colon during text-run concatenation. Replaced with paragraph-style-based heading extraction, so boundaries now reflect actual heading paragraphs. Affects the new commands; the existing sync flow already used pandoc-derived headings and was unaffected.
99
+ - `stripCriticMarkup` regex used `[^<]*` and silently failed on comments containing `<` characters (e.g. `pre-industrial trade (<1825)`). Switched to non-greedy `[\s\S]*?`.
100
+ - `insertCommentsIntoMarkdown` always prepended a leading space when there was no anchor, accumulating multiple spaces when several comments shared a position 0 anchor. Removed the heuristic; comments insert at exact position so prose stays byte-identical except for the inserted blocks.
101
+ - `verify-anchors` crashed with a stack trace when given a non-docx file (e.g. an `.md` path). Now reports a friendly error.
102
+
103
+ ### Changed
104
+ - New flag is `--comments-only` (positive form). The originally proposed `--no-overwrite` was dropped because Commander assigns `--no-X` to `options.x === false` rather than `options.noX === true`, which made the flag silently ignored.
105
+ - `insertCommentsIntoMarkdown` now accepts `wrapAnchor?: boolean` (default `true`). When `false`, comment blocks are inserted next to the anchor without `[anchor]{.mark}` wrapping. `--comments-only` uses this so multiple comments sharing an anchor (e.g. 6 reviewers commenting on the same word) no longer produce nested broken CriticMarkup.
106
+
107
+ ## [0.7.1] - 2025-01-02
108
+
109
+ ### Added
110
+ - Writing Markdown guide in docs (tables, equations, citations, cross-refs)
111
+ - Grid table syntax documentation for merged cells
112
+
113
+ ### Changed
114
+ - README restructured for better scannability (490 → 290 lines)
115
+ - Install section moved up for faster onboarding
116
+ - Added Highlights section with quick feature overview
117
+ - Condensed overlapping sections
118
+
119
+ ## [0.7.0] - 2025-01-02
120
+
121
+ ### Added
122
+ - API rate limiting with exponential backoff for Crossref/DataCite/doi.org APIs
123
+ - Windows support in CI matrix
124
+ - Architecture documentation for contributors (`ARCHITECTURE.md`)
125
+ - Exclusion patterns for cross-reference false positives (e.g., "Table of Contents")
126
+ - Timeout support for PDF extraction (30s default)
127
+
128
+ ### Changed
129
+ - Consolidated YAML dependencies (removed `js-yaml`, using `yaml` package only)
130
+ - Improved annotation false positive detection (code blocks, URLs, LaTeX patterns)
131
+ - Enhanced error messages for Word import and PDF extraction
132
+ - Updated User-Agent strings for API requests
133
+ - Improved README with problem statement and quick example
134
+
135
+ ### Fixed
136
+ - CI lint step now checks all command files separately
137
+ - Windows temp directory paths in tests
138
+
139
+ ## [0.3.2] - 2024-12-29
140
+
141
+ ### Added
142
+ - Full TypeScript type definitions (`types/index.d.ts`)
143
+ - GitHub Actions CI workflow (Node 18/20/22)
144
+ - ESM subpath exports for all library modules
145
+ - CLI integration tests (26 tests)
146
+ - Comprehensive test coverage: 419 tests across 18 modules
147
+
148
+ ### Fixed
149
+ - DOI skip detection: `% no-doi` comments now correctly apply only to the next entry
150
+
151
+ ### Changed
152
+ - Added `engines` field requiring Node.js >=18.0.0
153
+ - Updated README with badges (npm, CI, Node.js, License)
154
+
155
+ ## [0.3.1] - 2024-12-28
156
+
157
+ ### Fixed
158
+ - Equation extraction test assertions
159
+ - Minor bug fixes
160
+
161
+ ## [0.3.0] - 2024-12-27
162
+
163
+ ### Added
164
+ - DOI validation via Crossref and DataCite APIs (`rev doi check`)
165
+ - DOI lookup for missing entries (`rev doi lookup`)
166
+ - DOI fetch and add commands (`rev doi fetch`, `rev doi add`)
167
+ - Citation validation against bibliography (`rev citations`)
168
+ - LaTeX equation extraction (`rev equations list`)
169
+ - Word equation import OMML → LaTeX (`rev equations from-word`)
170
+ - Response letter generation (`rev response`)
171
+ - Journal validation profiles (`rev validate --journal`)
172
+ - Advanced figure/table reference patterns (Figs. 1-3, Fig. 1a-c)
173
+
174
+ ### Changed
175
+ - Improved cross-reference pattern detection
176
+ - Enhanced Word import with better section splitting
177
+
178
+ ## [0.2.1] - 2024-12-26
179
+
180
+ ### Added
181
+ - Table of contents option (`rev build --toc`)
182
+ - CSV export for comments (`rev comments --export`)
183
+ - Anonymize command for blind review (`rev anonymize`)
184
+ - Formatting utilities (tables, boxes, spinners)
185
+
186
+ ## [0.2.0] - 2024-12-25
187
+
188
+ ### Added
189
+ - Integrated build system (`rev build pdf/docx/tex`)
190
+ - Comment reply functionality (`rev reply`)
191
+ - Word document bootstrap (`rev import` creates project from .docx)
192
+ - Section-aware import (`rev sections`)
193
+ - Cross-reference migration (`rev migrate`)
194
+
195
+ ### Changed
196
+ - Renamed project to docrev
197
+ - Published to npm
198
+
199
+ ## [0.1.0] - 2024-12-24
200
+
201
+ ### Added
202
+ - Initial release
203
+ - CriticMarkup annotation parsing
204
+ - Word ↔ Markdown round-trips
205
+ - Interactive review TUI (`rev review`)
206
+ - Comment management (`rev comments`, `rev resolve`)
207
+ - Project templates (`rev new`)