@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
@@ -9,8 +9,9 @@ import { Docx4JException } from '../opc/exceptions.mjs';
9
9
  import { Namespaces } from '../parts/Namespaces.mjs';
10
10
  import { Parts } from '../parts/Parts.mjs';
11
11
  import { XmlPart } from '../parts/XmlPart.mjs';
12
- import { RelationshipsPart } from '../parts/RelationshipsPart.mjs';
12
+ import { RelationshipsPart, isExternal } from '../parts/RelationshipsPart.mjs';
13
13
  import { DocPropsCorePart, DocPropsExtendedPart } from '../parts/docProps/index.mjs';
14
+ import { assertTimeZone, runtimeTimeZone } from '../model/dateZone.mjs';
14
15
  import { mceKeep, mcePreprocess } from '../opc/mce/preprocessor.mjs';
15
16
  import { createPackageForContentType, registerGenericPackageClass } from './registry.mjs';
16
17
  /**
@@ -18,6 +19,27 @@ import { createPackageForContentType, registerGenericPackageClass } from './regi
18
19
  * the content types, the package relationships and the parts reachable from them.
19
20
  */
20
21
  export class OpcPackage {
22
+ /**
23
+ * The client's time zone for this package, an IANA id (`Australia/Sydney`), or undefined for the runtime's (CR-018; the
24
+ * portfolio's date rule of 2026-10-28, docx4j's `OpcPackage.setDateTimeZone`). Every instant the package holds is shown
25
+ * in it, and a `w:date` without `dateUtc` read in it: a new revision's or comment's stamp (Word's local wall-clock
26
+ * `w:date`), `TrackedChange.date` and `Comment.creationDate`, and date fields when they are evaluated (CR-012 phase 5).
27
+ * It is the client's for this package, not the document's, and reaches no saved file as such: a server reusing a
28
+ * loaded package sets it per request. Under Office JS the runtime's zone is already the client's. A bound date has no
29
+ * zone (CR-002 section 56) unless `boundDatesConvertedAsWord` asks for Word's conversion in this one. A zone the
30
+ * runtime does not know is refused with a `RangeError` at the set.
31
+ */
32
+ get dateTimeZone() {
33
+ return this.dateTimeZone_;
34
+ }
35
+ set dateTimeZone(id) {
36
+ this.dateTimeZone_ = id === undefined ? undefined : assertTimeZone(id);
37
+ }
38
+ /** The zone in force: `dateTimeZone`, else the runtime's. */
39
+ effectiveDateTimeZone() {
40
+ var _a;
41
+ return (_a = this.dateTimeZone_) !== null && _a !== void 0 ? _a : runtimeTimeZone();
42
+ }
21
43
  constructor() {
22
44
  /** The pseudo part name of the package itself: the source of the package relationships. */
23
45
  this.partName = PartName.ROOT;
@@ -26,7 +48,46 @@ export class OpcPackage {
26
48
  /** Custom XML parts by the (lower-cased) itemID of their properties part. */
27
49
  this.customXmlDataStorageParts = new Map();
28
50
  /** The options this package was loaded with. */
51
+ /**
52
+ * The names the container held more than one entry of, each read from its first entry under
53
+ * `LoadOptions.repair: 'word'` (WD REQ-206, CR-024); empty for a package loaded without one, or made here.
54
+ */
55
+ this.duplicateEntries = [];
29
56
  this.loadOptions = {};
57
+ /**
58
+ * Whether a save refuses a part holding a child its container never admits (CR-016 D2, docx4j CR-064's rules in the
59
+ * objects facade, its CR-017): a run straight in the body, a table in a paragraph, a cell beside a table's rows, a
60
+ * string in a run, a name and value that disagree. On by default: the save throws `MisplacedContentException` with
61
+ * every such child in the part, its path and docx4j's message naming the fix, and writes nothing, since Word 365
62
+ * refuses such a file or repairs it by dropping content (check 72). Off, the part is written as held and each is on
63
+ * `lastSave.misplaced`. Only a part being marshalled is checked (one unmarshalled, or given contents); a part copied
64
+ * from the source is never refused, so a document read and saved untouched never is. `checkContent()` is the same
65
+ * check on request. A misplaced child read from a file is a `target.misplaced` warning on its part (D7).
66
+ */
67
+ this.checkContentOnSave = true;
68
+ /**
69
+ * Whether a save refuses to lose what a read dropped (CR-025 sections 2.3 and 2.4, D8): a part holding `part.skipped` content
70
+ * that was changed throws `SaveLossException` and nothing is written. Off, the part is written without those items, each on
71
+ * `lastSave.lost`. A part read and not changed is copied either way, so nothing is lost there. Word's own save drops such
72
+ * content with no message (check 76), so off is Word's behaviour.
73
+ */
74
+ this.checkLossOnSave = true;
75
+ /**
76
+ * Show bound dates as Word displays them in the package's zone (CR-018, the date rule's point 3; docx4j's
77
+ * `setBoundDatesConvertedAsWord`): off by default, a bound date being the day its fields say wherever it is read
78
+ * (CR-002 section 56). On, a bound value carrying a `Z` or an offset is read as an instant and shown in
79
+ * `effectiveDateTimeZone()`, as Word reads the `Z` as UTC and shows the machine's local time (a day early west of
80
+ * UTC); a value with no marker, or a date alone, stays nominal. Setting `dateTimeZone` does not turn this on.
81
+ */
82
+ this.boundDatesConvertedAsWord = false;
83
+ /**
84
+ * Write the save's time into the core properties (CR-018, the date rule's point 6; docx4j's `docx4j.dcterms.write`):
85
+ * off by default, a save leaving `dcterms:created` and `dcterms:modified` as they are. On, each save sets
86
+ * `dcterms:modified` to now, UTC to the second (`2026-10-28T03:04:05Z`, the W3CDTF form Office writes), and
87
+ * `dcterms:created` too for a package created here that has none; a loaded package with no core properties part is
88
+ * left without one, as docx4j leaves it.
89
+ */
90
+ this.writeTimesOnSave = false;
30
91
  this.relationshipsPart = RelationshipsPart.createPackageRels();
31
92
  this.relationshipsPart.sourceP = this;
32
93
  this.relationshipsPart.package = this;
@@ -73,22 +134,71 @@ export class OpcPackage {
73
134
  default: return false;
74
135
  }
75
136
  }
76
- /** The main part: the target of the officeDocument relationship. */
137
+ /** The main part: the target of the officeDocument relationship, an External one naming none. */
77
138
  getMainPart() {
78
- var _a;
79
- const rel = (_a = this.relationshipsPart.getRelationshipByType(Namespaces.DOCUMENT)) !== null && _a !== void 0 ? _a : this.relationshipsPart.getRelationshipByType(Namespaces.DOCUMENT_STRICT);
80
- return rel ? this.relationshipsPart.getPart(rel) : undefined;
139
+ const rels = this.relationshipsPart;
140
+ const rel = [...rels.getRelationshipsByType(Namespaces.DOCUMENT), ...rels.getRelationshipsByType(Namespaces.DOCUMENT_STRICT)].find((r) => !isExternal(r));
141
+ return rel ? rels.getPart(rel) : undefined;
81
142
  }
82
143
  /**
83
- * The warnings of every part parsed so far (each XML part's `warnings`, CR-010 phase 1). A part
144
+ * The warnings of every part parsed so far (each XML part's `warnings`, CR-010 phase 1), after the
145
+ * load's own: a name the container holds twice, and more than one officeDocument relationship, read under
146
+ * `repair: 'word'` (CR-024), and an `External` main relationship dropped under `repair: 'all'` (CR-031). A part
84
147
  * is parsed when something reads it, so a reader that wants a whole package's warnings reads its
85
148
  * parts first; `unmarshalAll()` does, at the cost of re-marshalling every part on save.
86
149
  */
87
150
  get warnings() {
88
- const out = [];
151
+ const out = [...this.duplicateEntries];
152
+ if (this.multipleMainParts)
153
+ out.push(this.multipleMainParts);
154
+ if (this.externalMainPart)
155
+ out.push(this.externalMainPart);
89
156
  for (const part of this.parts)
90
157
  if (part instanceof XmlPart)
91
158
  out.push(...part.warnings);
159
+ // a relationships part's own, what its read dropped: a child of another local name, an attribute the model doesn't map
160
+ // (CR-025 section 8, D12); after the parts', and outside the save's gate, since none names a part
161
+ for (const rels of [this.relationshipsPart, ...[...this.parts].map((p) => p.relationshipsPart)])
162
+ if (rels)
163
+ out.push(...rels.warnings);
164
+ return out;
165
+ }
166
+ /**
167
+ * Each relationships part a load under `repair: 'word'` read by local name, being in a wrong namespace (CR-031 section
168
+ * 2.3): the package's and its parts', in that order.
169
+ */
170
+ get relationshipsNamespaces() {
171
+ var _a;
172
+ const out = [];
173
+ for (const rels of [this.relationshipsPart, ...[...this.parts].map((p) => p.relationshipsPart)]) {
174
+ for (const w of (_a = rels === null || rels === void 0 ? void 0 : rels.warnings) !== null && _a !== void 0 ? _a : [])
175
+ if (w.code === 'package.relationships_namespace')
176
+ out.push(w);
177
+ }
178
+ return out;
179
+ }
180
+ /**
181
+ * What the load repaired (WD REQ-207's `repaired`, CR-031 section 2.4), read from what it recorded, so it reports what the
182
+ * load did whatever the option: `'own'` for a repair of this package's own (an `External` main relationship dropped),
183
+ * `'word'` where only Word's were followed (a duplicated entry, several main relationships, a relationships part read by
184
+ * local name), else `'none'`.
185
+ */
186
+ get repaired() {
187
+ if (this.externalMainPart)
188
+ return 'own';
189
+ return this.duplicateEntries.length > 0 || this.multipleMainParts || this.relationshipsNamespaces.length > 0 ? 'word' : 'none';
190
+ }
191
+ /**
192
+ * Every child a part holds that its container never admits (CR-016 D6, the check on request): what a save would
193
+ * refuse for, over every typed XML part, each finding with its part, its path, the rule and docx4j's message naming
194
+ * the fix. Nothing is changed, and an untouched part stays untouched (read privately). `[]` for a package whose
195
+ * content is all in its place.
196
+ */
197
+ async checkContent() {
198
+ const out = [];
199
+ for (const part of this.parts)
200
+ if (part instanceof XmlPart)
201
+ out.push(...(await part.checkContent()));
92
202
  return out;
93
203
  }
94
204
  /** Unmarshals every XML part, so that `contents` is available synchronously everywhere. */
@@ -135,6 +245,12 @@ export class OpcPackage {
135
245
  if (copy.constructor !== this.constructor) {
136
246
  throw new Docx4JException(`Cloning ${this.constructor.name} produced ${copy.constructor.name}`);
137
247
  }
248
+ copy.normaliseOnSave = this.normaliseOnSave;
249
+ copy.checkContentOnSave = this.checkContentOnSave;
250
+ copy.checkLossOnSave = this.checkLossOnSave;
251
+ copy.dateTimeZone = this.dateTimeZone;
252
+ copy.boundDatesConvertedAsWord = this.boundDatesConvertedAsWord;
253
+ copy.writeTimesOnSave = this.writeTimesOnSave;
138
254
  this.copyPackageSettingsTo(copy);
139
255
  return copy;
140
256
  }
@@ -4,6 +4,7 @@ import type { Part } from '../parts/Part.mjs';
4
4
  import { MainDocumentPart, StyleDefinitionsPart, type NumberingDefinitionsPart } from '../parts/wml/index.mjs';
5
5
  import { type FontSettings, type DefaultThemeValue } from '../model/fonts/defaultTheme.mjs';
6
6
  import { Body, type Address, type Outline, type OutlineParagraph, type OutlineTable } from '../model/content/Body.mjs';
7
+ import { type TrackedChangeSelection } from '../model/content/trackedChangeFilter.mjs';
7
8
  import type { Paragraph } from '../model/content/Paragraph.mjs';
8
9
  import type { Author } from '../model/content/comments.mjs';
9
10
  import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
@@ -11,6 +12,7 @@ import { type XPathEngine } from '../model/customxml/xpath.mjs';
11
12
  import { ChangeTracker, type ChangeTrackingMode, type TrackingHost, type TrackingScope } from '../model/content/tracking.mjs';
12
13
  import { NumberingFacade } from '../model/content/List.mjs';
13
14
  import { StylesFacade } from '../model/content/stylesFacade.mjs';
15
+ import { GlossaryEntries } from '../model/content/placeholders.mjs';
14
16
  import type { Bound } from '../model/content/binder.mjs';
15
17
  import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
16
18
  import type { Emulator } from '../model/listnumbering/Emulator.mjs';
@@ -19,6 +21,9 @@ import { type RelationshipRemovals } from '../model/content/relationships.mjs';
19
21
  import { XmlPart } from '../parts/XmlPart.mjs';
20
22
  import type { PartSink } from '../opc/PartStore.mjs';
21
23
  import '../parts/wml/comments.mjs';
24
+ import '../model/text/outline.mjs';
25
+ import type { TextContext } from '../model/text/TextContext.mjs';
26
+ import type { TextOptions, TextOptionsInit } from '../model/text/TextOptions.mjs';
22
27
  /** The outline of a document: the body's paragraphs and tables, then each header's and footer's (loaded ones only). */
23
28
  export interface DocumentOutline extends Outline {
24
29
  headers: {
@@ -102,6 +107,12 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
102
107
  * 47). Settled on save, not at once, so a picture cut and pasted back keeps its image. An extension.
103
108
  */
104
109
  readonly pendingRelationshipRemovals: RelationshipRemovals;
110
+ /**
111
+ * The glossary's placeholder entries: read privately when a body is first read (`getBody`, `Word.run`), and those a
112
+ * placeholder written since names, which go into the glossary when the package is saved, the glossary made where the
113
+ * file has none (CR-002 section 63, D8 and D9). An extension.
114
+ */
115
+ readonly glossaryEntries: GlossaryEntries;
105
116
  /**
106
117
  * The parts `seedAnnotationIds()` has read, with what it read: `true` for a part still holding its
107
118
  * source, whose bytes cannot change, and otherwise the bytes that were set, which stay the same
@@ -212,10 +223,24 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
212
223
  private settingsPart;
213
224
  /**
214
225
  * Office JS `document.getTrackedChanges()`: every tracked change in the main document part,
215
- * in document order (headers and footers have their own `Body`). The part must be
216
- * unmarshalled, as `body` needs it to be.
226
+ * in document order (headers and footers have their own `Body`; `getAllTrackedChanges` lists
227
+ * every story). The part must be unmarshalled, as `body` needs it to be.
217
228
  */
218
229
  getTrackedChanges(): TrackedChange[];
230
+ /**
231
+ * Every tracked change in every story, in docx4j's order (its CR-043 `TrackedChanges.in`, CR-011):
232
+ * the main document, each footnote, each endnote, each comment, then the headers and footers in the
233
+ * order the sections reference them; a text box's after the story it is in. Each story's are its
234
+ * `Body.getTrackedChanges()`, grouped as Office JS groups them, so changes never group across two
235
+ * stories. `TrackedChange.part` says which part each is in.
236
+ *
237
+ * With a filter, the changes with a piece it matches, each whole (docx4j's `in(pkg, filter)`).
238
+ *
239
+ * A story part whose source holds no revision markup is not read, so it keeps its bytes; one that
240
+ * does is unmarshalled, since the views returned must be resolvable, and so is re-marshalled on save.
241
+ * An extension: Office JS lists one body at a time.
242
+ */
243
+ getAllTrackedChanges(filter?: TrackedChangeSelection): Promise<TrackedChange[]>;
219
244
  /**
220
245
  * Accepts every tracked change in every story: the main document, the footnotes, the endnotes and
221
246
  * the comments, the headers and footers, and the text boxes in each. Word's
@@ -223,15 +248,19 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
223
248
  * revision in any story; `Body.acceptAll` resolves its own story only, as Office JS's `body` does
224
249
  * (CR-002 section 49). A story part with no revision markup is not read, so it keeps its bytes.
225
250
  * Returns how many changes were listed, story by story. An extension, named after Word's verb.
251
+ *
252
+ * With a filter (CR-011), only the single changes it matches are accepted, as `Body.acceptAll`
253
+ * takes one, and the count is of the listed changes with a matching piece.
226
254
  */
227
- acceptAllRevisions(): Promise<number>;
255
+ acceptAllRevisions(filter?: TrackedChangeSelection): Promise<number>;
228
256
  /** Rejects every tracked change in every story, as `acceptAllRevisions` accepts them (Word's `Document.RejectAllRevisions`). */
229
- rejectAllRevisions(): Promise<number>;
257
+ rejectAllRevisions(filter?: TrackedChangeSelection): Promise<number>;
230
258
  private resolveEveryStory;
231
259
  /**
232
260
  * The body of every story whose part holds revision markup, in docx4j's order (its CR-043
233
261
  * `TrackedChanges.in`): the main document, each footnote, each endnote, each comment, then the
234
- * headers and footers. A footnote, an endnote or a comment is a body of its own over its content.
262
+ * headers and footers in section order (`inSectionOrder`). A footnote, an endnote or a comment is a
263
+ * body of its own over its content.
235
264
  */
236
265
  private revisedStories;
237
266
  /** The tracker every content-API mutation asks for; undefined while the mode is `Off`. */
@@ -294,10 +323,18 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
294
323
  /** A clone carries the identity, the tracking date, the theme setting, the XPath engine and the styles still to ensure. */
295
324
  protected copyPackageSettingsTo(target: OpcPackage): void;
296
325
  saveTo<R>(sink: PartSink<R>): Promise<R>;
297
- /** The paragraph at an address anywhere in the document: 'body/3', 'header:rId5/0', a paraId, or a text match. */
326
+ /**
327
+ * The paragraph at an address anywhere in the document: 'body/3', 'header:rId5/0', 'footnote:2/0',
328
+ * 'endnote:1/0', 'comment:5/0', 'body/3/textbox:0/1' (a text box's paragraph, read-only: CR-012 D4 and
329
+ * D5), a paraId, or a text match. Undefined where the address names no paragraph.
330
+ */
298
331
  paragraphAt(address: Address): Promise<Paragraph | undefined>;
299
- /** Every paragraph and table with its address, style and text (CR-002 section 3.3). Unmarshals the main part, headers and footers. */
300
- outline(): Promise<DocumentOutline>;
332
+ /**
333
+ * Every paragraph and table with its address, style and text (CR-002 section 3.3), read by the text model
334
+ * under one context (CR-012 D3: `Body.outline`, whose options it takes): the main document, then each
335
+ * header and footer. Unmarshals the main part, headers and footers.
336
+ */
337
+ outline(options?: TextOptionsInit | TextOptions, context?: TextContext): Promise<DocumentOutline>;
301
338
  private bodies;
302
339
  /**
303
340
  * The XPath engine the custom XML views use (CR-002 section 3.6): `document.evaluate` in a
@@ -4,27 +4,33 @@ import { registerPackageClass } from './registry.mjs';
4
4
  import { ContentTypes } from '../opc/ContentTypes.mjs';
5
5
  import { Docx4JException } from '../opc/exceptions.mjs';
6
6
  import { Namespaces } from '../parts/Namespaces.mjs';
7
- import { MainDocumentPart, StyleDefinitionsPart, DocumentSettingsPart } from '../parts/wml/index.mjs';
7
+ import { MainDocumentPart, StyleDefinitionsPart, DocumentSettingsPart, GlossaryDocumentPart } from '../parts/wml/index.mjs';
8
8
  import { DocPropsCorePart, DocPropsExtendedPart } from '../parts/docProps/index.mjs';
9
9
  import { DEFAULT_STYLES_XML } from '../parts/wml/defaultStyles.mjs';
10
10
  import { ThemePart } from '../parts/dml/index.mjs';
11
11
  import { newFontSettings, themeOfSettings, } from '../model/fonts/defaultTheme.mjs';
12
12
  import { HeaderPart, FooterPart } from '../parts/wml/index.mjs';
13
- import { Body, resolveStory } from '../model/content/Body.mjs';
13
+ import { Body, resolveStory, trackedChangesOfStory } from '../model/content/Body.mjs';
14
+ import { pieceMatcher } from '../model/content/trackedChangeFilter.mjs';
14
15
  import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
15
16
  import { DefaultXPathEngine } from '../model/customxml/xpath.mjs';
16
17
  import { ChangeTracker, highestAnnotationId } from '../model/content/tracking.mjs';
17
18
  import { NumberingFacade } from '../model/content/List.mjs';
18
19
  import { StylesFacade } from '../model/content/stylesFacade.mjs';
19
20
  import { flushPendingCommentRemovals } from '../model/content/Comment.mjs';
21
+ import { GlossaryEntries } from '../model/content/placeholders.mjs';
20
22
  import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
21
23
  import { PropertyResolverNotCreatedException } from '../opc/exceptions.mjs';
22
- import { flushPendingNoteRemovals } from '../model/content/TrackedChange.mjs';
24
+ import { flushPendingNoteRemovals, notesGoing } from '../model/content/TrackedChange.mjs';
23
25
  import { flushPendingRelationshipRemovals } from '../model/content/relationships.mjs';
24
26
  import { XmlPart } from '../parts/XmlPart.mjs';
25
27
  // Registers the comment parts with the content API (CR-002 phase G); no cycle: the model half
26
28
  // never imports a part, as packages/registry.mts does for the package classes.
27
29
  import '../parts/wml/comments.mjs';
30
+ // Registers the text model's outline reader with Body.outline (CR-012 D3), the same way: the content API
31
+ // can't import the text model, which imports it.
32
+ import '../model/text/outline.mjs';
33
+ import { Texts } from '../model/text/Texts.mjs';
28
34
  const MAIN_CONTENT_TYPES = [
29
35
  ContentTypes.WORDPROCESSINGML_DOCUMENT,
30
36
  ContentTypes.WORDPROCESSINGML_DOCUMENT_MACROENABLED,
@@ -105,6 +111,12 @@ export class WordprocessingMLPackage extends OpcPackage {
105
111
  * 47). Settled on save, not at once, so a picture cut and pasted back keeps its image. An extension.
106
112
  */
107
113
  this.pendingRelationshipRemovals = new Map();
114
+ /**
115
+ * The glossary's placeholder entries: read privately when a body is first read (`getBody`, `Word.run`), and those a
116
+ * placeholder written since names, which go into the glossary when the package is saved, the glossary made where the
117
+ * file has none (CR-002 section 63, D8 and D9). An extension.
118
+ */
119
+ this.glossaryEntries = new GlossaryEntries();
108
120
  /**
109
121
  * The parts `seedAnnotationIds()` has read, with what it read: `true` for a part still holding its
110
122
  * source, whose bytes cannot change, and otherwise the bytes that were set, which stay the same
@@ -159,7 +171,8 @@ export class WordprocessingMLPackage extends OpcPackage {
159
171
  if (landscape)
160
172
  pgSz.orient = 'landscape';
161
173
  const pgMar = { top: 1440, right: 1440, bottom: 1440, left: 1440, header: 708, footer: 708, gutter: 0 };
162
- const document = { body: { content: [], sectPr: { pgSz, pgMar } } };
174
+ // typed, as a loaded document is, so the objects facade's walks (its onMisplaced, CR-016) see the body as a container
175
+ const document = { TYPE_NAME: 'org_docx4j_wml.Document', body: { TYPE_NAME: 'org_docx4j_wml.Body', content: [], sectPr: { TYPE_NAME: 'org_docx4j_wml.SectPr', pgSz, pgMar } } };
163
176
  const main = new MainDocumentPart();
164
177
  main.setContents(document);
165
178
  pkg.addTargetPart(main);
@@ -414,12 +427,32 @@ export class WordprocessingMLPackage extends OpcPackage {
414
427
  }
415
428
  /**
416
429
  * Office JS `document.getTrackedChanges()`: every tracked change in the main document part,
417
- * in document order (headers and footers have their own `Body`). The part must be
418
- * unmarshalled, as `body` needs it to be.
430
+ * in document order (headers and footers have their own `Body`; `getAllTrackedChanges` lists
431
+ * every story). The part must be unmarshalled, as `body` needs it to be.
419
432
  */
420
433
  getTrackedChanges() {
421
434
  return this.body.getTrackedChanges();
422
435
  }
436
+ /**
437
+ * Every tracked change in every story, in docx4j's order (its CR-043 `TrackedChanges.in`, CR-011):
438
+ * the main document, each footnote, each endnote, each comment, then the headers and footers in the
439
+ * order the sections reference them; a text box's after the story it is in. Each story's are its
440
+ * `Body.getTrackedChanges()`, grouped as Office JS groups them, so changes never group across two
441
+ * stories. `TrackedChange.part` says which part each is in.
442
+ *
443
+ * With a filter, the changes with a piece it matches, each whole (docx4j's `in(pkg, filter)`).
444
+ *
445
+ * A story part whose source holds no revision markup is not read, so it keeps its bytes; one that
446
+ * does is unmarshalled, since the views returned must be resolvable, and so is re-marshalled on save.
447
+ * An extension: Office JS lists one body at a time.
448
+ */
449
+ async getAllTrackedChanges(filter) {
450
+ const matches = filter === undefined ? undefined : pieceMatcher(filter);
451
+ const out = [];
452
+ for (const body of await this.revisedStories())
453
+ out.push(...trackedChangesOfStory(body));
454
+ return matches ? out.filter((change) => change.pieces.some(matches)) : out;
455
+ }
423
456
  /**
424
457
  * Accepts every tracked change in every story: the main document, the footnotes, the endnotes and
425
458
  * the comments, the headers and footers, and the text boxes in each. Word's
@@ -427,24 +460,30 @@ export class WordprocessingMLPackage extends OpcPackage {
427
460
  * revision in any story; `Body.acceptAll` resolves its own story only, as Office JS's `body` does
428
461
  * (CR-002 section 49). A story part with no revision markup is not read, so it keeps its bytes.
429
462
  * Returns how many changes were listed, story by story. An extension, named after Word's verb.
463
+ *
464
+ * With a filter (CR-011), only the single changes it matches are accepted, as `Body.acceptAll`
465
+ * takes one, and the count is of the listed changes with a matching piece.
430
466
  */
431
- async acceptAllRevisions() {
432
- return this.resolveEveryStory('accept');
467
+ async acceptAllRevisions(filter) {
468
+ return this.resolveEveryStory('accept', filter);
433
469
  }
434
470
  /** Rejects every tracked change in every story, as `acceptAllRevisions` accepts them (Word's `Document.RejectAllRevisions`). */
435
- async rejectAllRevisions() {
436
- return this.resolveEveryStory('reject');
471
+ async rejectAllRevisions(filter) {
472
+ return this.resolveEveryStory('reject', filter);
437
473
  }
438
- async resolveEveryStory(what) {
474
+ async resolveEveryStory(what, filter) {
475
+ if (filter !== undefined)
476
+ pieceMatcher(filter); // a filter misread throws before anything is read or resolved
439
477
  let count = 0;
440
478
  for (const body of await this.revisedStories())
441
- count += resolveStory(body, what);
479
+ count += resolveStory(body, what, filter);
442
480
  return count;
443
481
  }
444
482
  /**
445
483
  * The body of every story whose part holds revision markup, in docx4j's order (its CR-043
446
484
  * `TrackedChanges.in`): the main document, each footnote, each endnote, each comment, then the
447
- * headers and footers. A footnote, an endnote or a comment is a body of its own over its content.
485
+ * headers and footers in section order (`inSectionOrder`). A footnote, an endnote or a comment is a
486
+ * body of its own over its content.
448
487
  */
449
488
  async revisedStories() {
450
489
  var _a, _b;
@@ -452,22 +491,33 @@ export class WordprocessingMLPackage extends OpcPackage {
452
491
  const out = [];
453
492
  if (await holdsRevisions(main))
454
493
  out.push(await main.getBody());
494
+ // a note or comment a resolution has taken the reference or anchor of goes on save; it is no story now
495
+ const pending = this.pendingNoteRemovals;
496
+ const going = pending.footnote.size + pending.endnote.size > 0 ? notesGoing(await main.readContents(), pending) : pending;
455
497
  for (const [part, kind] of [[main.footnotesPart, 'footnote'], [main.endnotesPart, 'endnote']]) {
456
498
  if (!part || !(await holdsRevisions(part)))
457
499
  continue;
458
500
  const contents = await part.getContents();
459
501
  for (const note of (_a = (kind === 'footnote' ? contents.footnote : contents.endnote)) !== null && _a !== void 0 ? _a : []) {
502
+ if ((note.type === undefined || note.type === 'normal') && going[kind].has(Number(note.id)))
503
+ continue;
460
504
  out.push(new Body(part, note, `${kind}:${note.id}`, this));
461
505
  }
462
506
  }
463
507
  const comments = main.commentsPart;
464
508
  if (comments && (await holdsRevisions(comments))) {
465
- for (const comment of (_b = (await comments.getContents()).comment) !== null && _b !== void 0 ? _b : [])
509
+ for (const comment of (_b = (await comments.getContents()).comment) !== null && _b !== void 0 ? _b : []) {
510
+ if (this.pendingCommentRemovals.has(comment.id))
511
+ continue;
466
512
  out.push(new Body(comments, comment, `comment:${comment.id}`, this));
513
+ }
467
514
  }
515
+ const revised = [];
468
516
  for (const part of [...main.headerParts, ...main.footerParts])
469
517
  if (await holdsRevisions(part))
470
- out.push(await part.getBody());
518
+ revised.push(part);
519
+ for (const part of revised.length > 1 ? await inSectionOrder(main, revised) : revised)
520
+ out.push(await part.getBody());
471
521
  return out;
472
522
  }
473
523
  /** The tracker every content-API mutation asks for; undefined while the mode is `Off`. */
@@ -583,6 +633,7 @@ export class WordprocessingMLPackage extends OpcPackage {
583
633
  target.pendingNoteRemovals.endnote.add(id);
584
634
  for (const [name, ids] of this.pendingRelationshipRemovals)
585
635
  target.pendingRelationshipRemovals.set(name, new Set(ids));
636
+ this.glossaryEntries.copyTo(target.glossaryEntries);
586
637
  target.trackedChangeDate = this.trackedChangeDate;
587
638
  target.fonts.defaultTheme = this.fonts.defaultTheme;
588
639
  target.xpathEngine = this.xpathEngine;
@@ -603,13 +654,23 @@ export class WordprocessingMLPackage extends OpcPackage {
603
654
  }
604
655
  if (this.pendingRelationshipRemovals.size > 0)
605
656
  flushPendingRelationshipRemovals(this, this.pendingRelationshipRemovals);
657
+ if (this.glossaryEntries.waiting) {
658
+ await this.glossaryEntries.flush(this, {
659
+ glossary: () => new GlossaryDocumentPart(),
660
+ styles: () => new StyleDefinitionsPart('/word/glossary/styles.xml'),
661
+ });
662
+ }
606
663
  if (this.requiredStyles.size > 0) {
607
664
  await this.styles.ensure([...this.requiredStyles]);
608
665
  this.requiredStyles.clear();
609
666
  }
610
667
  return super.saveTo(sink);
611
668
  }
612
- /** The paragraph at an address anywhere in the document: 'body/3', 'header:rId5/0', a paraId, or a text match. */
669
+ /**
670
+ * The paragraph at an address anywhere in the document: 'body/3', 'header:rId5/0', 'footnote:2/0',
671
+ * 'endnote:1/0', 'comment:5/0', 'body/3/textbox:0/1' (a text box's paragraph, read-only: CR-012 D4 and
672
+ * D5), a paraId, or a text match. Undefined where the address names no paragraph.
673
+ */
613
674
  async paragraphAt(address) {
614
675
  for (const body of await this.bodies(address)) {
615
676
  const p = body.paragraphAt(address);
@@ -618,28 +679,44 @@ export class WordprocessingMLPackage extends OpcPackage {
618
679
  }
619
680
  return undefined;
620
681
  }
621
- /** Every paragraph and table with its address, style and text (CR-002 section 3.3). Unmarshals the main part, headers and footers. */
622
- async outline() {
682
+ /**
683
+ * Every paragraph and table with its address, style and text (CR-002 section 3.3), read by the text model
684
+ * under one context (CR-012 D3: `Body.outline`, whose options it takes): the main document, then each
685
+ * header and footer. Unmarshals the main part, headers and footers.
686
+ */
687
+ async outline(options, context) {
623
688
  var _a, _b, _c, _d;
624
689
  const main = await this.getBody();
625
- const out = { ...main.outline(), headers: [], footers: [] };
690
+ const ctx = context !== null && context !== void 0 ? context : await Texts.contextOf(this);
691
+ const out = { ...await main.outline(options, ctx), headers: [], footers: [] };
626
692
  for (const part of this.getMainDocumentPart().headerParts) {
627
693
  const body = await part.getBody();
628
- out.headers.push({ relId: (_b = (_a = part.sourceRelationship) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '', partName: part.partName.name, ...body.outline() });
694
+ out.headers.push({ relId: (_b = (_a = part.sourceRelationship) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '', partName: part.partName.name, ...await body.outline(options, ctx) });
629
695
  }
630
696
  for (const part of this.getMainDocumentPart().footerParts) {
631
697
  const body = await part.getBody();
632
- out.footers.push({ relId: (_d = (_c = part.sourceRelationship) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : '', partName: part.partName.name, ...body.outline() });
698
+ out.footers.push({ relId: (_d = (_c = part.sourceRelationship) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : '', partName: part.partName.name, ...await body.outline(options, ctx) });
633
699
  }
634
700
  return out;
635
701
  }
636
702
  async bodies(address) {
703
+ var _a;
637
704
  const main = this.getMainDocumentPart();
638
705
  if (typeof address === 'string' && !address.startsWith('w14:')) {
639
706
  const prefix = address.split('/')[0];
640
707
  if (prefix === 'body')
641
708
  return [await main.getBody()];
642
709
  const [kind, relId] = prefix.split(':');
710
+ if (kind === 'footnote' || kind === 'endnote' || kind === 'comment') {
711
+ // a note's or a comment's body, by its w:id, as the text model and Comment address them (CR-012 D4)
712
+ const part = kind === 'footnote' ? main.footnotesPart : kind === 'endnote' ? main.endnotesPart : main.commentsPart;
713
+ if (!part)
714
+ return [];
715
+ const contents = await part.getContents();
716
+ const entry = ((_a = contents[kind]) !== null && _a !== void 0 ? _a : []).find((e) => String(e.id) === relId);
717
+ await this.getPropertyResolver().catch(() => undefined);
718
+ return entry ? [new Body(part, entry, `${kind}:${relId}`, this)] : [];
719
+ }
643
720
  const parts = kind === 'header' ? main.headerParts : kind === 'footer' ? main.footerParts : [];
644
721
  const part = parts.find((p) => { var _a; return ((_a = p.sourceRelationship) === null || _a === void 0 ? void 0 : _a.id) === relId || p.partName.fileName === relId; });
645
722
  return part instanceof HeaderPart || part instanceof FooterPart ? [await part.getBody()] : [];
@@ -709,12 +786,72 @@ export class WordprocessingMLPackage extends OpcPackage {
709
786
  },
710
787
  customXmlRelationshipSource: () => this.getMainDocumentPart(),
711
788
  xhtmlHost: this,
789
+ getPropertyResolver: () => this.getPropertyResolver(),
712
790
  })));
713
791
  }
714
792
  get progId() {
715
793
  return 'Word.Document';
716
794
  }
717
795
  }
796
+ /**
797
+ * Headers and footers in docx4j's order (its CR-043 `Lister.headersAndFooters`): as the sections
798
+ * reference them, in document order, a part once, then any other in the order of the main part's
799
+ * relationships. The main part's tree is read privately, so a main part nobody has otherwise read keeps
800
+ * its bytes.
801
+ */
802
+ async function inSectionOrder(main, parts) {
803
+ var _a;
804
+ const rels = main.relationshipsPart;
805
+ if (!rels)
806
+ return parts;
807
+ const order = [];
808
+ const add = (part) => {
809
+ const known = parts.find((p) => p === part);
810
+ if (known && !order.includes(known))
811
+ order.push(known);
812
+ };
813
+ const body = (await main.readContents()).body;
814
+ for (const sectPr of sectionsOf(body))
815
+ for (const ref of (_a = sectPr.egHdrFtrReferences) !== null && _a !== void 0 ? _a : [])
816
+ add(rels.getPart(ref.id));
817
+ for (const rel of rels.list)
818
+ add(rels.getPart(rel));
819
+ for (const part of parts)
820
+ if (!order.includes(part))
821
+ order.push(part);
822
+ return order;
823
+ }
824
+ /**
825
+ * The body's `w:sectPr`s in document order, the paragraphs' first and the body's own last, as docx4j's
826
+ * walk finds them: not inside a run (where a text box's paragraphs are), DOM the model does not type
827
+ * left alone.
828
+ */
829
+ function sectionsOf(body) {
830
+ const out = [];
831
+ const visit = (o) => {
832
+ if (typeof o !== 'object' || o === null || typeof o.nodeType === 'number')
833
+ return;
834
+ if (Array.isArray(o)) {
835
+ for (const item of o)
836
+ visit(item);
837
+ return;
838
+ }
839
+ const typeName = o.TYPE_NAME;
840
+ if (typeName === 'org_docx4j_wml.SectPr') {
841
+ out.push(o);
842
+ return;
843
+ }
844
+ if (typeName === 'org_docx4j_wml.R')
845
+ return;
846
+ for (const key in o)
847
+ if (key !== 'PARENT')
848
+ visit(o[key]);
849
+ };
850
+ visit(body === null || body === void 0 ? void 0 : body.content);
851
+ if (body === null || body === void 0 ? void 0 : body.sectPr)
852
+ out.push(body.sectPr);
853
+ return out;
854
+ }
718
855
  /** Revision markup, by local name in any prefix: what a story part holds when it has a tracked change to resolve. */
719
856
  const REVISION_MARKUP = /<(?:[\w.-]+:)?(?:ins|del|moveFrom|moveTo|rPrChange|pPrChange|sectPrChange|tblPrChange|trPrChange|tcPrChange|tblGridChange|tblPrExChange|cellIns|cellDel|cellMerge|numberingChange|customXmlInsRangeStart|customXmlDelRangeStart)[\s/>]/;
720
857
  /**
@@ -1,4 +1,4 @@
1
- export { OpcPackage, type PackageSource } from './OpcPackage.mjs';
1
+ export { OpcPackage, type PackageSource, type PackageWarning, type Repaired } from './OpcPackage.mjs';
2
2
  export { WordprocessingMLPackage, type PageSizePaper, type CreatePackageOptions } from './WordprocessingMLPackage.mjs';
3
3
  export { PresentationMLPackage, createSlideSize, type SlideSizesWellKnown, type CreatePresentationOptions, } from './PresentationMLPackage.mjs';
4
4
  export { SpreadsheetMLPackage } from './SpreadsheetMLPackage.mjs';
@@ -2,7 +2,7 @@ import { Part } from './Part.mjs';
2
2
  import { ContentTypes } from '../opc/ContentTypes.mjs';
3
3
  import { Namespaces } from './Namespaces.mjs';
4
4
  import { Docx4JException } from '../opc/exceptions.mjs';
5
- import { parseXml, serializeXmlPart, encodeText, decodeXmlText } from '../xml/dom.mjs';
5
+ import { parseXml, serializeXmlPart, encodeText, decodeXmlText, assertXmlCharacters } from '../xml/dom.mjs';
6
6
  /**
7
7
  * An XML part the object model does not type, held as a DOM (docx4j DefaultXmlPart / XmlPart).
8
8
  * The document is parsed on first `getDocument()`; a part whose document was never requested is
@@ -71,7 +71,7 @@ export class DefaultXmlPart extends Part {
71
71
  }
72
72
  async getBytes() {
73
73
  if (this.document !== undefined)
74
- return encodeText(serializeXmlPart(this.document));
74
+ return encodeText(assertXmlCharacters(serializeXmlPart(this.document), `Part ${this.partName}`));
75
75
  if (this.bytes !== undefined)
76
76
  return this.bytes;
77
77
  const loaded = await this.loadSourceBytes();