@ansonlai/docx-redline-js 0.4.0 → 0.5.1

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 (104) hide show
  1. package/AGENTS.md +646 -288
  2. package/ARCHITECTURE.md +215 -9
  3. package/CHANGELOG.md +319 -0
  4. package/README.md +604 -360
  5. package/adapters/config.js +45 -43
  6. package/bin/docx-redline.js +3 -0
  7. package/core/list-targeting.js +101 -110
  8. package/core/paragraph-targeting.js +501 -61
  9. package/core/paragraph-text.js +209 -0
  10. package/core/redline-validation.js +11 -5
  11. package/core/revision-cloning.js +38 -0
  12. package/core/types.js +64 -10
  13. package/core/word-xml.js +43 -15
  14. package/dist/docx-redline-js.esm.js +3145 -505
  15. package/dist/docx-redline-js.esm.js.map +4 -4
  16. package/dist/docx-redline-js.esm.min.js +88 -76
  17. package/dist/docx-redline-js.esm.min.js.map +4 -4
  18. package/docs/TESTING.md +342 -23
  19. package/docs/plans/2026-09-05-structural-revisions-and-fidelity-oracles.md +1669 -0
  20. package/docs/plans/2026-09-08-cross-author-revision-slicing.md +505 -0
  21. package/docs/plans/completed/2026-09-01-performance-and-complexity-reduction.md +669 -0
  22. package/docs/plans/completed/2026-09-03-agent-friendly-document-workflows.md +427 -0
  23. package/docs/plans/completed/2026-09-04-comment-anchor-and-cli-reliability.md +519 -0
  24. package/docs/plans/completed/PERFORMANCE-CONSOLIDATION.md +69 -0
  25. package/docs/plans/completed/structural-revision-capability-matrix.md +115 -0
  26. package/docs/schemas/document-operations.schema.json +109 -0
  27. package/docs/test-comparison-dashboard.html +4250 -7
  28. package/engine/formatting-removal.js +11 -2
  29. package/engine/oxml-engine.js +508 -336
  30. package/engine/reconstruction-mode.js +15 -14
  31. package/engine/reconstruction-writer.js +247 -142
  32. package/engine/route-selection.js +35 -0
  33. package/engine/rpr-helpers.js +334 -35
  34. package/engine/run-builders.js +239 -196
  35. package/engine/surgical-diff-application.js +407 -50
  36. package/engine/surgical-mode.js +142 -6
  37. package/engine/surgical-run-splitting.js +103 -0
  38. package/engine/surgical-spans.js +52 -1
  39. package/engine/table-cell-context.js +3 -6
  40. package/engine/table-mode.js +1 -1
  41. package/index.d.ts +234 -6
  42. package/index.js +24 -1
  43. package/node/cli.js +322 -0
  44. package/node/docx-document.js +302 -0
  45. package/node/index.d.ts +31 -0
  46. package/node/index.js +2 -0
  47. package/node/zip-archive.js +52 -0
  48. package/orchestration/list-markdown.js +10 -16
  49. package/orchestration/list-parsing.js +7 -12
  50. package/orchestration/list-structural-fallback.js +21 -10
  51. package/package.json +123 -102
  52. package/pipeline/content-analysis.js +12 -17
  53. package/pipeline/ingestion-export.js +3 -31
  54. package/pipeline/ingestion-paragraph.js +10 -5
  55. package/pipeline/list-generation.js +150 -55
  56. package/pipeline/list-markers.js +70 -3
  57. package/pipeline/serialization.js +4 -2
  58. package/pipeline/structured-content.js +160 -0
  59. package/scripts/apply_changes.mjs +27 -0
  60. package/scripts/benchmark-operation-session.mjs +137 -0
  61. package/scripts/benchmark-targeting-browser.html +74 -0
  62. package/scripts/benchmark-targeting-hot-paths.mjs +67 -0
  63. package/scripts/benchmark-test-runner.mjs +59 -0
  64. package/scripts/build-test-dashboard.mjs +23 -0
  65. package/scripts/export-lane1-fixtures.mjs +380 -0
  66. package/scripts/export-reredline-stress-fixtures.mjs +317 -0
  67. package/scripts/export-validation-fixtures.mjs +1 -1
  68. package/scripts/extract_text.mjs +7 -0
  69. package/scripts/generate-cross-author-slicing-fixtures.ps1 +256 -0
  70. package/scripts/generate-paragraph-boundary-fixtures.ps1 +215 -0
  71. package/scripts/generate-test-dashboard.mjs +362 -11
  72. package/scripts/lib/word-coverage-catalogue.mjs +6 -2
  73. package/scripts/profile-route-selection.mjs +19 -0
  74. package/scripts/render-agenda-multilevel.mjs +0 -5
  75. package/scripts/render-multilevel-cases.mjs +0 -1
  76. package/scripts/run-tests.mjs +107 -35
  77. package/scripts/word-com-corpus-suite.ps1 +3 -0
  78. package/scripts/word-com-differential.ps1 +64 -4
  79. package/scripts/word-com-suite.ps1 +3 -0
  80. package/services/batch-operation-orchestrator.js +513 -0
  81. package/services/capture-engine.js +226 -0
  82. package/services/comment-builders.js +23 -6
  83. package/services/comment-engine.js +108 -47
  84. package/services/comment-locator.js +187 -82
  85. package/services/comment-replies.js +95 -0
  86. package/services/document-inspection.js +258 -0
  87. package/services/document-operation-applier.js +372 -0
  88. package/services/document-operation-contract.js +345 -0
  89. package/services/document-operation-mutations.js +1749 -0
  90. package/services/document-operation-session.js +258 -0
  91. package/services/numbering-service.js +14 -5
  92. package/services/operation-heuristics.js +173 -0
  93. package/services/operation-preflight.js +390 -0
  94. package/services/receipt-collector.js +288 -0
  95. package/services/revision-comment-management.js +77 -5
  96. package/services/revision-token.js +290 -0
  97. package/services/standalone-docx-plumbing.js +123 -8
  98. package/services/standalone-operation-runner.d.ts +296 -0
  99. package/services/standalone-operation-runner.js +10 -1455
  100. package/services/table-reconciliation.js +15 -6
  101. package/docs/VALIDATION.md +0 -183
  102. package/docs/WORD-MANUAL-REVIEW.md +0 -138
  103. package/docs/plans/2026-09-01-performance-and-complexity-reduction.md +0 -210
  104. /package/docs/plans/{2026-08-30-reliability-testing-improvements.md → completed/2026-08-30-reliability-testing-improvements.md} +0 -0
@@ -0,0 +1,215 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
3
+
4
+ $fixturesDir = "C:\Users\Phara\Desktop\Projects\Docx Redline JS\tests\fixtures\paragraph-boundaries"
5
+ if (-not (Test-Path $fixturesDir)) {
6
+ New-Item -ItemType Directory -Path $fixturesDir -Force | Out-Null
7
+ }
8
+
9
+ function Extract-DocumentXml($docxPath, $xmlPath) {
10
+ $zip = [System.IO.Compression.ZipFile]::OpenRead($docxPath)
11
+ try {
12
+ $entry = $zip.GetEntry("word/document.xml")
13
+ if ($entry) {
14
+ $reader = New-Object System.IO.StreamReader($entry.Open(), [System.Text.Encoding]::UTF8)
15
+ try {
16
+ $xml = $reader.ReadToEnd()
17
+ [System.IO.File]::WriteAllText($xmlPath, $xml, [System.Text.Encoding]::UTF8)
18
+ } finally {
19
+ $reader.Dispose()
20
+ }
21
+ }
22
+ } finally {
23
+ $zip.Dispose()
24
+ }
25
+ }
26
+
27
+ function Save-Triple($doc, [string]$baseName) {
28
+ $pendingDocx = [string](Join-Path $fixturesDir "$baseName-pending.docx")
29
+ $acceptedDocx = [string](Join-Path $fixturesDir "$baseName-accepted.docx")
30
+ $rejectedDocx = [string](Join-Path $fixturesDir "$baseName-rejected.docx")
31
+
32
+ [object]$pRef = $pendingDocx
33
+ [object]$aRef = $acceptedDocx
34
+ [object]$rRef = $rejectedDocx
35
+ [object]$fmt = 16
36
+
37
+ # Save pending
38
+ $doc.SaveAs2([ref]$pRef, [ref]$fmt)
39
+
40
+ # Accept All
41
+ $doc.Revisions.AcceptAll()
42
+ $doc.SaveAs2([ref]$aRef, [ref]$fmt)
43
+ $doc.Close($false)
44
+
45
+ # Reopen pending and Reject All
46
+ $reopened = $global:word.Documents.Open([ref]$pRef)
47
+ $reopened.Revisions.RejectAll()
48
+ $reopened.SaveAs2([ref]$rRef, [ref]$fmt)
49
+ $reopened.Close($false)
50
+
51
+ # Extract XML
52
+ Extract-DocumentXml $pendingDocx (Join-Path $fixturesDir "$baseName-pending.xml")
53
+ Extract-DocumentXml $acceptedDocx (Join-Path $fixturesDir "$baseName-accepted.xml")
54
+ Extract-DocumentXml $rejectedDocx (Join-Path $fixturesDir "$baseName-rejected.xml")
55
+ Write-Host "Saved: $baseName"
56
+ }
57
+
58
+ $global:word = New-Object -ComObject Word.Application
59
+ $global:word.Visible = $false
60
+ $global:word.DisplayAlerts = 0
61
+
62
+ try {
63
+ # 1. split-middle
64
+ Write-Host "1. split-middle"
65
+ $doc = $global:word.Documents.Add()
66
+ $doc.TrackRevisions = $false
67
+ $doc.Range(0, 0).Text = "Sentence one. Sentence two."
68
+ $doc.TrackRevisions = $true
69
+ $splitPoint = $doc.Range(14, 14)
70
+ $splitPoint.InsertParagraph()
71
+ Save-Triple $doc "split-middle"
72
+
73
+ # 2. delete-boundary
74
+ Write-Host "2. delete-boundary"
75
+ $doc = $global:word.Documents.Add()
76
+ $doc.TrackRevisions = $false
77
+ $r = $doc.Range(0, 0)
78
+ $r.Text = "Paragraph one."
79
+ $r.InsertParagraphAfter()
80
+ $doc.Paragraphs.Item(2).Range.Text = "Paragraph two."
81
+ $doc.TrackRevisions = $true
82
+ $p1 = $doc.Paragraphs.Item(1).Range
83
+ $delPoint = $doc.Range($p1.End - 1, $p1.End)
84
+ $delPoint.Delete() | Out-Null
85
+ Save-Triple $doc "delete-boundary"
86
+
87
+ # 3. delete-middle-paragraph
88
+ Write-Host "3. delete-middle-paragraph"
89
+ $doc = $global:word.Documents.Add()
90
+ $doc.TrackRevisions = $false
91
+ $r = $doc.Range(0, 0)
92
+ $r.Text = "Paragraph one."
93
+ $r.InsertParagraphAfter()
94
+ $doc.Paragraphs.Item(2).Range.Text = "Paragraph two."
95
+ $doc.Paragraphs.Item(2).Range.InsertParagraphAfter()
96
+ $doc.Paragraphs.Item(3).Range.Text = "Paragraph three."
97
+ $doc.TrackRevisions = $true
98
+ $p2 = $doc.Paragraphs.Item(2).Range
99
+ $p2.Delete() | Out-Null
100
+ Save-Triple $doc "delete-middle-paragraph"
101
+
102
+ # 4. insert-blank-paragraph
103
+ Write-Host "4. insert-blank-paragraph"
104
+ $doc = $global:word.Documents.Add()
105
+ $doc.TrackRevisions = $false
106
+ $r = $doc.Range(0, 0)
107
+ $r.Text = "Paragraph one."
108
+ $r.InsertParagraphAfter()
109
+ $doc.Paragraphs.Item(2).Range.Text = "Paragraph two."
110
+ $doc.TrackRevisions = $true
111
+ $p1 = $doc.Paragraphs.Item(1).Range
112
+ $insPoint = $doc.Range($p1.End - 1, $p1.End - 1)
113
+ $insPoint.InsertParagraph()
114
+ Save-Triple $doc "insert-blank-paragraph"
115
+
116
+ # 5. different-styles-boundary
117
+ Write-Host "5. different-styles-boundary"
118
+ $doc = $global:word.Documents.Add()
119
+ $doc.TrackRevisions = $false
120
+ $p1 = $doc.Paragraphs.Item(1).Range
121
+ $p1.Text = "Heading title"
122
+ $p1.Style = "Heading 1"
123
+ $p1.InsertParagraphAfter()
124
+ $p2 = $doc.Paragraphs.Item(2).Range
125
+ $p2.Text = "Normal body text."
126
+ $p2.Style = "Normal"
127
+ $doc.TrackRevisions = $true
128
+ $p1End = $doc.Paragraphs.Item(1).Range.End
129
+ $delPoint = $doc.Range($p1End - 1, $p1End)
130
+ $delPoint.Delete() | Out-Null
131
+ Save-Triple $doc "different-styles-boundary"
132
+
133
+ # 6. different-list-levels-boundary
134
+ Write-Host "6. different-list-levels-boundary"
135
+ $doc = $global:word.Documents.Add()
136
+ $doc.TrackRevisions = $false
137
+ $p1 = $doc.Paragraphs.Item(1).Range
138
+ $p1.Text = "List item 1"
139
+ $p1.InsertParagraphAfter()
140
+ $p2 = $doc.Paragraphs.Item(2).Range
141
+ $p2.Text = "List item 2"
142
+ $doc.Paragraphs.Item(1).Range.ListFormat.ApplyBulletDefault()
143
+ $doc.Paragraphs.Item(2).Range.ListFormat.ApplyBulletDefault()
144
+ $doc.Paragraphs.Item(2).Range.ListFormat.ListIndent()
145
+ $doc.TrackRevisions = $true
146
+ $p1End = $doc.Paragraphs.Item(1).Range.End
147
+ $delPoint = $doc.Range($p1End - 1, $p1End)
148
+ $delPoint.Delete() | Out-Null
149
+ Save-Triple $doc "different-list-levels-boundary"
150
+
151
+ # 7. section-break-boundary
152
+ Write-Host "7. section-break-boundary"
153
+ $doc = $global:word.Documents.Add()
154
+ $doc.TrackRevisions = $false
155
+ $p1 = $doc.Paragraphs.Item(1).Range
156
+ $p1.Text = "Section one text."
157
+ $p1.InsertBreak(2) # wdSectionBreakNextPage
158
+ $p2 = $doc.Paragraphs.Item(2).Range
159
+ $p2.Text = "Section two text."
160
+ $doc.TrackRevisions = $true
161
+ $p1End = $doc.Paragraphs.Item(1).Range.End
162
+ $delPoint = $doc.Range($p1End - 1, $p1End)
163
+ $delPoint.Delete() | Out-Null
164
+ Save-Triple $doc "section-break-boundary"
165
+
166
+ # 8. table-cell-boundary
167
+ Write-Host "8. table-cell-boundary"
168
+ $doc = $global:word.Documents.Add()
169
+ $doc.TrackRevisions = $false
170
+ $table = $doc.Tables.Add($doc.Range(0, 0), 1, 1)
171
+ $cell = $table.Cell(1, 1)
172
+ $cell.Range.Text = "Cell paragraph 1"
173
+ $cell.Range.InsertParagraphAfter()
174
+ $p2 = $doc.Paragraphs.Item(2).Range
175
+ $p2.Text = "Cell paragraph 2"
176
+ $doc.TrackRevisions = $true
177
+ $p1End = $doc.Paragraphs.Item(1).Range.End
178
+ $delPoint = $doc.Range($p1End - 1, $p1End)
179
+ $delPoint.Delete() | Out-Null
180
+ Save-Triple $doc "table-cell-boundary"
181
+
182
+ # 9. adjacent-bookmark-comment
183
+ Write-Host "9. adjacent-bookmark-comment"
184
+ $doc = $global:word.Documents.Add()
185
+ $doc.TrackRevisions = $false
186
+ $p1 = $doc.Paragraphs.Item(1).Range
187
+ $p1.Text = "Paragraph with bookmark."
188
+ $p1.InsertParagraphAfter()
189
+ $p2 = $doc.Paragraphs.Item(2).Range
190
+ $p2.Text = "Second paragraph."
191
+ $bmRange = $doc.Range(0, 9)
192
+ $doc.Bookmarks.Add("TestBookmark", $bmRange) | Out-Null
193
+ $doc.Comments.Add($bmRange, "Comment on first paragraph") | Out-Null
194
+ $doc.TrackRevisions = $true
195
+ $p1End = $doc.Paragraphs.Item(1).Range.End
196
+ $delPoint = $doc.Range($p1End - 1, $p1End)
197
+ $delPoint.Delete() | Out-Null
198
+ Save-Triple $doc "adjacent-bookmark-comment"
199
+
200
+ # 10. multi-author-boundary
201
+ Write-Host "10. multi-author-boundary"
202
+ $doc = $global:word.Documents.Add()
203
+ $doc.TrackRevisions = $false
204
+ $doc.Range(0, 0).Text = "Author one text. Author two text."
205
+ $doc.TrackRevisions = $true
206
+ $global:word.UserName = "AuthorOne"
207
+ $doc.Range(16, 16).InsertParagraph()
208
+ $global:word.UserName = "AuthorTwo"
209
+ $doc.Paragraphs.Item(2).Range.InsertBefore("Updated ")
210
+ Save-Triple $doc "multi-author-boundary"
211
+
212
+ Write-Host "All 10 Word paragraph boundary golden fixtures generated successfully!"
213
+ } finally {
214
+ $global:word.Quit()
215
+ }