@docx4j/core-ts 0.5.0 → 0.7.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 (207) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +92 -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 +507 -150
  25. package/dist/model/content/Comment.d.mts +23 -5
  26. package/dist/model/content/Comment.mjs +207 -26
  27. package/dist/model/content/ContentControl.d.mts +198 -19
  28. package/dist/model/content/ContentControl.mjs +672 -99
  29. package/dist/model/content/Font.d.mts +70 -17
  30. package/dist/model/content/Font.mjs +119 -36
  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.d.mts +6 -3
  34. package/dist/model/content/List.mjs +18 -8
  35. package/dist/model/content/Paragraph.d.mts +200 -14
  36. package/dist/model/content/Paragraph.mjs +898 -82
  37. package/dist/model/content/Range.d.mts +227 -12
  38. package/dist/model/content/Range.mjs +785 -59
  39. package/dist/model/content/ResolvedView.d.mts +104 -0
  40. package/dist/model/content/ResolvedView.mjs +596 -0
  41. package/dist/model/content/Table.d.mts +29 -3
  42. package/dist/model/content/Table.mjs +135 -49
  43. package/dist/model/content/TrackedChange.d.mts +174 -15
  44. package/dist/model/content/TrackedChange.mjs +734 -170
  45. package/dist/model/content/comments.d.mts +20 -6
  46. package/dist/model/content/comments.mjs +67 -57
  47. package/dist/model/content/generalException.d.mts +18 -0
  48. package/dist/model/content/generalException.mjs +24 -0
  49. package/dist/model/content/index.d.mts +10 -3
  50. package/dist/model/content/index.mjs +10 -2
  51. package/dist/model/content/mathText.d.mts +21 -0
  52. package/dist/model/content/mathText.mjs +267 -0
  53. package/dist/model/content/officeText.d.mts +27 -0
  54. package/dist/model/content/officeText.mjs +74 -0
  55. package/dist/model/content/ooxml.mjs +12 -1
  56. package/dist/model/content/outline.d.mts +5 -0
  57. package/dist/model/content/outline.mjs +13 -0
  58. package/dist/model/content/paraIds.d.mts +5 -0
  59. package/dist/model/content/paraIds.mjs +54 -0
  60. package/dist/model/content/placeholders.d.mts +110 -0
  61. package/dist/model/content/placeholders.mjs +253 -0
  62. package/dist/model/content/search.d.mts +74 -0
  63. package/dist/model/content/search.mjs +255 -9
  64. package/dist/model/content/spanEdits.d.mts +159 -0
  65. package/dist/model/content/spanEdits.mjs +728 -0
  66. package/dist/model/content/story.d.mts +47 -0
  67. package/dist/model/content/story.mjs +95 -0
  68. package/dist/model/content/tableColumns.d.mts +1 -1
  69. package/dist/model/content/tableColumns.mjs +108 -80
  70. package/dist/model/content/tableRevisions.d.mts +11 -3
  71. package/dist/model/content/tableRevisions.mjs +72 -42
  72. package/dist/model/content/tableRules.d.mts +30 -0
  73. package/dist/model/content/tableRules.mjs +102 -0
  74. package/dist/model/content/textBoxes.d.mts +18 -0
  75. package/dist/model/content/textBoxes.mjs +105 -0
  76. package/dist/model/content/trackedChangeFilter.d.mts +39 -0
  77. package/dist/model/content/trackedChangeFilter.mjs +81 -0
  78. package/dist/model/content/tracking.d.mts +63 -6
  79. package/dist/model/content/tracking.mjs +242 -22
  80. package/dist/model/content/tree.d.mts +172 -24
  81. package/dist/model/content/tree.mjs +328 -54
  82. package/dist/model/content/wordRange.d.mts +48 -0
  83. package/dist/model/content/wordRange.mjs +97 -0
  84. package/dist/model/customxml/CustomXmlPartCollection.d.mts +30 -1
  85. package/dist/model/customxml/CustomXmlPartCollection.mjs +81 -12
  86. package/dist/model/customxml/XmlMapping.d.mts +32 -8
  87. package/dist/model/customxml/XmlMapping.mjs +64 -10
  88. package/dist/model/customxml/bindings.d.mts +33 -4
  89. package/dist/model/customxml/bindings.mjs +171 -45
  90. package/dist/model/customxml/index.d.mts +1 -0
  91. package/dist/model/customxml/index.mjs +1 -0
  92. package/dist/model/customxml/kinds.d.mts +8 -3
  93. package/dist/model/customxml/kinds.mjs +26 -5
  94. package/dist/model/customxml/opendope.d.mts +4 -1
  95. package/dist/model/customxml/opendope.mjs +9 -6
  96. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  97. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  98. package/dist/model/customxml/pictures.d.mts +4 -3
  99. package/dist/model/customxml/pictures.mjs +22 -8
  100. package/dist/model/customxml/storeItems.d.mts +57 -0
  101. package/dist/model/customxml/storeItems.mjs +122 -0
  102. package/dist/model/customxml/xhtml.mjs +23 -22
  103. package/dist/model/dateZone.d.mts +25 -0
  104. package/dist/model/dateZone.mjs +57 -0
  105. package/dist/model/index.d.mts +3 -0
  106. package/dist/model/index.mjs +5 -0
  107. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  108. package/dist/model/listnumbering/Emulator.mjs +63 -9
  109. package/dist/model/properties/PropertyResolver.d.mts +74 -2
  110. package/dist/model/properties/PropertyResolver.mjs +133 -5
  111. package/dist/model/properties/catalogue.d.mts +19 -5
  112. package/dist/model/properties/catalogue.mjs +41 -15
  113. package/dist/model/properties/index.d.mts +1 -1
  114. package/dist/model/properties/log.d.mts +1 -1
  115. package/dist/model/properties/log.mjs +5 -5
  116. package/dist/model/properties/styleUtil.d.mts +3 -1
  117. package/dist/model/properties/styleUtil.mjs +20 -24
  118. package/dist/model/properties/table.mjs +4 -2
  119. package/dist/model/text/CaseMapping.d.mts +38 -0
  120. package/dist/model/text/CaseMapping.mjs +86 -0
  121. package/dist/model/text/Extractor.d.mts +349 -0
  122. package/dist/model/text/Extractor.mjs +2406 -0
  123. package/dist/model/text/LinkTargets.d.mts +45 -0
  124. package/dist/model/text/LinkTargets.mjs +170 -0
  125. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  126. package/dist/model/text/MarkdownExporter.mjs +255 -0
  127. package/dist/model/text/PlainText.d.mts +29 -0
  128. package/dist/model/text/PlainText.mjs +542 -0
  129. package/dist/model/text/TextContext.d.mts +256 -0
  130. package/dist/model/text/TextContext.mjs +600 -0
  131. package/dist/model/text/TextOptions.d.mts +233 -0
  132. package/dist/model/text/TextOptions.mjs +419 -0
  133. package/dist/model/text/TextResult.d.mts +621 -0
  134. package/dist/model/text/TextResult.mjs +629 -0
  135. package/dist/model/text/Texts.d.mts +99 -0
  136. package/dist/model/text/Texts.mjs +187 -0
  137. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  138. package/dist/model/text/WmlToMarkdown.mjs +936 -0
  139. package/dist/model/text/caseMapping.generated.d.mts +7 -0
  140. package/dist/model/text/caseMapping.generated.mjs +214 -0
  141. package/dist/model/text/commonmark.d.mts +121 -0
  142. package/dist/model/text/commonmark.mjs +655 -0
  143. package/dist/model/text/index.d.mts +8 -0
  144. package/dist/model/text/index.mjs +9 -0
  145. package/dist/model/text/normalize.d.mts +8 -0
  146. package/dist/model/text/normalize.mjs +13 -0
  147. package/dist/model/text/outline.d.mts +4 -0
  148. package/dist/model/text/outline.mjs +71 -0
  149. package/dist/model/wordIntegers.d.mts +29 -0
  150. package/dist/model/wordIntegers.mjs +78 -0
  151. package/dist/office-js/document.mjs +15 -1
  152. package/dist/office-js/fragment.d.mts +7 -5
  153. package/dist/office-js/fragment.mjs +63 -14
  154. package/dist/office-js/proxy.d.mts +8 -0
  155. package/dist/office-js/proxy.mjs +29 -0
  156. package/dist/office-js/run.mjs +2 -0
  157. package/dist/office-js/supported.generated.mjs +16 -0
  158. package/dist/office-js/toApiScript.mjs +29 -12
  159. package/dist/opc/DirectoryPartStore.d.mts +6 -2
  160. package/dist/opc/DirectoryPartStore.mjs +11 -4
  161. package/dist/opc/FlatOpcPartStore.d.mts +4 -2
  162. package/dist/opc/FlatOpcPartStore.mjs +11 -8
  163. package/dist/opc/Load.d.mts +32 -0
  164. package/dist/opc/Load.mjs +115 -5
  165. package/dist/opc/PartStore.d.mts +34 -1
  166. package/dist/opc/PartStore.mjs +71 -8
  167. package/dist/opc/Save.d.mts +32 -0
  168. package/dist/opc/Save.mjs +110 -4
  169. package/dist/opc/ZipPartStore.d.mts +4 -2
  170. package/dist/opc/ZipPartStore.mjs +12 -7
  171. package/dist/opc/exceptions.d.mts +140 -0
  172. package/dist/opc/exceptions.mjs +108 -0
  173. package/dist/opc/index.d.mts +8 -5
  174. package/dist/opc/index.mjs +5 -3
  175. package/dist/opc/mce/preprocessor.d.mts +141 -5
  176. package/dist/opc/mce/preprocessor.mjs +119 -18
  177. package/dist/opc/mce/understood.d.mts +3 -11
  178. package/dist/opc/mce/understood.mjs +27 -23
  179. package/dist/opc/repair/breaks.d.mts +23 -0
  180. package/dist/opc/repair/breaks.mjs +288 -0
  181. package/dist/opc/repair/hosts.d.mts +12 -0
  182. package/dist/opc/repair/hosts.mjs +33 -0
  183. package/dist/opc/repair/mainRoot.d.mts +19 -0
  184. package/dist/opc/repair/mainRoot.mjs +168 -0
  185. package/dist/opc/repair/unknownElements.d.mts +8 -0
  186. package/dist/opc/repair/unknownElements.mjs +180 -0
  187. package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
  188. package/dist/opc/repair/wmlNames.generated.mjs +80 -0
  189. package/dist/opc/skipped.d.mts +50 -0
  190. package/dist/opc/skipped.mjs +140 -0
  191. package/dist/packages/OpcPackage.d.mts +110 -4
  192. package/dist/packages/OpcPackage.mjs +123 -7
  193. package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
  194. package/dist/packages/WordprocessingMLPackage.mjs +158 -21
  195. package/dist/packages/index.d.mts +1 -1
  196. package/dist/parts/DefaultXmlPart.mjs +2 -2
  197. package/dist/parts/Part.d.mts +14 -2
  198. package/dist/parts/RelationshipsPart.d.mts +15 -0
  199. package/dist/parts/RelationshipsPart.mjs +66 -1
  200. package/dist/parts/XmlPart.d.mts +63 -32
  201. package/dist/parts/XmlPart.mjs +240 -96
  202. package/dist/parts/wml/comments.mjs +30 -0
  203. package/dist/parts/wml/index.d.mts +12 -1
  204. package/dist/parts/wml/index.mjs +37 -1
  205. package/dist/xml/dom.d.mts +7 -0
  206. package/dist/xml/dom.mjs +18 -0
  207. package/package.json +2 -2
@@ -26,6 +26,11 @@ export interface TrackingHost {
26
26
  readonly author: Author;
27
27
  /** A fixed date for new revisions; `undefined` means now, read once per revision. */
28
28
  readonly trackedChangeDate?: Date | undefined;
29
+ /**
30
+ * The zone a stamp's `w:date` wall-clock fields are written in, and a `w:date` without `dateUtc` read in: the
31
+ * package's `dateTimeZone`, an IANA id; undefined is the runtime's zone (CR-018, the portfolio's date rule).
32
+ */
33
+ readonly dateTimeZone?: string | undefined;
29
34
  /** The trees to scan for the highest annotation id in use: the parts already unmarshalled. */
30
35
  markupRoots(): object[];
31
36
  /**
@@ -73,19 +78,43 @@ export declare function dateOf(cal: wml.XmlCalendar | undefined): Date | undefin
73
78
  /**
74
79
  * A revision's `w:date` as Word writes it: the local wall-clock time, with a `Z` that does not mean
75
80
  * UTC (CR-002 section 29, check 23: Office JS read `01:00:00Z` as 15:00 UTC the day before, at
76
- * UTC+10; Word's own files carry the true UTC beside it in `w16du:dateUtc`). "Local" is this
77
- * process's time zone, as it is the add-in's for Office JS.
81
+ * UTC+10; Word's own files carry the true UTC beside it in `w16du:dateUtc`). "Local" is `zone`, the
82
+ * package's `dateTimeZone` (CR-018), else this process's time zone, which is the add-in's for Office JS.
78
83
  */
79
- export declare function wordCalendarOf(date: Date): wml.XmlCalendar;
84
+ export declare function wordCalendarOf(date: Date, zone?: string): wml.XmlCalendar;
80
85
  /**
81
86
  * A revision's date as Word means it: `w16du:dateUtc` when there is one, which is UTC; else
82
- * `w:date` read as local wall-clock time, its `Z` notwithstanding, as Office JS reads it (check 23).
87
+ * `w:date` read as local wall-clock time, its `Z` notwithstanding, as Office JS reads it (check 23),
88
+ * in `zone` (the package's `dateTimeZone`, CR-018), else the runtime's zone.
83
89
  * A `w:date` with a non-zero offset, which Word does not write, is read as it says.
84
90
  */
85
91
  export declare function revisionDateOf(value: {
86
92
  date?: wml.XmlCalendar;
87
93
  dateUtc?: wml.XmlCalendar;
88
- }): Date | undefined;
94
+ }, zone?: string): Date | undefined;
95
+ /** A stamp's fields as written: an `XmlCalendar`, or its lexical form as a reader may hold it. */
96
+ type Stamp = wml.XmlCalendar | string | null | undefined;
97
+ /**
98
+ * The author's local time of a revision's or comment's `w:date`: its date and time as stored, in ISO 8601's extended form
99
+ * with no designator (`2026-10-31T11:00:00`), any designator not read, a missing time 00:00:00, fractions of a second
100
+ * dropped; undefined for no date. Word writes the author's wall clock labelled `Z` (CR-002 section 29), and shows it as it
101
+ * is. docx4j `RevisionDates.localTime`.
102
+ */
103
+ export declare function authorLocalTime(date: Stamp): string | undefined;
104
+ /**
105
+ * The author's UTC offset in minutes: `w:date` less `dateUtc` (`w16du:dateUtc`, or a comment's `w16cex:dateUtc`), where both
106
+ * are present and differ by a whole number of quarter hours from -12:00 to +14:00, as a clock's offset does; else
107
+ * undefined, so a pair a producer wrote inconsistently gives no offset rather than a wrong one. `dateUtc` without a zone is
108
+ * UTC, and one with an offset is moved by it. docx4j `RevisionDates.offset`.
109
+ */
110
+ export declare function authorOffsetMinutes(date: Stamp, dateUtc: Stamp): number | undefined;
111
+ /**
112
+ * A revision's or comment's stamp as WD REQ-702 writes it: the author's local time (`authorLocalTime`), with the author's
113
+ * offset after it where it is known (`2026-10-31T11:00:00+11:00`; `+00:00` for UTC, never `Z`); `dateUtc` with `Z` where
114
+ * there is no `w:date`; undefined where there is neither. The `Z` Word stores on `w:date` is never written, and nothing is
115
+ * converted to another zone. docx4j `RevisionDates.text`.
116
+ */
117
+ export declare function revisionDateText(date: Stamp, dateUtc: Stamp): string | undefined;
89
118
  /** Properties compared as values: keys sorted, `PARENT`, `TYPE_NAME` and absent values left out. */
90
119
  export declare function canonical(value: unknown): string;
91
120
  /** The part a tracker writes into, as far as the tracker needs it: its tree, once unmarshalled. */
@@ -143,7 +172,7 @@ export declare class ChangeTracker {
143
172
  nextId(): number;
144
173
  /**
145
174
  * The `w:id`, `w:author` and `w:date` a new revision carries, `w:date` in Word's local wall-clock
146
- * convention (`wordCalendarOf`), and `w16du:dateUtc`, the true UTC, as Word writes them both. The
175
+ * convention (`wordCalendarOf`, in the host's `dateTimeZone`), and `w16du:dateUtc`, the true UTC, as Word writes them both. The
147
176
  * part's root is made to list `w16du` in `mc:Ignorable` first (`declareDateUtc`): a consumer that
148
177
  * does not know `w16du` must reject it unless it is declared ignorable. A tracker bound to no part -
149
178
  * the package's own - writes `w:date` alone (CR-002 section 29).
@@ -176,6 +205,14 @@ export declare class ChangeTracker {
176
205
  settleRPrChange(run: {
177
206
  rPr?: wml.RPr;
178
207
  }): void;
208
+ /**
209
+ * Records a paragraph mark's formatting as it is now in its `w:rPrChange`, once: what a tracked `font`
210
+ * write over a range holding the mark writes (check 52 case 56: `<w:rPrChange><w:rPr/></w:rPrChange>`
211
+ * for a mark that had no formatting). The mark's own revisions (inserted, deleted) are not its formatting.
212
+ */
213
+ recordMarkRPrChange(rPr: wml.ParaRPr): void;
214
+ /** `settleRPrChange` for a paragraph mark: its `w:rPrChange` goes where its formatting is back to what it recorded. */
215
+ settleMarkRPrChange(p: wml.P): void;
179
216
  /** Records the paragraph's properties as they are now in `w:pPrChange`, once. */
180
217
  recordPPrChange(pPr: wml.PPr): void;
181
218
  /** `w:pPr/w:rPr/w:ins`: the paragraph mark is an insertion. */
@@ -244,6 +281,13 @@ export declare function holderItemsOf(value: object): Element[] | undefined;
244
281
  * pairs, so that the ids run in document order as Word's do.
245
282
  */
246
283
  export declare function markHolderInserted(tracker: ChangeTracker, holder: Element, owner: Element[], inside: () => void): void;
284
+ /**
285
+ * A content control or custom XML element deleted under tracking, as Word writes it (check 54 cases 15 and 17, a
286
+ * range across paragraphs holding a whole control): `markHolderInserted`'s form with `w:customXmlDelRangeStart` and
287
+ * `w:customXmlDelRangeEnd`, its content marked deleted between the two pairs (`inside`). Accepting takes the element
288
+ * away; rejecting, the markers (`TrackedChange`'s `holder` target).
289
+ */
290
+ export declare function markHolderDeleted(tracker: ChangeTracker, holder: Element, owner: Element[], inside: () => void): void;
247
291
  /** The paragraph mark's run properties (`w:pPr/w:rPr`), created when absent. */
248
292
  export declare function paraRPrOf(p: wml.P): wml.ParaRPr;
249
293
  /** The row's properties (`w:trPr`), created when absent. */
@@ -254,6 +298,19 @@ export declare function pruneParagraphProperties(p: wml.P): void;
254
298
  export declare function markDeleted(p: wml.P): boolean;
255
299
  /** True when a paragraph's mark is marked inserted. */
256
300
  export declare function markInserted(p: wml.P): boolean;
301
+ /**
302
+ * An equation (`m:oMath`, `m:oMathPara`) marked deleted where it stands, in Word's form (check 57 cases 7 to 10): each
303
+ * math run's content inside a `w:del` in its `m:r`, and each structure's `m:ctrlPr` holding a `w:del` around its run
304
+ * properties, as Word's tracked `delete()` writes them. An argument's own `m:ctrlPr` marks no structure, and is left as
305
+ * it is. An equation holding a revision of its own (`equationRevisionIn`) is the caller's to put in a `w:del` whole.
306
+ */
307
+ export declare function markEquationDeleted(tracker: ChangeTracker, equation: object): void;
308
+ /**
309
+ * A revision an equation holds of its own, or undefined: a math run's, a structure's or an argument's, or a `w:ins` or
310
+ * `w:del` among its runs. How Word deletes such an equation isn't measured, so a tracked deletion puts it whole in a
311
+ * `w:del`, the form this package wrote for every equation before (CR-002 section 62.2, D2).
312
+ */
313
+ export declare function equationRevisionIn(equation: object): string | undefined;
257
314
  /** Turns a run's `w:t` into `w:delText` and `w:instrText` into `w:delInstrText`, in place. */
258
315
  export declare function toDeletedText(run: wml.R): void;
259
316
  /** The inverse, for `reject()` of a deletion. */
@@ -1,9 +1,10 @@
1
1
  import { deepCopy, deepCopyAsSync } from '@docx4j/generated-objects-ts';
2
2
  import * as el from '@docx4j/generated-objects-ts/el/org_docx4j_wml';
3
- import { createCTTrackChange, createCTRPrChange, createCTRPrChangeRPr, createCTPPrChange, createCTMarkup, createDelText, createPPr, createParaRPr, createTrPr, } from '@docx4j/generated-objects-ts/factory/org_docx4j_wml';
3
+ import { createCTTrackChange, createCTRPrChange, createCTRPrChangeRPr, createCTPPrChange, createCTMarkup, createDelText, createPPr, createParaRPr, createTrPr, createParaRPrChange, createCTParaRPrOriginal, } from '@docx4j/generated-objects-ts/factory/org_docx4j_wml';
4
4
  import { rPrToElements, rPrFromElements } from '@docx4j/generated-objects-ts/builders/wml';
5
5
  import { Docx4JException } from '../../opc/exceptions.mjs';
6
- import { W_NS, linkParents, walk, typeNameOf, revisionKindOf, childrenOf, rowsOf, cellsOf } from './tree.mjs';
6
+ import { W_NS, linkParents, walk, typeNameOf, revisionKindOf, childrenOf, rowsOf, cellsOf, isAlternateContent, selectedBranchOf, branchesOf, ALTERNATE_CONTENT } from './tree.mjs';
7
+ import { wallClockIn, instantOf } from '../dateZone.mjs';
7
8
  /**
8
9
  * `w:id` on these is the one annotation id space (ECMA-376 17.13.5.4): revisions, bookmarks,
9
10
  * comment range marks and permissions share it. `w:comment/@w:id` (docx4j `Comments.Comment`,
@@ -69,21 +70,20 @@ export function dateOf(cal) {
69
70
  /**
70
71
  * A revision's `w:date` as Word writes it: the local wall-clock time, with a `Z` that does not mean
71
72
  * UTC (CR-002 section 29, check 23: Office JS read `01:00:00Z` as 15:00 UTC the day before, at
72
- * UTC+10; Word's own files carry the true UTC beside it in `w16du:dateUtc`). "Local" is this
73
- * process's time zone, as it is the add-in's for Office JS.
73
+ * UTC+10; Word's own files carry the true UTC beside it in `w16du:dateUtc`). "Local" is `zone`, the
74
+ * package's `dateTimeZone` (CR-018), else this process's time zone, which is the add-in's for Office JS.
74
75
  */
75
- export function wordCalendarOf(date) {
76
- return {
77
- year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate(),
78
- hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), timezone: 0,
79
- };
76
+ export function wordCalendarOf(date, zone) {
77
+ const clock = wallClockIn(date, zone);
78
+ return { year: clock.year, month: clock.month, day: clock.day, hour: clock.hour, minute: clock.minute, second: clock.second, timezone: 0 };
80
79
  }
81
80
  /**
82
81
  * A revision's date as Word means it: `w16du:dateUtc` when there is one, which is UTC; else
83
- * `w:date` read as local wall-clock time, its `Z` notwithstanding, as Office JS reads it (check 23).
82
+ * `w:date` read as local wall-clock time, its `Z` notwithstanding, as Office JS reads it (check 23),
83
+ * in `zone` (the package's `dateTimeZone`, CR-018), else the runtime's zone.
84
84
  * A `w:date` with a non-zero offset, which Word does not write, is read as it says.
85
85
  */
86
- export function revisionDateOf(value) {
86
+ export function revisionDateOf(value, zone) {
87
87
  var _a, _b, _c, _d, _e, _f;
88
88
  if (((_a = value.dateUtc) === null || _a === void 0 ? void 0 : _a.year) !== undefined)
89
89
  return dateOf(value.dateUtc);
@@ -92,7 +92,88 @@ export function revisionDateOf(value) {
92
92
  return undefined;
93
93
  if (cal.timezone !== undefined && cal.timezone !== 0)
94
94
  return dateOf(cal);
95
- return new Date(cal.year, ((_b = cal.month) !== null && _b !== void 0 ? _b : 1) - 1, (_c = cal.day) !== null && _c !== void 0 ? _c : 1, (_d = cal.hour) !== null && _d !== void 0 ? _d : 0, (_e = cal.minute) !== null && _e !== void 0 ? _e : 0, (_f = cal.second) !== null && _f !== void 0 ? _f : 0);
95
+ return instantOf({ year: cal.year, month: (_b = cal.month) !== null && _b !== void 0 ? _b : 1, day: (_c = cal.day) !== null && _c !== void 0 ? _c : 1, hour: (_d = cal.hour) !== null && _d !== void 0 ? _d : 0, minute: (_e = cal.minute) !== null && _e !== void 0 ? _e : 0, second: (_f = cal.second) !== null && _f !== void 0 ? _f : 0 }, zone);
96
+ }
97
+ const STAMP = /^(-?\d{4,})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?)?(Z|[+-]\d{2}:\d{2})?$/;
98
+ /** A stamp's date and time as written, its fields read as a UTC clock's (milliseconds), and its zone in minutes; undefined for no year. */
99
+ function clockOf(stamp) {
100
+ var _a, _b, _c, _d, _e, _f, _g, _h;
101
+ if (stamp === undefined || stamp === null)
102
+ return undefined;
103
+ if (typeof stamp === 'string') {
104
+ const m = STAMP.exec(stamp.trim());
105
+ if (!m)
106
+ return undefined;
107
+ const zone = m[7];
108
+ const timezone = zone === undefined ? undefined : zone === 'Z' ? 0
109
+ : (zone.startsWith('-') ? -1 : 1) * (Number(zone.slice(1, 3)) * 60 + Number(zone.slice(4, 6)));
110
+ return { ms: utcClock(Number(m[1]), Number(m[2]), Number(m[3]), Number((_a = m[4]) !== null && _a !== void 0 ? _a : 0), Number((_b = m[5]) !== null && _b !== void 0 ? _b : 0), Number((_c = m[6]) !== null && _c !== void 0 ? _c : 0)), timezone };
111
+ }
112
+ if (stamp.year === undefined)
113
+ return undefined;
114
+ return { ms: utcClock(stamp.year, (_d = stamp.month) !== null && _d !== void 0 ? _d : 1, (_e = stamp.day) !== null && _e !== void 0 ? _e : 1, (_f = stamp.hour) !== null && _f !== void 0 ? _f : 0, (_g = stamp.minute) !== null && _g !== void 0 ? _g : 0, (_h = stamp.second) !== null && _h !== void 0 ? _h : 0), timezone: stamp.timezone };
115
+ }
116
+ function utcClock(year, month, day, hour, minute, second) {
117
+ const d = new Date(Date.UTC(2000, month - 1, day, hour, minute, second));
118
+ d.setUTCFullYear(year);
119
+ return d.getTime();
120
+ }
121
+ /** The offsets clocks keep, in seconds: UTC-12:00 to UTC+14:00. */
122
+ const MIN_OFFSET = -12 * 3600;
123
+ const MAX_OFFSET = 14 * 3600;
124
+ /**
125
+ * The author's local time of a revision's or comment's `w:date`: its date and time as stored, in ISO 8601's extended form
126
+ * with no designator (`2026-10-31T11:00:00`), any designator not read, a missing time 00:00:00, fractions of a second
127
+ * dropped; undefined for no date. Word writes the author's wall clock labelled `Z` (CR-002 section 29), and shows it as it
128
+ * is. docx4j `RevisionDates.localTime`.
129
+ */
130
+ export function authorLocalTime(date) {
131
+ const clock = clockOf(date);
132
+ return clock === undefined ? undefined : clockText(clock.ms);
133
+ }
134
+ /**
135
+ * The author's UTC offset in minutes: `w:date` less `dateUtc` (`w16du:dateUtc`, or a comment's `w16cex:dateUtc`), where both
136
+ * are present and differ by a whole number of quarter hours from -12:00 to +14:00, as a clock's offset does; else
137
+ * undefined, so a pair a producer wrote inconsistently gives no offset rather than a wrong one. `dateUtc` without a zone is
138
+ * UTC, and one with an offset is moved by it. docx4j `RevisionDates.offset`.
139
+ */
140
+ export function authorOffsetMinutes(date, dateUtc) {
141
+ var _a;
142
+ const local = clockOf(date);
143
+ const utc = clockOf(dateUtc);
144
+ if (local === undefined || utc === undefined)
145
+ return undefined;
146
+ const seconds = Math.round((local.ms - (utc.ms - ((_a = utc.timezone) !== null && _a !== void 0 ? _a : 0) * 60000)) / 1000);
147
+ if (seconds % 900 !== 0 || seconds < MIN_OFFSET || seconds > MAX_OFFSET)
148
+ return undefined;
149
+ return seconds / 60;
150
+ }
151
+ /**
152
+ * A revision's or comment's stamp as WD REQ-702 writes it: the author's local time (`authorLocalTime`), with the author's
153
+ * offset after it where it is known (`2026-10-31T11:00:00+11:00`; `+00:00` for UTC, never `Z`); `dateUtc` with `Z` where
154
+ * there is no `w:date`; undefined where there is neither. The `Z` Word stores on `w:date` is never written, and nothing is
155
+ * converted to another zone. docx4j `RevisionDates.text`.
156
+ */
157
+ export function revisionDateText(date, dateUtc) {
158
+ var _a;
159
+ const local = clockOf(date);
160
+ if (local === undefined) {
161
+ const utc = clockOf(dateUtc);
162
+ return utc === undefined ? undefined : `${clockText(utc.ms - ((_a = utc.timezone) !== null && _a !== void 0 ? _a : 0) * 60000)}Z`;
163
+ }
164
+ const offset = authorOffsetMinutes(date, dateUtc);
165
+ if (offset === undefined)
166
+ return clockText(local.ms);
167
+ const abs = Math.abs(offset);
168
+ return `${clockText(local.ms)}${offset < 0 ? '-' : '+'}${String(Math.floor(abs / 60)).padStart(2, '0')}:${String(abs % 60).padStart(2, '0')}`;
169
+ }
170
+ /** A UTC clock's milliseconds as `uuuu-MM-ddTHH:mm:ss`. */
171
+ function clockText(ms) {
172
+ const d = new Date(ms);
173
+ const p2 = (n) => String(n).padStart(2, '0');
174
+ const year = d.getUTCFullYear();
175
+ const y = year < 0 ? `-${String(-year).padStart(4, '0')}` : String(year).padStart(4, '0');
176
+ return `${y}-${p2(d.getUTCMonth() + 1)}-${p2(d.getUTCDate())}T${p2(d.getUTCHours())}:${p2(d.getUTCMinutes())}:${p2(d.getUTCSeconds())}`;
96
177
  }
97
178
  /** Properties compared as values: keys sorted, `PARENT`, `TYPE_NAME` and absent values left out. */
98
179
  export function canonical(value) {
@@ -194,7 +275,7 @@ export class ChangeTracker {
194
275
  }
195
276
  /**
196
277
  * The `w:id`, `w:author` and `w:date` a new revision carries, `w:date` in Word's local wall-clock
197
- * convention (`wordCalendarOf`), and `w16du:dateUtc`, the true UTC, as Word writes them both. The
278
+ * convention (`wordCalendarOf`, in the host's `dateTimeZone`), and `w16du:dateUtc`, the true UTC, as Word writes them both. The
198
279
  * part's root is made to list `w16du` in `mc:Ignorable` first (`declareDateUtc`): a consumer that
199
280
  * does not know `w16du` must reject it unless it is declared ignorable. A tracker bound to no part -
200
281
  * the package's own - writes `w:date` alone (CR-002 section 29).
@@ -202,7 +283,7 @@ export class ChangeTracker {
202
283
  markup() {
203
284
  var _a;
204
285
  const when = (_a = this.host.trackedChangeDate) !== null && _a !== void 0 ? _a : nowToTheMinute();
205
- const markup = { id: this.nextId(), author: this.author, date: wordCalendarOf(when) };
286
+ const markup = { id: this.nextId(), author: this.author, date: wordCalendarOf(when, this.host.dateTimeZone) };
206
287
  if (declareDateUtc(this.part))
207
288
  markup.dateUtc = calendarOf(when);
208
289
  return markup;
@@ -263,6 +344,31 @@ export class ChangeTracker {
263
344
  if (Object.keys(rPr).every((key) => key === 'TYPE_NAME'))
264
345
  delete run.rPr;
265
346
  }
347
+ /**
348
+ * Records a paragraph mark's formatting as it is now in its `w:rPrChange`, once: what a tracked `font`
349
+ * write over a range holding the mark writes (check 52 case 56: `<w:rPrChange><w:rPr/></w:rPrChange>`
350
+ * for a mark that had no formatting). The mark's own revisions (inserted, deleted) are not its formatting.
351
+ */
352
+ recordMarkRPrChange(rPr) {
353
+ if (rPr.rPrChange)
354
+ return;
355
+ const original = createCTParaRPrOriginal({ egrPrBase: rPrToElements(rPr) });
356
+ rPr.rPrChange = createParaRPrChange({ ...this.markup(), rPr: original });
357
+ linkParents(rPr.rPrChange, rPr);
358
+ }
359
+ /** `settleRPrChange` for a paragraph mark: its `w:rPrChange` goes where its formatting is back to what it recorded. */
360
+ settleMarkRPrChange(p) {
361
+ var _a, _b, _c;
362
+ const rPr = (_a = p.pPr) === null || _a === void 0 ? void 0 : _a.rPr;
363
+ const change = rPr === null || rPr === void 0 ? void 0 : rPr.rPrChange;
364
+ if (!rPr || !change)
365
+ return;
366
+ const { rPrChange: _recorded, ins: _ins, del: _del, moveFrom: _from, moveTo: _to, ...current } = rPr;
367
+ if (canonical(current) !== canonical(rPrFromElements((_c = (_b = change.rPr) === null || _b === void 0 ? void 0 : _b.egrPrBase) !== null && _c !== void 0 ? _c : [])))
368
+ return;
369
+ delete rPr.rPrChange;
370
+ pruneParagraphProperties(p);
371
+ }
266
372
  /** Records the paragraph's properties as they are now in `w:pPrChange`, once. */
267
373
  recordPPrChange(pPr) {
268
374
  if (pPr.pPrChange)
@@ -373,11 +479,12 @@ export function wrapInsertedRuns(tracker, items, parent) {
373
479
  /** A whole table inserted: every row is marked inserted and everything in its cells is an insertion (`trackInsertedBlocks`). */
374
480
  export function trackInsertedTable(tracker, tbl) {
375
481
  var _a;
376
- for (const row of rowsOf(tbl)) {
482
+ // every branch of a kept row- or cell-level mc:AlternateContent (CR-013 phase 3)
483
+ for (const row of rowsOf(tbl, 'every')) {
377
484
  const tr = row.element.value;
378
485
  if (!((_a = tr.trPr) === null || _a === void 0 ? void 0 : _a.ins))
379
486
  tracker.markRowInserted(tr);
380
- for (const cell of cellsOf(tr))
487
+ for (const cell of cellsOf(tr, 'every'))
381
488
  trackInsertedBlocks(tracker, childrenOf(cell.element.value));
382
489
  }
383
490
  }
@@ -398,6 +505,10 @@ export function trackInsertedBlock(tracker, block, owner) {
398
505
  return;
399
506
  else if (HOLDER_TYPES.has(tn !== null && tn !== void 0 ? tn : ''))
400
507
  markHolderInserted(tracker, block, owner, () => trackInsertedBlocks(tracker, childrenOf(block.value)));
508
+ // a kept block-level mc:AlternateContent: every branch's content (CR-013 phase 3)
509
+ else if (tn === ALTERNATE_CONTENT)
510
+ for (const branch of branchesOf(block.value))
511
+ trackInsertedBlocks(tracker, branch);
401
512
  else
402
513
  trackInsertedBlocks(tracker, childrenOf(block.value));
403
514
  }
@@ -443,6 +554,18 @@ export function holderItemsOf(value) {
443
554
  * pairs, so that the ids run in document order as Word's do.
444
555
  */
445
556
  export function markHolderInserted(tracker, holder, owner, inside) {
557
+ markHolder(tracker, holder, owner, inside, 'ins');
558
+ }
559
+ /**
560
+ * A content control or custom XML element deleted under tracking, as Word writes it (check 54 cases 15 and 17, a
561
+ * range across paragraphs holding a whole control): `markHolderInserted`'s form with `w:customXmlDelRangeStart` and
562
+ * `w:customXmlDelRangeEnd`, its content marked deleted between the two pairs (`inside`). Accepting takes the element
563
+ * away; rejecting, the markers (`TrackedChange`'s `holder` target).
564
+ */
565
+ export function markHolderDeleted(tracker, holder, owner, inside) {
566
+ markHolder(tracker, holder, owner, inside, 'del');
567
+ }
568
+ function markHolder(tracker, holder, owner, inside, revision) {
446
569
  var _a;
447
570
  const at = owner.indexOf(holder);
448
571
  const items = holderItemsOf(holder.value);
@@ -450,16 +573,17 @@ export function markHolderInserted(tracker, holder, owner, inside) {
450
573
  inside();
451
574
  return;
452
575
  }
576
+ const [start, end] = revision === 'ins' ? [el.customXmlInsRangeStart, el.customXmlInsRangeEnd] : [el.customXmlDelRangeStart, el.customXmlDelRangeEnd];
453
577
  const value = holder.value;
454
578
  const first = tracker.markup();
455
- const outerStart = el.customXmlInsRangeStart(createCTTrackChange(first));
456
- const innerEnd = el.customXmlInsRangeEnd(createCTMarkup({ id: first.id }));
579
+ const outerStart = start(createCTTrackChange(first));
580
+ const innerEnd = end(createCTMarkup({ id: first.id }));
457
581
  owner.splice(at, 0, outerStart);
458
582
  items.unshift(innerEnd);
459
583
  inside();
460
584
  const second = tracker.markup();
461
- const innerStart = el.customXmlInsRangeStart(createCTTrackChange(second));
462
- const outerEnd = el.customXmlInsRangeEnd(createCTMarkup({ id: second.id }));
585
+ const innerStart = start(createCTTrackChange(second));
586
+ const outerEnd = end(createCTMarkup({ id: second.id }));
463
587
  items.push(innerStart);
464
588
  owner.splice(owner.indexOf(holder) + 1, 0, outerEnd);
465
589
  linkParents([outerStart, outerEnd], value.PARENT);
@@ -505,6 +629,87 @@ export function markInserted(p) {
505
629
  var _a, _b;
506
630
  return ((_b = (_a = p.pPr) === null || _a === void 0 ? void 0 : _a.rPr) === null || _b === void 0 ? void 0 : _b.ins) !== undefined;
507
631
  }
632
+ // --- an equation deleted (CR-002 section 62.2, D2) ----------------------------------------
633
+ /** Each equation structure's properties, whose `m:ctrlPr` marks the structure inserted or deleted (CR-002 section 51). */
634
+ const MATH_STRUCTURES = Object.fromEntries(['Acc', 'Bar', 'BorderBox', 'Box', 'D', 'EqArr', 'F', 'Func', 'GroupChr', 'LimLow', 'LimUpp', 'M', 'Nary', 'Phant', 'Rad', 'SPre', 'SSub', 'SSubSup', 'SSup']
635
+ .map((n) => [`org_docx4j_math.CT${n}`, `${n[0].toLowerCase()}${n.slice(1)}Pr`]));
636
+ /**
637
+ * An equation (`m:oMath`, `m:oMathPara`) marked deleted where it stands, in Word's form (check 57 cases 7 to 10): each
638
+ * math run's content inside a `w:del` in its `m:r`, and each structure's `m:ctrlPr` holding a `w:del` around its run
639
+ * properties, as Word's tracked `delete()` writes them. An argument's own `m:ctrlPr` marks no structure, and is left as
640
+ * it is. An equation holding a revision of its own (`equationRevisionIn`) is the caller's to put in a `w:del` whole.
641
+ */
642
+ export function markEquationDeleted(tracker, equation) {
643
+ const visit = (value, depth) => {
644
+ var _a;
645
+ if (typeof value !== 'object' || value === null || depth > 64)
646
+ return;
647
+ if (Array.isArray(value)) {
648
+ for (const v of value)
649
+ visit(v, depth + 1);
650
+ return;
651
+ }
652
+ const named = value;
653
+ if (named.name !== undefined && 'value' in named) {
654
+ visit(named.value, depth + 1);
655
+ return;
656
+ }
657
+ const tn = (_a = value.TYPE_NAME) !== null && _a !== void 0 ? _a : '';
658
+ if (!tn.startsWith('org_docx4j_math.') || tn.endsWith('Pr'))
659
+ return;
660
+ if (tn === 'org_docx4j_math.CTR') {
661
+ deleteMathRun(tracker, value);
662
+ return;
663
+ }
664
+ const key = MATH_STRUCTURES[tn];
665
+ if (key !== undefined)
666
+ deleteMathStructure(tracker, value, tn, key);
667
+ for (const k of Object.keys(value))
668
+ if (k !== 'PARENT' && k !== 'TYPE_NAME' && k !== key)
669
+ visit(value[k], depth + 1);
670
+ };
671
+ visit(equation, 0);
672
+ }
673
+ /** A math run's content moved into a `w:del` in it (`CT_MathRunTrackChange`), its `m:t` kept as `m:t`, as Word writes it. */
674
+ function deleteMathRun(tracker, run) {
675
+ var _a;
676
+ const content = ((_a = run.content) !== null && _a !== void 0 ? _a : (run.content = []));
677
+ const value = { TYPE_NAME: 'org_docx4j_wml.CTMathRunTrackChange', ...tracker.markup(), rest: content.splice(0) };
678
+ const del = element('del', value);
679
+ linkParents(value.rest, value);
680
+ content.push(del);
681
+ linkParents(del, run);
682
+ }
683
+ /** A structure's `m:ctrlPr` holding a `w:del` with the run properties it had, its properties made where it had none. */
684
+ function deleteMathStructure(tracker, structure, tn, key) {
685
+ var _a, _b;
686
+ const properties = ((_a = structure[key]) !== null && _a !== void 0 ? _a : (structure[key] = { TYPE_NAME: `${tn}Pr` }));
687
+ const ctrlPr = ((_b = properties.ctrlPr) !== null && _b !== void 0 ? _b : (properties.ctrlPr = { TYPE_NAME: 'org_docx4j_math.CTCtrlPr' }));
688
+ const rPr = createCTRPrChangeRPr({ egrPrBase: ctrlPr.rPr ? rPrToElements(ctrlPr.rPr) : [] });
689
+ ctrlPr.del = createCTRPrChange({ ...tracker.markup(), rPr });
690
+ delete ctrlPr.rPr;
691
+ linkParents(properties, structure);
692
+ }
693
+ /**
694
+ * A revision an equation holds of its own, or undefined: a math run's, a structure's or an argument's, or a `w:ins` or
695
+ * `w:del` among its runs. How Word deletes such an equation isn't measured, so a tracked deletion puts it whole in a
696
+ * `w:del`, the form this package wrote for every equation before (CR-002 section 62.2, D2).
697
+ */
698
+ export function equationRevisionIn(equation) {
699
+ let found;
700
+ walk(equation, (value) => {
701
+ if (found)
702
+ return;
703
+ const tn = value.TYPE_NAME;
704
+ if (tn === 'org_docx4j_wml.CTMathRunTrackChange')
705
+ found = 'a math run\'s revision';
706
+ else if (tn === 'org_docx4j_wml.RunIns' || tn === 'org_docx4j_wml.RunDel' || tn === 'org_docx4j_wml.RunTrackChange')
707
+ found = 'a revision among its runs';
708
+ else if (tn === 'org_docx4j_math.CTCtrlPr' && (value.ins || value.del))
709
+ found = 'a structure\'s revision';
710
+ });
711
+ return found;
712
+ }
508
713
  // --- w:t <-> w:delText -------------------------------------------------------------------
509
714
  const DELETED_NAME = { t: 'delText', instrText: 'delInstrText' };
510
715
  const RESTORED_NAME = { delText: 't', delInstrText: 'instrText' };
@@ -517,11 +722,26 @@ export function toRestoredText(run) {
517
722
  rename(run, RESTORED_NAME, false);
518
723
  }
519
724
  function rename(run, table, deleting) {
520
- const content = run.content;
725
+ renameIn(run.content, run, table, deleting);
726
+ }
727
+ /**
728
+ * `rename` over a run's items, and over a kept `mc:AlternateContent`'s selected branch among them: a
729
+ * deletion of a branch's text writes the selected branch's `w:delText` and keeps the other branches as
730
+ * they were (CR-012 section 12.2, the editor's ED-009 section 3.6).
731
+ */
732
+ function renameIn(content, parent, table, deleting) {
733
+ var _a, _b, _c;
521
734
  if (!content)
522
735
  return;
523
736
  for (let i = 0; i < content.length; i++) {
524
737
  const item = content[i];
738
+ if (isAlternateContent(item)) {
739
+ const branch = selectedBranchOf(item.value);
740
+ const holder = branch === undefined ? undefined : ((_c = (_b = (_a = branch[0]) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.PARENT) !== null && _c !== void 0 ? _c : parent);
741
+ if (branch && holder)
742
+ renameIn(branch, holder, table, deleting);
743
+ continue;
744
+ }
525
745
  const to = table[item.name.localPart];
526
746
  if (to === undefined)
527
747
  continue;
@@ -530,7 +750,7 @@ function rename(run, table, deleting) {
530
750
  ? createDelText({ value: v.value, ...(v.space === undefined ? {} : { space: v.space }) })
531
751
  : { TYPE_NAME: 'org_docx4j_wml.Text', value: v.value, ...(v.space === undefined ? {} : { space: v.space }) };
532
752
  content[i] = element(to, value);
533
- linkParents(content[i], run);
753
+ linkParents(content[i], parent);
534
754
  }
535
755
  }
536
756
  // --- w:rPr <-> w:rPrChange/w:rPr ---------------------------------------------------------