@usejunior/docx-core 0.9.0 → 0.10.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.
Files changed (185) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/atomizer.d.ts +49 -0
  3. package/dist/atomizer.d.ts.map +1 -1
  4. package/dist/atomizer.js +90 -0
  5. package/dist/atomizer.js.map +1 -1
  6. package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
  7. package/dist/baselines/atomizer/documentReconstructor.js +289 -92
  8. package/dist/baselines/atomizer/documentReconstructor.js.map +1 -1
  9. package/dist/baselines/atomizer/formattingFidelity.d.ts +99 -0
  10. package/dist/baselines/atomizer/formattingFidelity.d.ts.map +1 -0
  11. package/dist/baselines/atomizer/formattingFidelity.js +449 -0
  12. package/dist/baselines/atomizer/formattingFidelity.js.map +1 -0
  13. package/dist/baselines/atomizer/inPlaceModifier-bookmarks.d.ts +37 -0
  14. package/dist/baselines/atomizer/inPlaceModifier-bookmarks.d.ts.map +1 -0
  15. package/dist/baselines/atomizer/inPlaceModifier-bookmarks.js +189 -0
  16. package/dist/baselines/atomizer/inPlaceModifier-bookmarks.js.map +1 -0
  17. package/dist/baselines/atomizer/inPlaceModifier-containers.d.ts +74 -0
  18. package/dist/baselines/atomizer/inPlaceModifier-containers.d.ts.map +1 -0
  19. package/dist/baselines/atomizer/inPlaceModifier-containers.js +171 -0
  20. package/dist/baselines/atomizer/inPlaceModifier-containers.js.map +1 -0
  21. package/dist/baselines/atomizer/inPlaceModifier-deletion.d.ts +88 -0
  22. package/dist/baselines/atomizer/inPlaceModifier-deletion.d.ts.map +1 -0
  23. package/dist/baselines/atomizer/inPlaceModifier-deletion.js +326 -0
  24. package/dist/baselines/atomizer/inPlaceModifier-deletion.js.map +1 -0
  25. package/dist/baselines/atomizer/inPlaceModifier-postprocess.d.ts +85 -0
  26. package/dist/baselines/atomizer/inPlaceModifier-postprocess.d.ts.map +1 -0
  27. package/dist/baselines/atomizer/inPlaceModifier-postprocess.js +402 -0
  28. package/dist/baselines/atomizer/inPlaceModifier-postprocess.js.map +1 -0
  29. package/dist/baselines/atomizer/inPlaceModifier-presplit.d.ts +39 -0
  30. package/dist/baselines/atomizer/inPlaceModifier-presplit.d.ts.map +1 -0
  31. package/dist/baselines/atomizer/inPlaceModifier-presplit.js +265 -0
  32. package/dist/baselines/atomizer/inPlaceModifier-presplit.js.map +1 -0
  33. package/dist/baselines/atomizer/inPlaceModifier-shared.d.ts +62 -0
  34. package/dist/baselines/atomizer/inPlaceModifier-shared.d.ts.map +1 -0
  35. package/dist/baselines/atomizer/inPlaceModifier-shared.js +139 -0
  36. package/dist/baselines/atomizer/inPlaceModifier-shared.js.map +1 -0
  37. package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts +189 -0
  38. package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts.map +1 -0
  39. package/dist/baselines/atomizer/inPlaceModifier-wrappers.js +427 -0
  40. package/dist/baselines/atomizer/inPlaceModifier-wrappers.js.map +1 -0
  41. package/dist/baselines/atomizer/inPlaceModifier.d.ts +6 -290
  42. package/dist/baselines/atomizer/inPlaceModifier.d.ts.map +1 -1
  43. package/dist/baselines/atomizer/inPlaceModifier.js +23 -1828
  44. package/dist/baselines/atomizer/inPlaceModifier.js.map +1 -1
  45. package/dist/baselines/atomizer/pipeline.d.ts +76 -1
  46. package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
  47. package/dist/baselines/atomizer/pipeline.js +445 -108
  48. package/dist/baselines/atomizer/pipeline.js.map +1 -1
  49. package/dist/baselines/atomizer/trackChangesAcceptorAst.d.ts.map +1 -1
  50. package/dist/baselines/atomizer/trackChangesAcceptorAst.js +56 -160
  51. package/dist/baselines/atomizer/trackChangesAcceptorAst.js.map +1 -1
  52. package/dist/compare-types.d.ts +151 -0
  53. package/dist/compare-types.d.ts.map +1 -0
  54. package/dist/compare-types.js +2 -0
  55. package/dist/compare-types.js.map +1 -0
  56. package/dist/core-types.d.ts +5 -1
  57. package/dist/core-types.d.ts.map +1 -1
  58. package/dist/core-types.js +5 -1
  59. package/dist/core-types.js.map +1 -1
  60. package/dist/footnotes.d.ts +8 -3
  61. package/dist/footnotes.d.ts.map +1 -1
  62. package/dist/footnotes.js +8 -3
  63. package/dist/footnotes.js.map +1 -1
  64. package/dist/index.d.ts +6 -150
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +6 -0
  67. package/dist/index.js.map +1 -1
  68. package/dist/integration/libreoffice-oracle.d.ts +41 -0
  69. package/dist/integration/libreoffice-oracle.d.ts.map +1 -0
  70. package/dist/integration/libreoffice-oracle.js +282 -0
  71. package/dist/integration/libreoffice-oracle.js.map +1 -0
  72. package/dist/integration/synthetic-docx-fixture.d.ts +62 -0
  73. package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -0
  74. package/dist/integration/synthetic-docx-fixture.js +171 -0
  75. package/dist/integration/synthetic-docx-fixture.js.map +1 -0
  76. package/dist/primitives/accept_changes.d.ts +2 -2
  77. package/dist/primitives/accept_changes.d.ts.map +1 -1
  78. package/dist/primitives/accept_changes.js +24 -79
  79. package/dist/primitives/accept_changes.js.map +1 -1
  80. package/dist/primitives/comments.d.ts +12 -3
  81. package/dist/primitives/comments.d.ts.map +1 -1
  82. package/dist/primitives/comments.js +374 -97
  83. package/dist/primitives/comments.js.map +1 -1
  84. package/dist/primitives/content_fingerprint.d.ts +29 -0
  85. package/dist/primitives/content_fingerprint.d.ts.map +1 -0
  86. package/dist/primitives/content_fingerprint.js +63 -0
  87. package/dist/primitives/content_fingerprint.js.map +1 -0
  88. package/dist/primitives/document.d.ts +56 -15
  89. package/dist/primitives/document.d.ts.map +1 -1
  90. package/dist/primitives/document.js +303 -32
  91. package/dist/primitives/document.js.map +1 -1
  92. package/dist/primitives/document_view-comments.d.ts +18 -0
  93. package/dist/primitives/document_view-comments.d.ts.map +1 -0
  94. package/dist/primitives/document_view-comments.js +159 -0
  95. package/dist/primitives/document_view-comments.js.map +1 -0
  96. package/dist/primitives/document_view-headings.d.ts +45 -0
  97. package/dist/primitives/document_view-headings.d.ts.map +1 -0
  98. package/dist/primitives/document_view-headings.js +247 -0
  99. package/dist/primitives/document_view-headings.js.map +1 -0
  100. package/dist/primitives/document_view-styles.d.ts +11 -0
  101. package/dist/primitives/document_view-styles.d.ts.map +1 -0
  102. package/dist/primitives/document_view-styles.js +104 -0
  103. package/dist/primitives/document_view-styles.js.map +1 -0
  104. package/dist/primitives/document_view-toon.d.ts +37 -0
  105. package/dist/primitives/document_view-toon.d.ts.map +1 -0
  106. package/dist/primitives/document_view-toon.js +199 -0
  107. package/dist/primitives/document_view-toon.js.map +1 -0
  108. package/dist/primitives/document_view-types.d.ts +137 -0
  109. package/dist/primitives/document_view-types.d.ts.map +1 -0
  110. package/dist/primitives/document_view-types.js +2 -0
  111. package/dist/primitives/document_view-types.js.map +1 -0
  112. package/dist/primitives/document_view.d.ts +8 -106
  113. package/dist/primitives/document_view.d.ts.map +1 -1
  114. package/dist/primitives/document_view.js +134 -301
  115. package/dist/primitives/document_view.js.map +1 -1
  116. package/dist/primitives/dom-helpers.d.ts +9 -0
  117. package/dist/primitives/dom-helpers.d.ts.map +1 -1
  118. package/dist/primitives/dom-helpers.js +10 -1
  119. package/dist/primitives/dom-helpers.js.map +1 -1
  120. package/dist/primitives/footnotes.d.ts +4 -3
  121. package/dist/primitives/footnotes.d.ts.map +1 -1
  122. package/dist/primitives/footnotes.js +232 -44
  123. package/dist/primitives/footnotes.js.map +1 -1
  124. package/dist/primitives/formatting_tags.d.ts +6 -0
  125. package/dist/primitives/formatting_tags.d.ts.map +1 -1
  126. package/dist/primitives/formatting_tags.js +6 -1
  127. package/dist/primitives/formatting_tags.js.map +1 -1
  128. package/dist/primitives/index.d.ts +6 -0
  129. package/dist/primitives/index.d.ts.map +1 -1
  130. package/dist/primitives/index.js +5 -0
  131. package/dist/primitives/index.js.map +1 -1
  132. package/dist/primitives/layout.d.ts +4 -3
  133. package/dist/primitives/layout.d.ts.map +1 -1
  134. package/dist/primitives/layout.js +32 -3
  135. package/dist/primitives/layout.js.map +1 -1
  136. package/dist/primitives/merge_runs.d.ts +21 -3
  137. package/dist/primitives/merge_runs.d.ts.map +1 -1
  138. package/dist/primitives/merge_runs.js +32 -10
  139. package/dist/primitives/merge_runs.js.map +1 -1
  140. package/dist/primitives/namespaces.d.ts +6 -0
  141. package/dist/primitives/namespaces.d.ts.map +1 -1
  142. package/dist/primitives/namespaces.js +9 -0
  143. package/dist/primitives/namespaces.js.map +1 -1
  144. package/dist/primitives/reject_changes.d.ts +2 -2
  145. package/dist/primitives/reject_changes.d.ts.map +1 -1
  146. package/dist/primitives/reject_changes.js +24 -81
  147. package/dist/primitives/reject_changes.js.map +1 -1
  148. package/dist/primitives/semantic_tags.d.ts +7 -0
  149. package/dist/primitives/semantic_tags.d.ts.map +1 -1
  150. package/dist/primitives/semantic_tags.js +21 -3
  151. package/dist/primitives/semantic_tags.js.map +1 -1
  152. package/dist/primitives/serialize_html.d.ts +36 -0
  153. package/dist/primitives/serialize_html.d.ts.map +1 -0
  154. package/dist/primitives/serialize_html.js +393 -0
  155. package/dist/primitives/serialize_html.js.map +1 -0
  156. package/dist/primitives/serialize_markdown.d.ts +16 -0
  157. package/dist/primitives/serialize_markdown.d.ts.map +1 -0
  158. package/dist/primitives/serialize_markdown.js +300 -0
  159. package/dist/primitives/serialize_markdown.js.map +1 -0
  160. package/dist/primitives/serialize_plaintext.d.ts +15 -0
  161. package/dist/primitives/serialize_plaintext.d.ts.map +1 -0
  162. package/dist/primitives/serialize_plaintext.js +154 -0
  163. package/dist/primitives/serialize_plaintext.js.map +1 -0
  164. package/dist/primitives/styles.js +22 -22
  165. package/dist/primitives/styles.js.map +1 -1
  166. package/dist/primitives/tables.d.ts.map +1 -1
  167. package/dist/primitives/tables.js +13 -3
  168. package/dist/primitives/tables.js.map +1 -1
  169. package/dist/primitives/text.d.ts +2 -1
  170. package/dist/primitives/text.d.ts.map +1 -1
  171. package/dist/primitives/text.js +116 -12
  172. package/dist/primitives/text.js.map +1 -1
  173. package/dist/primitives/track-changes-emitter.d.ts +139 -0
  174. package/dist/primitives/track-changes-emitter.d.ts.map +1 -0
  175. package/dist/primitives/track-changes-emitter.js +241 -0
  176. package/dist/primitives/track-changes-emitter.js.map +1 -0
  177. package/dist/primitives/xml-helpers.d.ts +29 -0
  178. package/dist/primitives/xml-helpers.d.ts.map +1 -0
  179. package/dist/primitives/xml-helpers.js +35 -0
  180. package/dist/primitives/xml-helpers.js.map +1 -0
  181. package/dist/shared/ooxml/namespaces.d.ts +4 -1
  182. package/dist/shared/ooxml/namespaces.d.ts.map +1 -1
  183. package/dist/shared/ooxml/namespaces.js +4 -1
  184. package/dist/shared/ooxml/namespaces.js.map +1 -1
  185. package/package.json +7 -6
@@ -0,0 +1,402 @@
1
+ /**
2
+ * In-Place AST Modifier
3
+ *
4
+ * Modifies the revised document's AST in-place to add track changes markup.
5
+ * This replaces the reconstruction-based approach with direct tree manipulation.
6
+ */
7
+ import { CorrelationStatus } from '../../core-types.js';
8
+ import { areRunPropertiesEqual } from '../../format-detection.js';
9
+ import { childElements, findChildByTagName, unwrapElement } from '../../primitives/index.js';
10
+ import { createEl } from './inPlaceModifier-shared.js';
11
+ import { TRACK_CHANGE_WRAPPERS } from './inPlaceModifier-wrappers.js';
12
+ export const DELETION_LIKE_STATUSES = new Set([
13
+ CorrelationStatus.Deleted,
14
+ CorrelationStatus.MovedSource,
15
+ ]);
16
+ export const INSERTION_LIKE_STATUSES = new Set([
17
+ CorrelationStatus.Inserted,
18
+ CorrelationStatus.MovedDestination,
19
+ ]);
20
+ /**
21
+ * Reorder merged atoms so that within each contiguous block of non-equal atoms,
22
+ * all deletion-like atoms come before all insertion-like atoms.
23
+ *
24
+ * This produces grouped tracked changes ("<del>old words</del><ins>new words</ins>")
25
+ * instead of alternating word-by-word pairs ("<del>old1</del><ins>new1</ins><del>old2</del>...").
26
+ */
27
+ export function groupDeletionsBeforeInsertions(atoms) {
28
+ const result = [];
29
+ let i = 0;
30
+ while (i < atoms.length) {
31
+ const atom = atoms[i];
32
+ const status = atom.correlationStatus;
33
+ // Pass through equal/format-changed/unknown atoms unchanged
34
+ if (!DELETION_LIKE_STATUSES.has(status) && !INSERTION_LIKE_STATUSES.has(status)) {
35
+ result.push(atom);
36
+ i++;
37
+ continue;
38
+ }
39
+ // Collect a contiguous block of change atoms (deletions + insertions)
40
+ const deletions = [];
41
+ const insertions = [];
42
+ while (i < atoms.length) {
43
+ const s = atoms[i].correlationStatus;
44
+ if (DELETION_LIKE_STATUSES.has(s)) {
45
+ deletions.push(atoms[i]);
46
+ }
47
+ else if (INSERTION_LIKE_STATUSES.has(s)) {
48
+ insertions.push(atoms[i]);
49
+ }
50
+ else {
51
+ break;
52
+ }
53
+ i++;
54
+ }
55
+ // Emit all deletions first, then all insertions
56
+ result.push(...deletions, ...insertions);
57
+ }
58
+ return result;
59
+ }
60
+ export function mergeAdjacentTrackChangeSiblings(root) {
61
+ function traverse(node) {
62
+ const children = childElements(node);
63
+ if (children.length < 2) {
64
+ // Still recurse into children
65
+ for (const child of childElements(node))
66
+ traverse(child);
67
+ return;
68
+ }
69
+ for (let i = 0; i < children.length - 1;) {
70
+ const a = children[i];
71
+ const b = children[i + 1];
72
+ if (a.tagName === b.tagName && TRACK_CHANGE_WRAPPERS.has(a.tagName) &&
73
+ a.getAttribute('w:author') === b.getAttribute('w:author') &&
74
+ a.getAttribute('w:date') === b.getAttribute('w:date')) {
75
+ // Absorb b's children into a
76
+ while (b.firstChild)
77
+ a.appendChild(b.firstChild);
78
+ node.removeChild(b);
79
+ // Remove b from our local children snapshot and don't increment i —
80
+ // recheck a with its new next sibling.
81
+ children.splice(i + 1, 1);
82
+ continue;
83
+ }
84
+ i++;
85
+ }
86
+ // Recurse into current children (re-query after mutations)
87
+ for (const child of childElements(node)) {
88
+ traverse(child);
89
+ }
90
+ }
91
+ traverse(root);
92
+ }
93
+ // =============================================================================
94
+ // Bug 1: Suppress field-adjacent false no-op del/ins pairs (issue #42)
95
+ // =============================================================================
96
+ /**
97
+ * Build a normalized content signature for a run's non-rPr children.
98
+ * On the del side, maps w:delText → w:t and w:delInstrText → w:instrText
99
+ * so that content from del wrappers can be compared to ins wrappers.
100
+ */
101
+ export function normalizeRunContentSignature(run, isDelSide) {
102
+ const parts = [];
103
+ for (let i = 0; i < run.childNodes.length; i++) {
104
+ const child = run.childNodes[i];
105
+ if (child.nodeType !== 1)
106
+ continue;
107
+ const el = child;
108
+ if (el.tagName === 'w:rPr')
109
+ continue;
110
+ let tag = el.tagName;
111
+ if (isDelSide) {
112
+ if (tag === 'w:delText')
113
+ tag = 'w:t';
114
+ else if (tag === 'w:delInstrText')
115
+ tag = 'w:instrText';
116
+ }
117
+ const text = el.textContent ?? '';
118
+ parts.push(`<${tag}>${text}</${tag}>`);
119
+ }
120
+ return parts.join('');
121
+ }
122
+ /**
123
+ * Check if an adjacent w:del + w:ins pair is a no-op (identical text and formatting).
124
+ * Both wrappers must contain the same number of runs with matching rPr and content.
125
+ */
126
+ export function isNoOpPair(del, ins) {
127
+ const delRuns = childElements(del).filter(c => c.tagName === 'w:r');
128
+ const insRuns = childElements(ins).filter(c => c.tagName === 'w:r');
129
+ if (delRuns.length !== insRuns.length)
130
+ return false;
131
+ if (delRuns.length === 0)
132
+ return false;
133
+ for (let i = 0; i < delRuns.length; i++) {
134
+ const delRun = delRuns[i];
135
+ const insRun = insRuns[i];
136
+ // Compare formatting via canonical rPr comparison
137
+ const delRPr = findChildByTagName(delRun, 'w:rPr');
138
+ const insRPr = findChildByTagName(insRun, 'w:rPr');
139
+ if (!areRunPropertiesEqual(delRPr ?? null, insRPr ?? null))
140
+ return false;
141
+ // Compare content structure (text, tabs, breaks, field chars, etc.)
142
+ const delSig = normalizeRunContentSignature(delRun, true);
143
+ const insSig = normalizeRunContentSignature(insRun, false);
144
+ if (delSig !== insSig)
145
+ return false;
146
+ }
147
+ return true;
148
+ }
149
+ /**
150
+ * Suppress no-op del/ins pairs — adjacent w:del + w:ins wrappers where the
151
+ * content and formatting are identical. These arise from field-adjacent atoms
152
+ * that are false-positive changes.
153
+ *
154
+ * When a no-op is detected, both wrappers are unwrapped, leaving the ins-side
155
+ * runs as plain (non-tracked) children. The del-side runs are removed.
156
+ */
157
+ export function suppressNoOpChangePairs(root) {
158
+ function traverse(node) {
159
+ const children = childElements(node);
160
+ for (let i = 0; i < children.length - 1;) {
161
+ const a = children[i];
162
+ const b = children[i + 1];
163
+ if (a.tagName === 'w:del' && b.tagName === 'w:ins' && isNoOpPair(a, b)) {
164
+ // Remove the del wrapper and its content entirely
165
+ node.removeChild(a);
166
+ // Unwrap the ins wrapper — promote its children to the parent
167
+ unwrapElement(b);
168
+ // Re-snapshot children after mutation
169
+ children.splice(i, 2, ...childElements(node).slice(i));
170
+ // Don't increment — recheck from same position
171
+ continue;
172
+ }
173
+ i++;
174
+ }
175
+ // Recurse into current children (re-query after mutations)
176
+ for (const child of childElements(node)) {
177
+ traverse(child);
178
+ }
179
+ }
180
+ traverse(root);
181
+ }
182
+ // =============================================================================
183
+ // Bug 2: Merge whitespace-bridged track change siblings (issue #42)
184
+ // =============================================================================
185
+ /**
186
+ * Narrow whitespace predicate for bridging: returns true only if a w:r element's
187
+ * visible children are exclusively w:t elements with whitespace-only text content.
188
+ * Excludes w:tab, w:br, w:cr which have layout significance.
189
+ */
190
+ export function isInlineWhitespaceOnlyRun(run) {
191
+ if (run.tagName !== 'w:r')
192
+ return false;
193
+ let hasVisibleChild = false;
194
+ for (let i = 0; i < run.childNodes.length; i++) {
195
+ const child = run.childNodes[i];
196
+ if (child.nodeType !== 1)
197
+ continue;
198
+ const el = child;
199
+ if (el.tagName === 'w:rPr')
200
+ continue;
201
+ // Only w:t with whitespace-only text is allowed
202
+ if (el.tagName === 'w:t') {
203
+ const text = el.textContent ?? '';
204
+ if (text.length === 0 || !/^\s+$/.test(text))
205
+ return false;
206
+ hasVisibleChild = true;
207
+ continue;
208
+ }
209
+ // Any other visible element (w:tab, w:br, w:cr, w:fldChar, etc.) disqualifies
210
+ return false;
211
+ }
212
+ return hasVisibleChild;
213
+ }
214
+ /**
215
+ * Merge track-change wrappers (w:del or w:ins) that are separated by a
216
+ * whitespace-only run. This groups "word-by-word" tracked changes into
217
+ * contiguous blocks for cleaner presentation.
218
+ *
219
+ * For w:del: clones the whitespace run, converts w:t→w:delText, and absorbs
220
+ * both the whitespace and the second wrapper's children into the first wrapper.
221
+ *
222
+ * For w:ins: moves the whitespace run into the first wrapper, then absorbs
223
+ * the second wrapper's children.
224
+ *
225
+ * Both projections (Accept All, Reject All) remain correct because each
226
+ * wrapper independently contains the whitespace it needs.
227
+ */
228
+ export function mergeWhitespaceBridgedTrackChanges(root) {
229
+ function traverse(node) {
230
+ const children = childElements(node);
231
+ for (let i = 0; i < children.length - 2;) {
232
+ const a = children[i];
233
+ const mid = children[i + 1];
234
+ const b = children[i + 2];
235
+ // Check: same track-change tag, same author/date, with whitespace-only run between.
236
+ // Only bridge w:ins and w:moveTo — bridging w:del is unsafe because the
237
+ // intervening whitespace is Equal content needed by the accept projection.
238
+ const bridgeableTags = new Set(['w:ins', 'w:moveTo']);
239
+ if (a.tagName === b.tagName &&
240
+ bridgeableTags.has(a.tagName) &&
241
+ a.getAttribute('w:author') === b.getAttribute('w:author') &&
242
+ a.getAttribute('w:date') === b.getAttribute('w:date') &&
243
+ isInlineWhitespaceOnlyRun(mid)) {
244
+ // Move the whitespace run into the first wrapper, then absorb second's children
245
+ a.appendChild(mid);
246
+ while (b.firstChild)
247
+ a.appendChild(b.firstChild);
248
+ node.removeChild(b);
249
+ // mid was moved into a, b removed from parent — splice both from snapshot
250
+ children.splice(i + 1, 2);
251
+ // Don't increment — recheck a with new next sibling
252
+ continue;
253
+ }
254
+ i++;
255
+ }
256
+ // Recurse into current children (re-query after mutations)
257
+ for (const child of childElements(node)) {
258
+ traverse(child);
259
+ }
260
+ }
261
+ traverse(root);
262
+ }
263
+ // =============================================================================
264
+ // Bug 2b: Coalesce del/ins pair chains across whitespace (issue #42)
265
+ // =============================================================================
266
+ /**
267
+ * Convert w:t → w:delText and w:instrText → w:delInstrText within a run,
268
+ * preserving xml:space attributes. Used for cloning whitespace runs into
269
+ * w:del wrappers during pair-chain coalescing.
270
+ */
271
+ export function convertRunTextToDelText(run) {
272
+ for (let i = 0; i < run.childNodes.length; i++) {
273
+ const child = run.childNodes[i];
274
+ if (child.nodeType !== 1)
275
+ continue;
276
+ const el = child;
277
+ if (el.tagName === 'w:t' || el.tagName === 'w:instrText') {
278
+ const newTag = el.tagName === 'w:t' ? 'w:delText' : 'w:delInstrText';
279
+ const newEl = createEl(newTag);
280
+ // Copy text content
281
+ while (el.firstChild)
282
+ newEl.appendChild(el.firstChild);
283
+ // Copy attributes (including xml:space="preserve")
284
+ for (let j = 0; j < el.attributes.length; j++) {
285
+ const attr = el.attributes[j];
286
+ newEl.setAttribute(attr.name, attr.value);
287
+ }
288
+ run.replaceChild(newEl, el);
289
+ }
290
+ }
291
+ }
292
+ /**
293
+ * Coalesce alternating del/ins pair chains separated by whitespace-only runs
294
+ * into single grouped del + ins wrappers.
295
+ *
296
+ * Pattern: [w:del, w:ins, ws-segment..., w:del, w:ins, ws-segment..., w:del, w:ins]
297
+ *
298
+ * For each whitespace segment between consecutive [del, ins] pairs:
299
+ * 1. Clone each ws-run → convert to delText → append to first del
300
+ * 2. Clone each ws-run → keep as w:t → append to first ins
301
+ * 3. Move nextDel's children into first del
302
+ * 4. Move nextIns's children into first ins
303
+ * 5. Remove original ws-runs, empty nextDel, empty nextIns from parent
304
+ *
305
+ * Safety invariants:
306
+ * - Only bridges when both del AND ins absorb the whitespace (both projections correct)
307
+ * - Incomplete tail [del, ins, ws, del] (no trailing ins) → stop chain, don't bridge
308
+ * - All wrappers in chain must share same w:author and w:date
309
+ */
310
+ export function coalesceDelInsPairChains(root) {
311
+ function traverse(node) {
312
+ const children = childElements(node);
313
+ for (let i = 0; i < children.length - 1;) {
314
+ const firstDel = children[i];
315
+ const firstIns = children[i + 1];
316
+ // Must start with a [del, ins] pair
317
+ if (firstDel.tagName !== 'w:del' || firstIns.tagName !== 'w:ins') {
318
+ i++;
319
+ continue;
320
+ }
321
+ const author = firstDel.getAttribute('w:author');
322
+ const date = firstDel.getAttribute('w:date');
323
+ // All four must match author/date
324
+ if (firstIns.getAttribute('w:author') !== author ||
325
+ firstIns.getAttribute('w:date') !== date) {
326
+ i++;
327
+ continue;
328
+ }
329
+ // Try to extend the chain by absorbing subsequent [ws..., del, ins] triples
330
+ let cursor = i + 2; // position after firstIns
331
+ let chainExtended = false;
332
+ while (cursor < children.length) {
333
+ // Collect whitespace segment (1..N consecutive whitespace-only runs)
334
+ const wsStart = cursor;
335
+ while (cursor < children.length && isInlineWhitespaceOnlyRun(children[cursor])) {
336
+ cursor++;
337
+ }
338
+ const wsEnd = cursor;
339
+ const wsCount = wsEnd - wsStart;
340
+ if (wsCount === 0)
341
+ break; // No whitespace → end of chain
342
+ // Must have a complete [del, ins] pair after the whitespace
343
+ if (cursor + 1 >= children.length)
344
+ break; // Not enough elements
345
+ const nextDel = children[cursor];
346
+ const nextIns = children[cursor + 1];
347
+ if (nextDel.tagName !== 'w:del' || nextIns.tagName !== 'w:ins')
348
+ break;
349
+ // Author/date must match
350
+ if (nextDel.getAttribute('w:author') !== author ||
351
+ nextDel.getAttribute('w:date') !== date ||
352
+ nextIns.getAttribute('w:author') !== author ||
353
+ nextIns.getAttribute('w:date') !== date)
354
+ break;
355
+ // All conditions met — absorb this [ws..., del, ins] into the first pair
356
+ // 1. Clone whitespace runs into del (as delText) and ins (as w:t)
357
+ for (let w = wsStart; w < wsEnd; w++) {
358
+ const wsRun = children[w];
359
+ const delClone = wsRun.cloneNode(true);
360
+ convertRunTextToDelText(delClone);
361
+ firstDel.appendChild(delClone);
362
+ const insClone = wsRun.cloneNode(true);
363
+ firstIns.appendChild(insClone);
364
+ }
365
+ // 2. Move nextDel's children into firstDel
366
+ while (nextDel.firstChild)
367
+ firstDel.appendChild(nextDel.firstChild);
368
+ // 3. Move nextIns's children into firstIns
369
+ while (nextIns.firstChild)
370
+ firstIns.appendChild(nextIns.firstChild);
371
+ // 4. Remove ws-runs, nextDel, nextIns from parent
372
+ for (let w = wsStart; w < wsEnd; w++) {
373
+ node.removeChild(children[w]);
374
+ }
375
+ node.removeChild(nextDel);
376
+ node.removeChild(nextIns);
377
+ // 5. Splice removed elements from children snapshot
378
+ // Remove wsCount + 2 elements starting at wsStart
379
+ children.splice(wsStart, wsCount + 2);
380
+ // Reset cursor to continue checking after firstIns
381
+ cursor = wsStart;
382
+ chainExtended = true;
383
+ }
384
+ // Advance past the (possibly extended) [del, ins] pair
385
+ i += chainExtended ? 2 : 1;
386
+ // If no chain was formed, we only skip the del (i++ already happened above
387
+ // for the non-chain case), but if it was a chain we skip both del+ins.
388
+ // Actually: if chain wasn't extended, we need to check if firstDel+firstIns
389
+ // alone should advance by 2 or by 1. Since they ARE a del+ins pair but
390
+ // no chain formed, skip both.
391
+ if (!chainExtended) {
392
+ i++; // skip the ins too (total i += 2 from the earlier i++)
393
+ }
394
+ }
395
+ // Recurse into current children (re-query after mutations)
396
+ for (const child of childElements(node)) {
397
+ traverse(child);
398
+ }
399
+ }
400
+ traverse(root);
401
+ }
402
+ //# sourceMappingURL=inPlaceModifier-postprocess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inPlaceModifier-postprocess.js","sourceRoot":"","sources":["../../../src/baselines/atomizer/inPlaceModifier-postprocess.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * In-Place AST Modifier
3
+ *
4
+ * Modifies the revised document's AST in-place to add track changes markup.
5
+ * This replaces the reconstruction-based approach with direct tree manipulation.
6
+ */
7
+ import type { ComparisonUnitAtom } from '../../core-types.js';
8
+ export declare function atomContentVisibleLength(el: Element): number;
9
+ /**
10
+ * Pre-split revised-tree runs that contain atoms with mixed correlation statuses.
11
+ *
12
+ * Without this, `handleInserted` wraps the entire run with `<w:ins>`, destroying
13
+ * Equal content in the same run. After splitting, each fragment is a separate
14
+ * `<w:r>` and existing per-status handlers work without modification.
15
+ *
16
+ * Safety: wrapped in try/catch per run group. If any DOM operation fails, the
17
+ * run is skipped and the existing fallback-to-rebuild architecture handles it.
18
+ */
19
+ export declare function preSplitMixedStatusRuns(mergedAtoms: ComparisonUnitAtom[]): void;
20
+ /**
21
+ * Pre-split revised-tree runs where word-split Equal atoms from the same run
22
+ * are interleaved with Deleted/MovedSource atoms in the merged atom list.
23
+ *
24
+ * `preSplitMixedStatusRuns` handles the case where a single run contains atoms
25
+ * with DIFFERENT statuses (e.g., some Equal and some Inserted). But it cannot
26
+ * handle the case where ALL atoms from a run are Equal yet Deleted atoms (from
27
+ * the original tree) are interspersed between them in the merged list.
28
+ *
29
+ * Without this split, `handleEqual` sees all Equal atoms pointing to the same
30
+ * run and skips position advancement (the `lastRevisedRunAnchor` optimization).
31
+ * Subsequent `handleDeleted` calls then insert deleted content at the wrong
32
+ * position because the cursor never advanced past the shared run.
33
+ *
34
+ * This function detects interleaved sequences and splits the DOM run so each
35
+ * contiguous group of Equal atoms gets its own run fragment. The handlers then
36
+ * advance the cursor correctly across fragments.
37
+ */
38
+ export declare function preSplitInterleavedWordRuns(mergedAtoms: ComparisonUnitAtom[]): void;
39
+ //# sourceMappingURL=inPlaceModifier-presplit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inPlaceModifier-presplit.d.ts","sourceRoot":"","sources":["../../../src/baselines/atomizer/inPlaceModifier-presplit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAM9D,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,OAAO,GAAG,MAAM,CAM5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAuH/E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAuInF"}