@docx4j/core-ts 0.5.0 → 0.6.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 (155) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +32 -4
  3. package/dist/html/convert.mjs +2 -1
  4. package/dist/html/elements.mjs +2 -1
  5. package/dist/model/color/ColorMath.d.mts +29 -0
  6. package/dist/model/color/ColorMath.mjs +146 -0
  7. package/dist/model/color/ColorTables.d.mts +6 -0
  8. package/dist/model/color/ColorTables.mjs +83 -0
  9. package/dist/model/color/DrawingMLColors.d.mts +52 -0
  10. package/dist/model/color/DrawingMLColors.mjs +374 -0
  11. package/dist/model/color/ResolvedColor.d.mts +36 -0
  12. package/dist/model/color/ResolvedColor.mjs +65 -0
  13. package/dist/model/color/SpreadsheetColors.d.mts +36 -0
  14. package/dist/model/color/SpreadsheetColors.mjs +84 -0
  15. package/dist/model/color/StyleFill.d.mts +28 -0
  16. package/dist/model/color/StyleFill.mjs +21 -0
  17. package/dist/model/color/ThemeColors.d.mts +86 -0
  18. package/dist/model/color/ThemeColors.mjs +304 -0
  19. package/dist/model/color/WordColors.d.mts +71 -0
  20. package/dist/model/color/WordColors.mjs +121 -0
  21. package/dist/model/color/index.d.mts +6 -0
  22. package/dist/model/color/index.mjs +30 -0
  23. package/dist/model/content/Body.d.mts +145 -23
  24. package/dist/model/content/Body.mjs +509 -141
  25. package/dist/model/content/Comment.d.mts +21 -3
  26. package/dist/model/content/Comment.mjs +195 -19
  27. package/dist/model/content/ContentControl.d.mts +197 -18
  28. package/dist/model/content/ContentControl.mjs +664 -95
  29. package/dist/model/content/Font.d.mts +67 -17
  30. package/dist/model/content/Font.mjs +114 -35
  31. package/dist/model/content/InlinePicture.d.mts +11 -0
  32. package/dist/model/content/InlinePicture.mjs +21 -1
  33. package/dist/model/content/List.mjs +3 -0
  34. package/dist/model/content/Paragraph.d.mts +189 -13
  35. package/dist/model/content/Paragraph.mjs +870 -74
  36. package/dist/model/content/Range.d.mts +227 -12
  37. package/dist/model/content/Range.mjs +785 -59
  38. package/dist/model/content/ResolvedView.d.mts +104 -0
  39. package/dist/model/content/ResolvedView.mjs +596 -0
  40. package/dist/model/content/Table.d.mts +29 -3
  41. package/dist/model/content/Table.mjs +109 -33
  42. package/dist/model/content/TrackedChange.d.mts +172 -13
  43. package/dist/model/content/TrackedChange.mjs +728 -167
  44. package/dist/model/content/comments.d.mts +20 -6
  45. package/dist/model/content/comments.mjs +67 -57
  46. package/dist/model/content/generalException.d.mts +18 -0
  47. package/dist/model/content/generalException.mjs +24 -0
  48. package/dist/model/content/index.d.mts +8 -3
  49. package/dist/model/content/index.mjs +7 -2
  50. package/dist/model/content/mathText.d.mts +21 -0
  51. package/dist/model/content/mathText.mjs +267 -0
  52. package/dist/model/content/officeText.d.mts +27 -0
  53. package/dist/model/content/officeText.mjs +74 -0
  54. package/dist/model/content/outline.d.mts +5 -0
  55. package/dist/model/content/outline.mjs +13 -0
  56. package/dist/model/content/placeholders.d.mts +110 -0
  57. package/dist/model/content/placeholders.mjs +253 -0
  58. package/dist/model/content/search.d.mts +72 -0
  59. package/dist/model/content/search.mjs +204 -2
  60. package/dist/model/content/spanEdits.d.mts +159 -0
  61. package/dist/model/content/spanEdits.mjs +728 -0
  62. package/dist/model/content/story.d.mts +44 -0
  63. package/dist/model/content/story.mjs +92 -0
  64. package/dist/model/content/tableColumns.d.mts +1 -1
  65. package/dist/model/content/tableColumns.mjs +108 -80
  66. package/dist/model/content/tableRevisions.d.mts +11 -3
  67. package/dist/model/content/tableRevisions.mjs +72 -42
  68. package/dist/model/content/tableRules.d.mts +30 -0
  69. package/dist/model/content/tableRules.mjs +100 -0
  70. package/dist/model/content/textBoxes.d.mts +18 -0
  71. package/dist/model/content/textBoxes.mjs +105 -0
  72. package/dist/model/content/trackedChangeFilter.d.mts +39 -0
  73. package/dist/model/content/trackedChangeFilter.mjs +81 -0
  74. package/dist/model/content/tracking.d.mts +28 -0
  75. package/dist/model/content/tracking.mjs +149 -10
  76. package/dist/model/content/tree.d.mts +171 -22
  77. package/dist/model/content/tree.mjs +329 -53
  78. package/dist/model/customxml/CustomXmlPartCollection.d.mts +8 -0
  79. package/dist/model/customxml/CustomXmlPartCollection.mjs +34 -11
  80. package/dist/model/customxml/XmlMapping.d.mts +1 -1
  81. package/dist/model/customxml/XmlMapping.mjs +11 -0
  82. package/dist/model/customxml/bindings.d.mts +21 -2
  83. package/dist/model/customxml/bindings.mjs +76 -32
  84. package/dist/model/customxml/kinds.d.mts +8 -3
  85. package/dist/model/customxml/kinds.mjs +26 -5
  86. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  87. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  88. package/dist/model/customxml/pictures.d.mts +4 -3
  89. package/dist/model/customxml/pictures.mjs +18 -6
  90. package/dist/model/customxml/xhtml.mjs +8 -2
  91. package/dist/model/index.d.mts +2 -0
  92. package/dist/model/index.mjs +4 -0
  93. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  94. package/dist/model/listnumbering/Emulator.mjs +63 -9
  95. package/dist/model/properties/PropertyResolver.d.mts +60 -1
  96. package/dist/model/properties/PropertyResolver.mjs +115 -2
  97. package/dist/model/properties/catalogue.d.mts +19 -5
  98. package/dist/model/properties/catalogue.mjs +41 -15
  99. package/dist/model/properties/log.d.mts +1 -1
  100. package/dist/model/properties/log.mjs +5 -5
  101. package/dist/model/properties/table.mjs +4 -2
  102. package/dist/model/text/Extractor.d.mts +289 -0
  103. package/dist/model/text/Extractor.mjs +2162 -0
  104. package/dist/model/text/LinkTargets.d.mts +45 -0
  105. package/dist/model/text/LinkTargets.mjs +170 -0
  106. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  107. package/dist/model/text/MarkdownExporter.mjs +255 -0
  108. package/dist/model/text/PlainText.d.mts +29 -0
  109. package/dist/model/text/PlainText.mjs +539 -0
  110. package/dist/model/text/TextContext.d.mts +161 -0
  111. package/dist/model/text/TextContext.mjs +425 -0
  112. package/dist/model/text/TextOptions.d.mts +150 -0
  113. package/dist/model/text/TextOptions.mjs +278 -0
  114. package/dist/model/text/TextResult.d.mts +504 -0
  115. package/dist/model/text/TextResult.mjs +526 -0
  116. package/dist/model/text/Texts.d.mts +99 -0
  117. package/dist/model/text/Texts.mjs +187 -0
  118. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  119. package/dist/model/text/WmlToMarkdown.mjs +911 -0
  120. package/dist/model/text/commonmark.d.mts +121 -0
  121. package/dist/model/text/commonmark.mjs +655 -0
  122. package/dist/model/text/index.d.mts +7 -0
  123. package/dist/model/text/index.mjs +8 -0
  124. package/dist/model/text/normalize.d.mts +8 -0
  125. package/dist/model/text/normalize.mjs +13 -0
  126. package/dist/model/text/outline.d.mts +4 -0
  127. package/dist/model/text/outline.mjs +71 -0
  128. package/dist/office-js/fragment.d.mts +7 -5
  129. package/dist/office-js/fragment.mjs +63 -14
  130. package/dist/office-js/proxy.d.mts +8 -0
  131. package/dist/office-js/proxy.mjs +29 -0
  132. package/dist/office-js/run.mjs +2 -0
  133. package/dist/office-js/supported.generated.mjs +16 -0
  134. package/dist/office-js/toApiScript.mjs +21 -5
  135. package/dist/opc/Save.d.mts +17 -0
  136. package/dist/opc/Save.mjs +12 -2
  137. package/dist/opc/index.d.mts +3 -3
  138. package/dist/opc/index.mjs +1 -1
  139. package/dist/opc/mce/preprocessor.d.mts +28 -3
  140. package/dist/opc/mce/preprocessor.mjs +4 -4
  141. package/dist/opc/mce/understood.d.mts +30 -6
  142. package/dist/opc/mce/understood.mjs +37 -7
  143. package/dist/packages/OpcPackage.d.mts +13 -0
  144. package/dist/packages/OpcPackage.mjs +1 -0
  145. package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
  146. package/dist/packages/WordprocessingMLPackage.mjs +155 -20
  147. package/dist/parts/DefaultXmlPart.mjs +2 -2
  148. package/dist/parts/Part.d.mts +10 -2
  149. package/dist/parts/XmlPart.d.mts +12 -30
  150. package/dist/parts/XmlPart.mjs +44 -93
  151. package/dist/parts/wml/comments.mjs +30 -0
  152. package/dist/parts/wml/index.mjs +12 -0
  153. package/dist/xml/dom.d.mts +7 -0
  154. package/dist/xml/dom.mjs +18 -0
  155. package/package.json +2 -2
@@ -0,0 +1,596 @@
1
+ import { typeNameOf, runItemsOf, childrenOf, revisionKindOf, itemTextOf } from './tree.mjs';
2
+ import { movePiecesOf, storyOf, firstCellParagraphOf } from './TrackedChange.mjs';
3
+ import { trackedChangesOfStory } from './Body.mjs';
4
+ import { HOLDER_TYPES } from './tracking.mjs';
5
+ const valueOf = (item) => (typeof item === 'object' && item !== null && 'value' in item && 'name' in item ? item.value : item);
6
+ const localName = (item) => { var _a, _b; return (typeof item === 'object' && item !== null && 'name' in item ? (_b = (_a = item.name) === null || _a === void 0 ? void 0 : _a.localPart) !== null && _b !== void 0 ? _b : '' : ''); };
7
+ const commentIdOf = (item) => { var _a; return (_a = valueOf(item)) === null || _a === void 0 ? void 0 : _a.id; };
8
+ /** The index in `list`, from `from` up to `to`, of a comment's range start or end (`local`), or -1. */
9
+ function markerAt(list, from, to, local, id) {
10
+ for (let i = from; i < to; i++)
11
+ if (localName(list[i]) === local && commentIdOf(list[i]) === id)
12
+ return i;
13
+ return -1;
14
+ }
15
+ /** A block-level control's content, which holds paragraphs. */
16
+ const SDT_CONTENTS = new Set(['org_docx4j_wml.SdtContentBlock', 'org_docx4j_wml.CTSdtContentBlock']);
17
+ /** A marker that stands between two blocks without keeping them apart, as a join reads one. */
18
+ function isRangeMarker(item) {
19
+ const name = localName(item);
20
+ return name.endsWith('RangeStart') || name.endsWith('RangeEnd') || name === 'bookmarkStart' || name === 'bookmarkEnd'
21
+ || name === 'permStart' || name === 'permEnd' || name === 'proofErr';
22
+ }
23
+ /** The live list of run-level content a holder keeps, or of block content a container keeps. */
24
+ function listOf(value) {
25
+ var _a;
26
+ if (typeof value !== 'object' || value === null)
27
+ return undefined;
28
+ return (_a = runItemsOf(value)) !== null && _a !== void 0 ? _a : childrenOf(value);
29
+ }
30
+ /**
31
+ * What Word's Accept All or Reject All would leave of a document, as `acceptAllRevisions` and
32
+ * `rejectAllRevisions` leave it, worked out without resolving anything: the content each removes and the
33
+ * paragraphs each joins. A reader walks the unresolved tree and asks this view what is there, so that the
34
+ * text it reads in a view is the text of the resolved document (WD REQ-402), and the package is untouched
35
+ * (REQ-204). docx4j `org.docx4j.model.revisions.ResolvedView`.
36
+ *
37
+ * It lists each story's changes (`trackedChangesOfStory`, text boxes in their selected branch) and
38
+ * records, change by change, what the resolution would do to the text: a revision taken away, a move's
39
+ * halves and the text typed into a rejected move's destination, an inserted field rejected whole, a row
40
+ * or cell taken away, an equation's run-level revision or structure, a paragraph mark taken away, and an
41
+ * inserted content control rejected (its content left in its place). What a resolution does to
42
+ * properties, range markers, comments' entries and parts is not recorded; the comments a resolution takes
43
+ * whole are (CR-002 section 54).
44
+ *
45
+ * A snapshot over the trees it was made from: valid until they change.
46
+ */
47
+ export class ResolvedView {
48
+ constructor(stories, accepted) {
49
+ this.accepted = accepted;
50
+ /** List members gone, by identity of their values. */
51
+ this.removed = new Set();
52
+ /** Content controls and custom XML elements gone, their content standing in their place. */
53
+ this.unwrapped = new Set();
54
+ /** Paragraphs whose mark is gone. */
55
+ this.marksGone = new Set();
56
+ /** Moved paragraphs whose mark is gone: gone themselves when nothing is left in them, else joined. */
57
+ this.movedMarksGone = new Set();
58
+ this.commentCandidates = [];
59
+ this.spanCandidates = [];
60
+ this.commentsGone = new Set();
61
+ /** Move halves whose story has no piece for them (a text box's, whose paragraphs' story is the body around it). */
62
+ this.unreplayed = new Set();
63
+ const changes = [];
64
+ for (const body of stories)
65
+ changes.push(...trackedChangesOfStory(body));
66
+ // moves first, story by story, in the resolution's order: their outcome depends on it
67
+ const moves = new Map();
68
+ for (const change of changes)
69
+ this.collectMoves(change, moves);
70
+ for (const [story, halves] of moves)
71
+ for (const missing of new MoveReplay(this, story, halves).run())
72
+ this.unreplayed.add(missing);
73
+ for (const change of changes)
74
+ this.plan(change);
75
+ for (const c of this.commentCandidates)
76
+ if (c.rangeEmpty())
77
+ this.commentsGone.add(Number(c.id));
78
+ for (const c of this.spanCandidates)
79
+ if (c.rangeEmpty())
80
+ this.commentsGone.add(Number(c.id));
81
+ }
82
+ /** The document after Accept All, over these stories (each a `Body` over the tree a reader walks). */
83
+ static accepted(stories) {
84
+ return new ResolvedView(stories, true);
85
+ }
86
+ /** The document after Reject All. */
87
+ static original(stories) {
88
+ return new ResolvedView(stories, false);
89
+ }
90
+ collectMoves(change, moves) {
91
+ const t = change.target;
92
+ if (t.kind === 'group') {
93
+ for (const piece of t.pieces)
94
+ this.collectMoves(piece, moves);
95
+ return;
96
+ }
97
+ if (t.kind === 'row') {
98
+ for (const inner of t.inner)
99
+ this.collectMoves(inner, moves);
100
+ return;
101
+ }
102
+ if (t.kind !== 'run' || (t.revision !== 'moveFrom' && t.revision !== 'moveTo') || !change.paragraph)
103
+ return;
104
+ const story = storyOf(change.paragraph.p);
105
+ let list = moves.get(story);
106
+ if (!list)
107
+ moves.set(story, (list = []));
108
+ list.push(change);
109
+ }
110
+ /**
111
+ * Whether a list member is gone in this view: a run-level revision taken away with its content, a run,
112
+ * a row, a cell, a paragraph, an equation's run-level revision or structure. A revision that is not
113
+ * gone is kept: its content is read as if it were not there. An element pair and its value alike.
114
+ */
115
+ removes(item) {
116
+ var _a;
117
+ const v = valueOf(item);
118
+ if (v === undefined || v === null)
119
+ return false;
120
+ if (this.removed.has(v))
121
+ return true;
122
+ const tn = typeNameOf(v);
123
+ if (tn === 'org_docx4j_wml.Tbl')
124
+ return this.emptiedTable(v);
125
+ if (tn !== 'org_docx4j_wml.P')
126
+ return false;
127
+ const p = v;
128
+ if (this.movedMarksGone.has(p) && !this.remainsIn(p))
129
+ return true;
130
+ if (!this.marksGone.has(p))
131
+ return false;
132
+ // an emptied paragraph whose mark is gone, with a table or a block control next in its list: gone (docx4j CR-043
133
+ // section 17: check 54 case 9, the text-left probe's case 3). One with text left and a table next isn't removed but
134
+ // moved: `joinsIntoTable`, which the walk applies
135
+ const next = this.nextBlockAfter(p);
136
+ return !this.remainsIn(p) && (typeNameOf(next) === 'org_docx4j_wml.Tbl' || HOLDER_TYPES.has((_a = typeNameOf(next)) !== null && _a !== void 0 ? _a : ''));
137
+ }
138
+ /**
139
+ * The table a paragraph with text left joins into, where its mark is gone and a table is the next block in its list
140
+ * (Word 365's Accept All, docx4j CR-043 section 17, the text-left probe's case 1: its content lands at the front of the
141
+ * first cell's first paragraph, which keeps its own properties); undefined otherwise. docx4j `joinsIntoTable`.
142
+ */
143
+ joinsIntoTable(p) {
144
+ if (!this.marksGone.has(p) || !this.remainsIn(p))
145
+ return undefined;
146
+ const next = this.nextBlockAfter(p);
147
+ return typeNameOf(next) === 'org_docx4j_wml.Tbl' && firstCellParagraphOf(next) ? next : undefined;
148
+ }
149
+ /**
150
+ * A paragraph's properties in this view, where its mark is gone and no paragraph follows it in its list (Word 365's
151
+ * Accept All, check 54; docx4j CR-043 section 17): a block control next gives it the control's first paragraph's
152
+ * properties, as a join would have (case 19); a control's last paragraph keeps a bare mark, its properties gone, its
153
+ * text left or not (case 13, the text-left probe's case 2); otherwise its own. docx4j `paragraphPropertiesOf`.
154
+ */
155
+ paragraphPropertiesOf(p) {
156
+ var _a, _b, _c;
157
+ if (!this.marksGone.has(p))
158
+ return p.pPr;
159
+ const parent = p.PARENT;
160
+ const container = listOf(parent);
161
+ const k = container ? container.findIndex((item) => valueOf(item) === p) : -1;
162
+ if (!container || k < 0)
163
+ return p.pPr;
164
+ const next = this.nextBlock(container, k);
165
+ if (typeNameOf(next) === 'org_docx4j_wml.P')
166
+ return p.pPr; // a join: the walk takes the chain's last
167
+ if (next && HOLDER_TYPES.has((_a = typeNameOf(next)) !== null && _a !== void 0 ? _a : '')) {
168
+ for (const o of (_b = childrenOf(next)) !== null && _b !== void 0 ? _b : []) {
169
+ if (typeNameOf(o) === 'org_docx4j_wml.P')
170
+ return o.value.pPr;
171
+ if (typeNameOf(o) === 'org_docx4j_wml.Tbl')
172
+ break;
173
+ }
174
+ }
175
+ if (next === undefined && SDT_CONTENTS.has((_c = parent === null || parent === void 0 ? void 0 : parent.TYPE_NAME) !== null && _c !== void 0 ? _c : ''))
176
+ return undefined; // a bare mark, text or not (the probe's case 2)
177
+ return p.pPr;
178
+ }
179
+ /**
180
+ * A table whose every row this view removes is gone with them, as the resolution removes an emptied table
181
+ * (check 54 case 6: a deletion from a heading across a whole table joins the heading with the paragraph after it).
182
+ */
183
+ emptiedTable(tbl) {
184
+ var _a;
185
+ let rows = false;
186
+ for (const item of ((_a = tbl.content) !== null && _a !== void 0 ? _a : [])) {
187
+ if (typeNameOf(item) === 'org_docx4j_wml.Tr') {
188
+ rows = true;
189
+ if (!this.removed.has(item.value))
190
+ return false;
191
+ }
192
+ else if (!isRangeMarker(item))
193
+ return false;
194
+ }
195
+ return rows;
196
+ }
197
+ /** The block after `p` in its list, past range markers and what this view removes; undefined at the end. */
198
+ nextBlockAfter(p) {
199
+ const container = listOf(p.PARENT);
200
+ const k = container ? container.findIndex((item) => valueOf(item) === p) : -1;
201
+ return container && k >= 0 ? this.nextBlock(container, k) : undefined;
202
+ }
203
+ nextBlock(container, k) {
204
+ for (let i = k + 1; i < container.length; i++) {
205
+ const item = container[i];
206
+ if (isRangeMarker(item) || this.removes(item))
207
+ continue;
208
+ return valueOf(item);
209
+ }
210
+ return undefined;
211
+ }
212
+ /** Whether a content control or custom XML element is gone with its content left in its place (one inserted, rejected). */
213
+ unwraps(item) {
214
+ const v = valueOf(item);
215
+ return v !== undefined && v !== null && this.unwrapped.has(v);
216
+ }
217
+ /**
218
+ * Whether a paragraph's mark is gone in this view: a deletion accepted, an insertion rejected, a move's
219
+ * mark on the side not kept. Such a paragraph joins the next one in its list, past range markers and
220
+ * what this view removes, when that is a paragraph; with no paragraph next only the mark goes.
221
+ */
222
+ removesMark(p) {
223
+ return p !== undefined && (this.marksGone.has(p) || this.movedMarksGone.has(p));
224
+ }
225
+ /**
226
+ * Whether a comment goes in this view, entry and reference: one whose range started on a revision taken
227
+ * away, or whose markers lie either side of one, once nothing with text is left in its range (CR-002
228
+ * section 54).
229
+ */
230
+ removesComment(id) {
231
+ return id !== undefined && id !== null && this.commentsGone.has(Number(id));
232
+ }
233
+ // --- the plan, change by change, as the resolution resolves each ----------------------------
234
+ plan(change) {
235
+ const t = change.target;
236
+ switch (t.kind) {
237
+ case 'run': {
238
+ // a move is replayed, unless its story has no piece for it (a text box's, whose paragraphs' story is
239
+ // the body around it): then the resolution takes it as the plain revision it stands for
240
+ if ((t.revision === 'moveFrom' || t.revision === 'moveTo') && !this.unreplayed.has(change))
241
+ return;
242
+ const kept = (t.revision === 'ins' || t.revision === 'moveTo') === this.accepted;
243
+ if (!kept)
244
+ this.removeRevision(t.element, t.owner);
245
+ return;
246
+ }
247
+ case 'mark':
248
+ if (change.paragraph && (t.mark === 'ins') !== this.accepted)
249
+ this.marksGone.add(change.paragraph.p);
250
+ return;
251
+ case 'row':
252
+ if ((t.row === 'ins') === this.accepted) {
253
+ for (const inner of t.inner)
254
+ this.plan(inner);
255
+ }
256
+ else
257
+ this.removed.add(t.tr.value);
258
+ return;
259
+ case 'group':
260
+ for (const piece of t.pieces)
261
+ this.plan(piece);
262
+ return;
263
+ case 'field':
264
+ // Word's inserted field: rejected, the whole field goes, its separator and result too
265
+ for (const el of t.span) {
266
+ if (revisionKindOf(el) === 'ins') {
267
+ if (!this.accepted)
268
+ this.removeRevision(el, t.owner);
269
+ }
270
+ else if (!this.accepted && typeNameOf(el) === 'org_docx4j_wml.R')
271
+ this.removed.add(el.value);
272
+ }
273
+ return;
274
+ case 'mathRun':
275
+ if ((t.revision === 'ins') !== this.accepted)
276
+ this.removed.add(t.item.value);
277
+ return;
278
+ case 'mathStructure':
279
+ if ((t.revision === 'ins') !== this.accepted && t.structure)
280
+ this.removed.add(t.structure.value);
281
+ return;
282
+ case 'cell':
283
+ if ((t.cell === 'ins') !== this.accepted)
284
+ this.removed.add(t.tc.value);
285
+ return;
286
+ case 'holder':
287
+ // a content control inserted keeps its content either way; rejected, the control itself goes. One deleted
288
+ // whole (Word's customXmlDelRange form), accepted, goes with everything in it; rejected, it stays (docx4j
289
+ // CR-043 section 17, check 54 cases 15 and 17)
290
+ if (t.revision === 'ins') {
291
+ if (!this.accepted)
292
+ this.unwrapped.add(t.holder.value);
293
+ }
294
+ else if (this.accepted)
295
+ this.removed.add(t.holder.value);
296
+ return;
297
+ default:
298
+ // property records change no text
299
+ }
300
+ }
301
+ /**
302
+ * `removeRevision`: the revision goes, and the comments whose range started on it, or whose markers
303
+ * lie either side of it in its list, are candidates; so is one with a marker in its list on the
304
+ * revision's side and the other in another paragraph (docx4j's U23).
305
+ */
306
+ removeRevision(item, owner) {
307
+ this.removed.add(item.value);
308
+ const inner = listOf(item.value);
309
+ const at = owner.indexOf(item);
310
+ if (!inner || at < 0)
311
+ return;
312
+ for (const o of inner) {
313
+ if (localName(o) !== 'commentRangeStart')
314
+ continue;
315
+ const id = commentIdOf(o);
316
+ if (markerAt(owner, at + 1, owner.length, 'commentRangeEnd', id) >= 0)
317
+ this.commentCandidates.push(new CommentCandidate(this, id, owner, at));
318
+ else
319
+ this.spanCandidates.push(new SpanCandidate(this, id, item, owner, at, true));
320
+ }
321
+ for (let s = 0; s < at; s++) {
322
+ if (localName(owner[s]) !== 'commentRangeStart')
323
+ continue;
324
+ const id = commentIdOf(owner[s]);
325
+ if (markerAt(owner, s + 1, owner.length, 'commentRangeEnd', id) < 0)
326
+ this.spanCandidates.push(new SpanCandidate(this, id, item, owner, s + 1, true));
327
+ else if (markerAt(owner, at + 1, owner.length, 'commentRangeEnd', id) >= 0)
328
+ this.commentCandidates.push(new CommentCandidate(this, id, owner, s));
329
+ }
330
+ for (let e = at + 1; e < owner.length; e++) {
331
+ if (localName(owner[e]) === 'commentRangeEnd' && markerAt(owner, 0, e, 'commentRangeStart', commentIdOf(owner[e])) < 0) {
332
+ this.spanCandidates.push(new SpanCandidate(this, commentIdOf(owner[e]), item, owner, e, false));
333
+ }
334
+ }
335
+ }
336
+ /** Records a list member gone (a move's half, the text typed into a rejected move's destination). */
337
+ remove(value) {
338
+ this.removed.add(value);
339
+ }
340
+ /** Records a paragraph mark gone. */
341
+ markGone(p) {
342
+ this.marksGone.add(p);
343
+ }
344
+ /** Records a moved paragraph's mark gone. */
345
+ movedMarkGone(p) {
346
+ this.movedMarksGone.add(p);
347
+ }
348
+ /** Whether run-level content has text in this view, once its removals are made. */
349
+ hasText(item) {
350
+ var _a;
351
+ const v = valueOf(item);
352
+ if (v === undefined || v === null || this.removed.has(v))
353
+ return false;
354
+ if (typeNameOf(v) === 'org_docx4j_wml.R')
355
+ return ((_a = v.content) !== null && _a !== void 0 ? _a : []).some((o) => itemTextOf(o) !== undefined);
356
+ const items = listOf(v);
357
+ return items !== undefined && items.some((o) => this.hasText(o));
358
+ }
359
+ /**
360
+ * Whether anything is left in a paragraph once this view's removals are made: the resolution removes
361
+ * an emptied moved paragraph and joins one that is not. A comment's range markers inside a revision
362
+ * taken away stay behind it.
363
+ */
364
+ remainsIn(p) {
365
+ var _a;
366
+ for (const item of ((_a = p.content) !== null && _a !== void 0 ? _a : [])) {
367
+ const v = item.value;
368
+ if (!this.removed.has(v))
369
+ return true;
370
+ const inner = listOf(v);
371
+ if (inner && revisionKindOf(item) !== undefined && inner.some((o) => localName(o) === 'commentRangeStart' || localName(o) === 'commentRangeEnd'))
372
+ return true;
373
+ }
374
+ return false;
375
+ }
376
+ }
377
+ /** A comment whose range held a revision taken away, and where its range's text begins to be looked for. */
378
+ class CommentCandidate {
379
+ constructor(view, id, owner, at) {
380
+ this.view = view;
381
+ this.id = id;
382
+ this.owner = owner;
383
+ this.at = at;
384
+ }
385
+ /** `rangeIsEmpty`, on what this view leaves: nothing with text before the range's end, in the same list. */
386
+ rangeEmpty() {
387
+ for (let i = this.at + 1; i < this.owner.length; i++) {
388
+ const item = this.owner[i];
389
+ if (localName(item) === 'commentRangeEnd' && commentIdOf(item) === this.id)
390
+ return true;
391
+ if (this.view.hasText(item))
392
+ return false;
393
+ }
394
+ return false; // the end is elsewhere: text may be
395
+ }
396
+ }
397
+ /**
398
+ * A comment whose range held a revision taken away, its start and end in different paragraphs of one
399
+ * list: gone, as `settleSpanningComments` judges it once the joins are made, when every paragraph from
400
+ * the start's up to the end's loses its mark (so that they join), with nothing between them but range
401
+ * markers and what this view removes, and nothing with text in the range.
402
+ */
403
+ class SpanCandidate {
404
+ constructor(view, id, revision, owner, at, startHere) {
405
+ this.view = view;
406
+ this.id = id;
407
+ this.revision = revision;
408
+ this.owner = owner;
409
+ this.at = at;
410
+ this.startHere = startHere;
411
+ }
412
+ rangeEmpty() {
413
+ const here = this.revision.value.PARENT;
414
+ if (typeNameOf(here) !== 'org_docx4j_wml.P' || here.content !== this.owner)
415
+ return false;
416
+ const container = listOf(here.PARENT);
417
+ if (!container)
418
+ return false;
419
+ let k = container.findIndex((el) => el.value === here);
420
+ if (k < 0)
421
+ return false;
422
+ const view = this.view;
423
+ const contentOf = (p) => { var _a; return ((_a = p.content) !== null && _a !== void 0 ? _a : []); };
424
+ if (this.startHere) {
425
+ for (let i = this.at; i < this.owner.length; i++)
426
+ if (view.hasText(this.owner[i]))
427
+ return false;
428
+ let p = here;
429
+ for (;;) {
430
+ if (!view.removesMark(p))
431
+ return false; // a mark left between start and end (U24)
432
+ k++;
433
+ while (k < container.length && this.skipped(container[k])) {
434
+ if (this.isMarker(container[k], 'commentRangeEnd'))
435
+ return true;
436
+ k++;
437
+ }
438
+ if (k >= container.length || typeNameOf(container[k]) !== 'org_docx4j_wml.P')
439
+ return false;
440
+ p = container[k].value;
441
+ const items = contentOf(p);
442
+ const end = markerAt(items, 0, items.length, 'commentRangeEnd', this.id);
443
+ const to = end < 0 ? items.length : end;
444
+ for (let i = 0; i < to; i++)
445
+ if (view.hasText(items[i]))
446
+ return false;
447
+ if (end >= 0)
448
+ return true;
449
+ }
450
+ }
451
+ for (let i = 0; i < this.at; i++)
452
+ if (view.hasText(this.owner[i]))
453
+ return false;
454
+ for (;;) {
455
+ k--;
456
+ while (k >= 0 && this.skipped(container[k])) {
457
+ if (this.isMarker(container[k], 'commentRangeStart'))
458
+ return true;
459
+ k--;
460
+ }
461
+ if (k < 0 || typeNameOf(container[k]) !== 'org_docx4j_wml.P')
462
+ return false;
463
+ const p = container[k].value;
464
+ if (!view.removesMark(p))
465
+ return false; // a mark left between start and end (U24)
466
+ const items = contentOf(p);
467
+ const start = markerAt(items, 0, items.length, 'commentRangeStart', this.id);
468
+ for (let i = start + 1; i < items.length; i++)
469
+ if (view.hasText(items[i]))
470
+ return false;
471
+ if (start >= 0)
472
+ return true;
473
+ }
474
+ }
475
+ /** A range marker between paragraphs, which a join carries along, or a member this view removes. */
476
+ skipped(item) {
477
+ const name = localName(item);
478
+ return name.endsWith('RangeStart') || name.endsWith('RangeEnd') || name === 'bookmarkStart' || name === 'bookmarkEnd'
479
+ || name === 'permStart' || name === 'permEnd' || name === 'proofErr'
480
+ || (typeNameOf(item) !== 'org_docx4j_wml.P' && this.view.removes(item));
481
+ }
482
+ isMarker(item, kind) {
483
+ return localName(item) === kind && commentIdOf(item) === this.id;
484
+ }
485
+ }
486
+ /**
487
+ * The moves of one story resolved as `Body.acceptAll` and `rejectAll` resolve them (`resolveMove`,
488
+ * `resolveRangelessHalf`, `dissolveBrokenMoves`): last half first; a half in a named range resolves its
489
+ * whole move, a half in none is an insertion or a deletion, and after a broken move what is left unpaired
490
+ * becomes the plain `w:ins` or `w:del` it stands for, resolved as such. docx4j `ResolvedView.MoveReplay`.
491
+ */
492
+ class MoveReplay {
493
+ constructor(view, story, halves) {
494
+ this.view = view;
495
+ this.halves = halves;
496
+ /** Pieces resolved, or turned plain: no longer move markup. */
497
+ this.done = new Set();
498
+ /** Halves and marks turned into plain revisions. */
499
+ this.plain = [];
500
+ this.pieces = movePiecesOf(story);
501
+ }
502
+ /** Replays the moves; returns the halves the story has no piece for. */
503
+ run() {
504
+ const missing = [];
505
+ for (let i = this.halves.length - 1; i >= 0; i--) {
506
+ const change = this.halves[i];
507
+ const t = change.target;
508
+ if (t.kind !== 'run')
509
+ continue;
510
+ const half = this.pieces.find((piece) => piece.kind === 'half' && piece.element === t.element);
511
+ if (!half || half.kind !== 'half') {
512
+ missing.push(change);
513
+ continue;
514
+ }
515
+ if (this.done.has(half))
516
+ continue;
517
+ if (half.names.length > 0)
518
+ this.named(half);
519
+ else
520
+ this.rangeless(half, change);
521
+ }
522
+ // what became plain is resolved as plain markup, in the next round
523
+ for (const piece of this.plain) {
524
+ const ins = piece.side === 'to';
525
+ if (ins === this.view.accepted)
526
+ continue;
527
+ if (piece.kind === 'half')
528
+ this.view.removeRevision(piece.element, piece.owner);
529
+ else if (piece.kind === 'mark')
530
+ this.view.markGone(piece.paragraph.value);
531
+ }
532
+ return missing;
533
+ }
534
+ live(piece) {
535
+ return !this.done.has(piece);
536
+ }
537
+ /** `resolveMove`. */
538
+ named(half) {
539
+ const name = half.names[0];
540
+ const ids = new Set();
541
+ for (const piece of this.pieces)
542
+ if (this.live(piece) && piece.kind === 'start' && piece.name === name)
543
+ ids.add(piece.id);
544
+ const mine = this.pieces.filter((piece) => this.live(piece) && ((piece.kind === 'start' && piece.name === name) || (piece.kind === 'end' && ids.has(piece.id))
545
+ || ((piece.kind === 'half' || piece.kind === 'mark' || piece.kind === 'inner') && piece.names.includes(name))));
546
+ const orphan = !mine.some((piece) => piece.side === 'from');
547
+ const keptFrom = !(this.view.accepted || orphan);
548
+ const broken = orphan || !mine.some((piece) => piece.side === 'to');
549
+ for (const piece of mine) {
550
+ this.done.add(piece);
551
+ if (piece.kind === 'inner' && piece.side === 'to' && keptFrom)
552
+ this.view.remove(piece.element.value);
553
+ if (piece.kind === 'half' && (piece.side === 'from') !== keptFrom)
554
+ this.view.remove(piece.element.value);
555
+ if (piece.kind === 'mark' && (piece.side === 'from') !== keptFrom)
556
+ this.view.movedMarkGone(piece.paragraph.value);
557
+ }
558
+ if (broken)
559
+ this.dissolveBroken();
560
+ }
561
+ /** `resolveRangelessHalf`. */
562
+ rangeless(half, change) {
563
+ const keep = (half.side === 'to') === this.view.accepted;
564
+ this.done.add(half);
565
+ if (!keep)
566
+ this.view.remove(half.element.value);
567
+ const paragraph = change.paragraph;
568
+ if (paragraph) {
569
+ for (const piece of this.pieces) {
570
+ if (!this.live(piece) || piece.kind !== 'mark' || piece.side !== half.side || piece.paragraph !== paragraph.element || piece.names.length > 0)
571
+ continue;
572
+ this.done.add(piece);
573
+ if (!keep)
574
+ this.view.movedMarkGone(piece.paragraph.value);
575
+ break;
576
+ }
577
+ }
578
+ this.dissolveBroken();
579
+ }
580
+ /** `dissolveBrokenMoves`: every half and mark that cannot be paired becomes plain. */
581
+ dissolveBroken() {
582
+ const named = { from: new Set(), to: new Set() };
583
+ for (const piece of this.pieces)
584
+ if (this.live(piece) && piece.kind === 'start')
585
+ named[piece.side].add(piece.name);
586
+ for (const piece of this.pieces) {
587
+ if (!this.live(piece) || (piece.kind !== 'half' && piece.kind !== 'mark'))
588
+ continue;
589
+ const other = named[piece.side === 'from' ? 'to' : 'from'];
590
+ if (piece.names.some((n) => other.has(n)))
591
+ continue;
592
+ this.done.add(piece);
593
+ this.plain.push(piece);
594
+ }
595
+ }
596
+ }
@@ -7,7 +7,9 @@ import { type ChangeTracker } from './tracking.mjs';
7
7
  import { type TableLayoutMode } from './tableColumns.mjs';
8
8
  /**
9
9
  * A subset of Office JS `Word.Table` over a `w:tbl`. Rows are read through row-level content
10
- * controls (an OpenDoPE repeat wraps its `w:tr` in a `w:sdt`), so `rows` is what Word shows.
10
+ * controls (an OpenDoPE repeat wraps its `w:tr` in a `w:sdt`), and through the selected branch of a
11
+ * kept row-level `mc:AlternateContent` (CR-013 phase 2), so `rows` is what Word shows. A table, row or
12
+ * cell in a branch is read-only (D4), and so is a write that would reach one.
11
13
  */
12
14
  export declare class Table {
13
15
  /** The `w:tbl` element pair. */
@@ -28,6 +30,13 @@ export declare class Table {
28
30
  get index(): number;
29
31
  get rowCount(): number;
30
32
  get rows(): TableRow[];
33
+ /**
34
+ * The table's range (Office JS `Table.getRange`; CR-014 phase 1): 'Whole' from its first cell's start to its
35
+ * last cell's end, its text the table's in `body.text`'s form, every row ended `\r\n` as Word 365 gives it
36
+ * (check 52); 'Start' and 'End' collapsed at those two ends, and 'After' at the start of the paragraph after
37
+ * the table.
38
+ */
39
+ getRange(location?: 'Whole' | 'Start' | 'End' | 'After'): Range;
31
40
  /** The text of every cell, row by row (Office JS values). */
32
41
  get values(): string[][];
33
42
  set values(values: string[][]);
@@ -82,11 +91,15 @@ export declare class Table {
82
91
  get changeTracker(): ChangeTracker | undefined;
83
92
  /** The cell this table is nested in, if any (extension). */
84
93
  get parentTableCell(): TableCell | undefined;
85
- /** The text of the table: a line per paragraph, as docx4j TextUtils (extension). */
94
+ /** The text of the table: a line per paragraph, each `Paragraph.text` (extension; CR-012 phase 4). */
86
95
  get text(): string;
87
96
  /** The column widths in twips, from the grid or from the first row (extension). */
88
97
  columnWidths(): number[];
89
98
  private tblPr;
99
+ /** True for a table in the selected branch of a kept block-level `mc:AlternateContent` (CR-013 phase 2): read-only (D4). */
100
+ get inBranch(): boolean;
101
+ /** Refuses a write to a table in a branch (CR-013 D4). Internal: the table's mutators call it first. */
102
+ assertWritable(): void;
90
103
  }
91
104
  /** A subset of Office JS `Word.TableRow` over a `w:tr`. */
92
105
  export declare class TableRow {
@@ -112,6 +125,12 @@ export declare class TableRow {
112
125
  insertRows(location: 'Before' | 'After', rowCount: number, values?: string[][]): TableRow[];
113
126
  /** Removes the row; tracked, it stays and takes a `w:trPr/w:del` (CR-002 phase F). */
114
127
  delete(): void;
128
+ /** True for a row in a branch of a kept `mc:AlternateContent`, or in a table in one (CR-013 phase 2): read-only (D4). */
129
+ get inBranch(): boolean;
130
+ /** Refuses a write to a row in a branch (CR-013 D4). Internal. */
131
+ assertWritable(): void;
132
+ /** Refuses `values` of `count` cells where the row, or one of those cells, is in a branch. Internal. */
133
+ assertValuesWritable(count: number): void;
115
134
  private trPrItem;
116
135
  }
117
136
  /** A subset of Office JS `Word.TableCell` over a `w:tc`: a body of its own, plus its position. */
@@ -134,7 +153,10 @@ export declare class TableCell {
134
153
  get body(): Body;
135
154
  get paragraphs(): Paragraph[];
136
155
  get tables(): Table[];
137
- /** The cell's text, a line per paragraph. */
156
+ /**
157
+ * The cell's text as Office JS's `tableCell.value` gives it: its body's text (`Body.text`), its paragraphs'
158
+ * `Paragraph.text` a mark `\r` apart (check 51: `value`, `values` and `body.text` alike).
159
+ */
138
160
  get text(): string;
139
161
  /** Office JS TableCell.value: the text, replaced as one paragraph when set. */
140
162
  get value(): string;
@@ -157,6 +179,10 @@ export declare class TableCell {
157
179
  insertColumns(location: 'Before' | 'After', columnCount: number, values?: string[][]): TableCell[][];
158
180
  /** Removes the grid columns this cell covers (Office JS `TableCell.deleteColumn`); tracked as `Table.deleteColumns` is. */
159
181
  deleteColumn(): void;
182
+ /** True for a cell in a branch of a kept `mc:AlternateContent`, or in a row or table in one (CR-013 phase 2): read-only (D4). */
183
+ get inBranch(): boolean;
184
+ /** Refuses a write to a cell in a branch (CR-013 D4); its body's writes refuse too. Internal. */
185
+ assertWritable(): void;
160
186
  /** Office JS TableCell.columnWidth, the same value. */
161
187
  get columnWidth(): number;
162
188
  set columnWidth(points: number);