@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
package/dist/opc/Save.mjs CHANGED
@@ -1,9 +1,40 @@
1
1
  import { CONTENT_TYPES_NAME } from './PartName.mjs';
2
2
  import { ContentTypes } from './ContentTypes.mjs';
3
- import { Docx4JException } from './exceptions.mjs';
3
+ import { Docx4JException, MisplacedContentException, SaveLossException } from './exceptions.mjs';
4
4
  import { Namespaces } from '../parts/Namespaces.mjs';
5
5
  import { isExternal } from '../parts/RelationshipsPart.mjs';
6
+ import { XmlPart, valueOutOfRange, misplacedContent } from '../parts/XmlPart.mjs';
6
7
  import { encodeText } from '../xml/dom.mjs';
8
+ function valueNormalised(partName, n) {
9
+ const after = n.after === null ? 'left out' : `written ${JSON.stringify(n.after)}`;
10
+ return {
11
+ code: 'value.normalised', partName, path: n.path, before: n.before, after: n.after,
12
+ message: `${partName}: ${n.path} ${n.before === undefined ? '(no value)' : JSON.stringify(n.before)} ${after}, as Word reads it`,
13
+ };
14
+ }
15
+ /**
16
+ * `pkg.writeTimesOnSave` (CR-018; docx4j `DocPropsCorePart.writeTimes` under `docx4j.dcterms.write`): `dcterms:modified`
17
+ * now, UTC to the second in the W3CDTF form Office writes, and `dcterms:created` too for a package created here (one with
18
+ * no source container) that has none, its core properties part made for it. A loaded package without the part is left
19
+ * without one, as docx4j leaves it. The part is unmarshalled for the write, so it is marshalled by this save.
20
+ */
21
+ async function writeTimes(pkg) {
22
+ const isNew = pkg.sourcePartStore === undefined;
23
+ let part = pkg.docPropsCorePart;
24
+ if (!part) {
25
+ if (!isNew)
26
+ return;
27
+ part = pkg.addDocPropsCorePart();
28
+ }
29
+ await part.getContents();
30
+ const props = part.contents;
31
+ const now = () => ({
32
+ TYPE_NAME: 'org_docx4j_docProps_core_dc_terms.W3CDTF', content: [new Date().toISOString().replace(/\.\d{3}Z$/, 'Z')],
33
+ });
34
+ if (props.created === undefined && isNew)
35
+ props.created = now();
36
+ props.modified = now();
37
+ }
7
38
  /**
8
39
  * Writes a package to a sink (docx4j io3.Save): `[Content_Types].xml` first, then the package
9
40
  * relationships, then every part reachable through relationships, each once. Relationship parts
@@ -11,16 +42,68 @@ import { encodeText } from '../xml/dom.mjs';
11
42
  * container unchanged.
12
43
  */
13
44
  export async function savePackage(pkg, sink) {
45
+ if (pkg.writeTimesOnSave)
46
+ await writeTimes(pkg);
14
47
  const saver = new Saver(pkg, sink);
48
+ await saver.settleLosses(); // before anything is written, whatever the sink
15
49
  sink.put(CONTENT_TYPES_NAME, encodeText(pkg.contentTypeManager.toXml()), { contentType: ContentTypes.CONTENT_TYPES_PART });
16
50
  await saver.saveRels(pkg.relationshipsPart);
17
- return sink.finish();
51
+ const result = await sink.finish();
52
+ pkg.lastSave = { normalised: saver.normalised, outOfRange: saver.outOfRange, misplaced: saver.misplaced, dropped: saver.dropped, lost: saver.lost };
53
+ return result;
18
54
  }
19
55
  class Saver {
20
56
  constructor(pkg, sink) {
21
57
  this.pkg = pkg;
22
58
  this.sink = sink;
23
59
  this.handled = new Set();
60
+ this.normalised = [];
61
+ this.outOfRange = [];
62
+ this.misplaced = [];
63
+ this.dropped = [];
64
+ this.lost = [];
65
+ /** Parts holding skipped content, read and not changed: written from their source (CR-025 section 2.2). */
66
+ this.copied = new Set();
67
+ }
68
+ /**
69
+ * CR-025 sections 2.2, 2.3 and 10, over the parts this save reaches: one holding what its read dropped is copied if it hasn't
70
+ * changed. If it has, what Word's own save drops too is written without and listed (`dropped`), and for the rest the save is
71
+ * refused for all such parts at once, or, with `checkLossOnSave` off, says what went (`lost`).
72
+ */
73
+ async settleLosses() {
74
+ const losses = [];
75
+ const seen = new Set();
76
+ const visit = async (rp) => {
77
+ for (const r of rp.list) {
78
+ if (r.type === Namespaces.HYPERLINK || isExternal(r))
79
+ continue;
80
+ const part = this.pkg.getPart(rp.resolveTarget(r));
81
+ if (!part || seen.has(part.partName.key))
82
+ continue;
83
+ seen.add(part.partName.key);
84
+ if (part instanceof XmlPart) {
85
+ const skipped = part.skippedByRead;
86
+ if (skipped.length > 0) {
87
+ if (await part.isUnchangedSinceRead())
88
+ this.copied.add(part.partName.key);
89
+ else {
90
+ this.dropped.push(...skipped.filter((w) => w.onSave === 'dropped'));
91
+ const lost = skipped.filter((w) => w.onSave === 'lost');
92
+ if (lost.length > 0 && this.pkg.checkLossOnSave)
93
+ losses.push({ partName: part.partName.name, kind: 'skipped', count: lost.length });
94
+ else
95
+ this.lost.push(...lost);
96
+ }
97
+ }
98
+ }
99
+ const rrp = part.relationshipsPart;
100
+ if (rrp && rrp.size > 0)
101
+ await visit(rrp);
102
+ }
103
+ };
104
+ await visit(this.pkg.relationshipsPart);
105
+ if (losses.length > 0)
106
+ throw new SaveLossException(losses);
24
107
  }
25
108
  async saveRels(rp) {
26
109
  this.sink.put(rp.partName.storeName, await rp.getBytes(), { contentType: ContentTypes.RELATIONSHIPS_PART });
@@ -37,12 +120,35 @@ class Saver {
37
120
  if (this.handled.has(part.partName.key))
38
121
  return;
39
122
  this.handled.add(part.partName.key);
123
+ if (this.copied.has(part.partName.key)) {
124
+ this.sink.put(part.partName.storeName, (await part.bytesRead()), { compress: part.compress, contentType: part.contentType });
125
+ const held = part.relationshipsPart;
126
+ if (held && held.size > 0)
127
+ await this.saveRels(held);
128
+ return;
129
+ }
40
130
  let bytes;
131
+ // CR-016 D2: a child its container never admits refuses the save, every one in the part listed, unless
132
+ // pkg.checkContentOnSave is off, when each is written as held and reported; the runtime's own refusal (a string in a
133
+ // run) names what the walk reported either way, where before it said nothing of the cause
134
+ const misplaced = [];
41
135
  try {
42
- bytes = await part.getBytes();
136
+ bytes = await part.getBytes({
137
+ onNormalised: (n) => this.normalised.push(valueNormalised(part.partName.name, n)),
138
+ onOutOfRange: (r) => this.outOfRange.push(valueOutOfRange(r, part.partName.name)),
139
+ onMisplaced: (r) => misplaced.push(misplacedContent(r, part.partName.name)),
140
+ });
43
141
  }
44
142
  catch (e) {
45
- throw new Docx4JException(`Problem saving part ${part.partName}`, { cause: e });
143
+ if (misplaced.length > 0 && this.pkg.checkContentOnSave)
144
+ throw new MisplacedContentException(part.partName.name, misplaced, { cause: e });
145
+ const because = misplaced.length > 0 ? `: ${misplaced.map((f) => f.message).join('; ')}` : '';
146
+ throw new Docx4JException(`Problem saving part ${part.partName}${because}`, { cause: e });
147
+ }
148
+ if (misplaced.length > 0) {
149
+ if (this.pkg.checkContentOnSave)
150
+ throw new MisplacedContentException(part.partName.name, misplaced);
151
+ this.misplaced.push(...misplaced);
46
152
  }
47
153
  this.sink.put(part.partName.storeName, bytes, { compress: part.compress, contentType: part.contentType });
48
154
  const rrp = part.relationshipsPart;
@@ -1,17 +1,19 @@
1
- import type { PartStore, PartSink, PutOptions } from './PartStore.mjs';
1
+ import { type PartStore, type PartSink, type PutOptions } from './PartStore.mjs';
2
2
  /**
3
3
  * A zip container read from bytes (docx4j io3.stores.ZipPartStore). The central directory is
4
4
  * read once; an entry is inflated on first `load` and then cached. ZIP64 archives are rejected.
5
+ * Entries are looked up as OPC part names, without case, and of two entries of one name the first
6
+ * in the central directory is the one read, the rest counted in `duplicates()` (CR-024).
5
7
  */
6
8
  export declare class ZipPartStore implements PartStore {
7
9
  private readonly data;
8
10
  private readonly entries;
9
- private readonly order;
10
11
  private readonly cache;
11
12
  constructor(source: Uint8Array | ArrayBuffer);
12
13
  partNames(): Iterable<string>;
13
14
  has(partName: string): boolean;
14
15
  size(partName: string): number | undefined;
16
+ duplicates(): ReadonlyMap<string, number>;
15
17
  load(partName: string): Promise<Uint8Array>;
16
18
  loadSync(partName: string): Uint8Array;
17
19
  private readCentralDirectory;
@@ -1,19 +1,21 @@
1
1
  import { inflateSync, zipSync } from 'fflate';
2
+ import { EntryIndex, entryKey } from './PartStore.mjs';
2
3
  import { InvalidFormatException } from './exceptions.mjs';
3
4
  /**
4
5
  * A zip container read from bytes (docx4j io3.stores.ZipPartStore). The central directory is
5
6
  * read once; an entry is inflated on first `load` and then cached. ZIP64 archives are rejected.
7
+ * Entries are looked up as OPC part names, without case, and of two entries of one name the first
8
+ * in the central directory is the one read, the rest counted in `duplicates()` (CR-024).
6
9
  */
7
10
  export class ZipPartStore {
8
11
  constructor(source) {
9
- this.entries = new Map();
10
- this.order = [];
12
+ this.entries = new EntryIndex();
11
13
  this.cache = new Map();
12
14
  this.data = source instanceof Uint8Array ? source : new Uint8Array(source);
13
15
  this.readCentralDirectory();
14
16
  }
15
17
  partNames() {
16
- return this.order;
18
+ return this.entries.names();
17
19
  }
18
20
  has(partName) {
19
21
  return this.entries.has(partName);
@@ -22,11 +24,15 @@ export class ZipPartStore {
22
24
  var _a;
23
25
  return (_a = this.entries.get(partName)) === null || _a === void 0 ? void 0 : _a.size;
24
26
  }
27
+ duplicates() {
28
+ return this.entries.duplicates();
29
+ }
25
30
  async load(partName) {
26
31
  return this.loadSync(partName);
27
32
  }
28
33
  loadSync(partName) {
29
- const cached = this.cache.get(partName);
34
+ const key = entryKey(partName);
35
+ const cached = this.cache.get(key);
30
36
  if (cached)
31
37
  return cached;
32
38
  const e = this.entries.get(partName);
@@ -47,7 +53,7 @@ export class ZipPartStore {
47
53
  bytes = inflateSync(raw);
48
54
  else
49
55
  throw new InvalidFormatException(`Unsupported compression method ${e.method} for ${partName}`);
50
- this.cache.set(partName, bytes);
56
+ this.cache.set(key, bytes);
51
57
  return bytes;
52
58
  }
53
59
  readCentralDirectory() {
@@ -85,8 +91,7 @@ export class ZipPartStore {
85
91
  p += 46 + nameLen + extraLen + commentLen;
86
92
  if (name.endsWith('/'))
87
93
  continue; // directory entry
88
- this.entries.set(name, { name, method, compressedSize, size, localHeaderOffset });
89
- this.order.push(name);
94
+ this.entries.add(name, { name, method, compressedSize, size, localHeaderOffset });
90
95
  }
91
96
  }
92
97
  }
@@ -1,3 +1,4 @@
1
+ import type { MisplacedContentWarning } from './mce/preprocessor.mjs';
1
2
  /** docx4j Docx4JException: anything the packaging layer cannot recover from. */
2
3
  export declare class Docx4JException extends Error {
3
4
  readonly cause: unknown;
@@ -11,6 +12,113 @@ export declare class InvalidFormatException extends Docx4JException {
11
12
  cause?: unknown;
12
13
  });
13
14
  }
15
+ /**
16
+ * A relationships part in another namespace, or in none, on its root or on any `Relationship` (CR-025 section 8, D10): refused when
17
+ * it is read, which is at the load, since the walk reads every relationships part it meets. Word reads such a part only through a
18
+ * repair, which reads every `Relationship` by its local name (the `rels-namespace` round), where the runtime here drops each one
19
+ * in a wrong namespace and with it the part it names, so a save would lose those parts with nothing said. `namespace` is the
20
+ * namespace found, `null` for none. The code is docx4j's and the WD's. `LoadOptions.repair: 'word'` reads such a part as Word's
21
+ * repair does, every `Relationship` by its local name (CR-031 section 2.3).
22
+ */
23
+ export declare class RelationshipsNamespaceException extends InvalidFormatException {
24
+ readonly partName: string;
25
+ readonly namespace: string | null;
26
+ /** The finding's code, the WD's, shared with docx4j and docx4j-python. */
27
+ readonly code = "package.relationships_namespace";
28
+ constructor(partName: string, namespace: string | null);
29
+ }
30
+ /**
31
+ * A package whose container holds two entries of one name, OPC part names compared without case (WD REQ-206; CR-024),
32
+ * refused when it is loaded, before anything is read. Word reads such a file only after a repair, and the readers that
33
+ * don't refuse read different copies. `entries` gives each duplicated name, as its first entry spells it, with the
34
+ * number of entries; `LoadOptions.repair: 'word'` reads the first copy of each instead (CR-031).
35
+ */
36
+ export declare class DuplicateEntryException extends InvalidFormatException {
37
+ readonly entries: Readonly<Record<string, number>>;
38
+ /** The finding's code, shared with docx4j-python (its CR-032). */
39
+ readonly code = "package.duplicate_entry";
40
+ constructor(entries: Readonly<Record<string, number>>);
41
+ }
42
+ /**
43
+ * Under `LoadOptions.repair: 'word'` or `'all'`, a name the container holds more than one entry of (WD REQ-206; CR-024):
44
+ * the first entry in the container's order is read, the rest ignored, and a save writes only the copy read, as Word's
45
+ * repaired save does. On `pkg.warnings`, ahead of the parts' warnings. The code and the fields are docx4j-python's (its
46
+ * CR-032): `entry`, the name as the first entry spells it (no leading '/'), and `count`, the entries of that name.
47
+ */
48
+ export interface DuplicateEntryWarning {
49
+ code: 'package.duplicate_entry';
50
+ entry: string;
51
+ count: number;
52
+ message: string;
53
+ }
54
+ /**
55
+ * A package whose package relationships hold more than one officeDocument relationship (WD REQ-206's statement, WD 0.100;
56
+ * CR-024 section 9), refused when it is loaded, as a duplicated entry is and for the same reason: Word reads such a file
57
+ * only through a repair, and which target it reads then alternates with each repaired open in a Word session. A
58
+ * transitional and a strict relationship are two, and so are two naming one target. An External one names no part and
59
+ * isn't counted. `targets` gives each as a part name (`/word/document.xml`), in the relationships' order.
60
+ * `LoadOptions.repair: 'word'` reads the last relationship's target instead, as a fresh Word does (CR-031).
61
+ */
62
+ export declare class MultipleMainPartsException extends InvalidFormatException {
63
+ readonly targets: readonly string[];
64
+ /** The finding's code, the WD's, shared with docx4j and docx4j-python. */
65
+ readonly code = "package.multiple_main_parts";
66
+ constructor(targets: readonly string[]);
67
+ }
68
+ /**
69
+ * Under `LoadOptions.repair: 'word'` or `'all'`, a package with more than one officeDocument relationship (WD REQ-206's
70
+ * statement; CR-024 section 9): the last relationship's target is read, as a fresh Word reads it, the other relationships
71
+ * go at the load, and a save writes the one main part. On `pkg.warnings`, after any `DuplicateEntryWarning` and ahead of
72
+ * the parts' warnings. The fields are docx4j-python's: `partName`, the part read (`/word/document.xml`), and `count`, the
73
+ * relationships there were.
74
+ */
75
+ export interface MultipleMainPartsWarning {
76
+ code: 'package.multiple_main_parts';
77
+ partName: string;
78
+ count: number;
79
+ message: string;
80
+ }
81
+ /**
82
+ * An `External` officeDocument relationship beside an internal one (WD REQ-206's NOTE, WD 0.102; CR-031 D3), refused at the load
83
+ * under `LoadOptions.repair` `'refuse'`, the default, and `'word'`, first or last alike: Word offers a repair and then fails
84
+ * (the `x-ext-*` rounds), so there is no reading of Word's to follow. `urls` gives each `External` relationship's target as
85
+ * written and `targets` each internal one's as a part name, in the relationships' order (docx4j-python's fields). The URL is
86
+ * never fetched. `repair: 'all'` reads the internal target instead, a repair of this package's own.
87
+ */
88
+ export declare class ExternalMainPartException extends InvalidFormatException {
89
+ readonly urls: readonly string[];
90
+ readonly targets: readonly string[];
91
+ /** The finding's code, the WD's, shared with docx4j and docx4j-python. */
92
+ readonly code = "package.external_main_part";
93
+ constructor(urls: readonly string[], targets: readonly string[]);
94
+ }
95
+ /**
96
+ * Under `LoadOptions.repair: 'all'`, an `External` officeDocument relationship beside an internal one (WD REQ-206's NOTE;
97
+ * CR-031 section 2.2): the internal target is read, every `External` officeDocument relationship goes at the load, so a save
98
+ * writes none, and the URL is never fetched. A repair of this package's own, so a reading's `repaired` is `own`. On
99
+ * `pkg.externalMainPart` and on `pkg.warnings`, after the other load warnings. `partName` is the part read, `urls` each URL
100
+ * as written, in the relationships' order (the text model's `detail` the first).
101
+ */
102
+ export interface ExternalMainPartWarning {
103
+ code: 'package.external_main_part';
104
+ partName: string;
105
+ urls: readonly string[];
106
+ message: string;
107
+ }
108
+ /**
109
+ * Under `LoadOptions.repair: 'word'` or `'all'`, a relationships part in another namespace, or in none, on its root or on any
110
+ * `Relationship` (CR-031 section 2.3; CR-025 section 8 refuses it otherwise): every `Relationship` is read by its local name,
111
+ * as Word's repair reads it, and a save writes the right namespace, so nothing is lost. On the relationships part's `warnings`
112
+ * and so on `pkg.warnings`. `partName` is the relationships part, `namespace` the first wrong one found (`null` for none),
113
+ * `count` the relationships read (the WD's `detail`, docx4j's).
114
+ */
115
+ export interface RelationshipsNamespaceWarning {
116
+ code: 'package.relationships_namespace';
117
+ partName: string;
118
+ namespace: string | null;
119
+ count: number;
120
+ message: string;
121
+ }
14
122
  /**
15
123
  * docx4j CyclicStylesException: a style's `w:basedOn` chain comes back to a style it already
16
124
  * holds, or goes deeper than docx4j's limit of 32. Thrown only when
@@ -70,3 +178,35 @@ export declare class PartUnmarshalException extends Docx4JException {
70
178
  readonly line: number | undefined;
71
179
  readonly column: number | undefined;
72
180
  }
181
+ /**
182
+ * A save refused for a child its container never admits (CR-016 D2): the part being marshalled holds a run straight in
183
+ * the body, a table in a paragraph, a string in a run, ..., which Word 365 refuses the file for or repairs by dropping
184
+ * content (check 72). Nothing was written. `findings` are the part's, each with its path and docx4j's message naming
185
+ * the fix; `pkg.checkContentOnSave = false` writes the file as held and reports them on `pkg.lastSave.misplaced` instead.
186
+ */
187
+ export declare class MisplacedContentException extends Docx4JException {
188
+ /** The part refused: `/word/document.xml`. */
189
+ readonly partName: string;
190
+ readonly findings: readonly MisplacedContentWarning[];
191
+ constructor(
192
+ /** The part refused: `/word/document.xml`. */
193
+ partName: string, findings: readonly MisplacedContentWarning[], options?: {
194
+ cause?: unknown;
195
+ });
196
+ }
197
+ /** One part a save would lose content from (CR-025 section 2.3). */
198
+ export interface ContentLoss {
199
+ partName: string;
200
+ kind: 'skipped';
201
+ /** The items its read dropped that Word's own save doesn't drop too: `part.skipped` with `onSave: 'lost'`, one each (CR-025 section 10). */
202
+ count: number;
203
+ }
204
+ /**
205
+ * A save refused because a part holding what its read dropped was changed, so a marshal would lose that (CR-025 section 2.3, the
206
+ * repair policy's P7). Nothing is written. The code and the wording are docx4j-python's, with this package's way past it.
207
+ */
208
+ export declare class SaveLossException extends Docx4JException {
209
+ readonly losses: readonly ContentLoss[];
210
+ readonly code = "save.content_lost";
211
+ constructor(losses: readonly ContentLoss[]);
212
+ }
@@ -13,6 +13,83 @@ export class InvalidFormatException extends Docx4JException {
13
13
  this.name = 'InvalidFormatException';
14
14
  }
15
15
  }
16
+ /**
17
+ * A relationships part in another namespace, or in none, on its root or on any `Relationship` (CR-025 section 8, D10): refused when
18
+ * it is read, which is at the load, since the walk reads every relationships part it meets. Word reads such a part only through a
19
+ * repair, which reads every `Relationship` by its local name (the `rels-namespace` round), where the runtime here drops each one
20
+ * in a wrong namespace and with it the part it names, so a save would lose those parts with nothing said. `namespace` is the
21
+ * namespace found, `null` for none. The code is docx4j's and the WD's. `LoadOptions.repair: 'word'` reads such a part as Word's
22
+ * repair does, every `Relationship` by its local name (CR-031 section 2.3).
23
+ */
24
+ export class RelationshipsNamespaceException extends InvalidFormatException {
25
+ constructor(partName, namespace) {
26
+ super(`${partName}: a relationships part in ${namespace === null ? 'no namespace' : `another namespace, ${namespace}`}, which Word reads `
27
+ + "only through a repair; refused, since its relationships would be lost with the parts they name. Load with { repair: 'word' } "
28
+ + 'to read every Relationship by its local name, as Word does (REQ-207)');
29
+ this.partName = partName;
30
+ this.namespace = namespace;
31
+ /** The finding's code, the WD's, shared with docx4j and docx4j-python. */
32
+ this.code = 'package.relationships_namespace';
33
+ this.name = 'RelationshipsNamespaceException';
34
+ }
35
+ }
36
+ /**
37
+ * A package whose container holds two entries of one name, OPC part names compared without case (WD REQ-206; CR-024),
38
+ * refused when it is loaded, before anything is read. Word reads such a file only after a repair, and the readers that
39
+ * don't refuse read different copies. `entries` gives each duplicated name, as its first entry spells it, with the
40
+ * number of entries; `LoadOptions.repair: 'word'` reads the first copy of each instead (CR-031).
41
+ */
42
+ export class DuplicateEntryException extends InvalidFormatException {
43
+ constructor(entries) {
44
+ const list = Object.entries(entries);
45
+ super(list.length === 1
46
+ ? `Duplicate entry ${list[0][0]} in this package: ${list[0][1]} entries (REQ-206). Load with { repair: 'word' } to read the first, as Word does (REQ-207)`
47
+ : `Duplicate entries in this package: ${list.map(([name, n]) => `${name}, ${n} entries`).join('; ')} (REQ-206). `
48
+ + "Load with { repair: 'word' } to read the first of each, as Word does (REQ-207)");
49
+ this.entries = entries;
50
+ /** The finding's code, shared with docx4j-python (its CR-032). */
51
+ this.code = 'package.duplicate_entry';
52
+ this.name = 'DuplicateEntryException';
53
+ }
54
+ }
55
+ /**
56
+ * A package whose package relationships hold more than one officeDocument relationship (WD REQ-206's statement, WD 0.100;
57
+ * CR-024 section 9), refused when it is loaded, as a duplicated entry is and for the same reason: Word reads such a file
58
+ * only through a repair, and which target it reads then alternates with each repaired open in a Word session. A
59
+ * transitional and a strict relationship are two, and so are two naming one target. An External one names no part and
60
+ * isn't counted. `targets` gives each as a part name (`/word/document.xml`), in the relationships' order.
61
+ * `LoadOptions.repair: 'word'` reads the last relationship's target instead, as a fresh Word does (CR-031).
62
+ */
63
+ export class MultipleMainPartsException extends InvalidFormatException {
64
+ constructor(targets) {
65
+ super(`${targets.length} officeDocument relationships in this package: ${targets.join(', ')} (REQ-206). `
66
+ + "Load with { repair: 'word' } to read the last, as a fresh Word does (REQ-207)");
67
+ this.targets = targets;
68
+ /** The finding's code, the WD's, shared with docx4j and docx4j-python. */
69
+ this.code = 'package.multiple_main_parts';
70
+ this.name = 'MultipleMainPartsException';
71
+ }
72
+ }
73
+ /**
74
+ * An `External` officeDocument relationship beside an internal one (WD REQ-206's NOTE, WD 0.102; CR-031 D3), refused at the load
75
+ * under `LoadOptions.repair` `'refuse'`, the default, and `'word'`, first or last alike: Word offers a repair and then fails
76
+ * (the `x-ext-*` rounds), so there is no reading of Word's to follow. `urls` gives each `External` relationship's target as
77
+ * written and `targets` each internal one's as a part name, in the relationships' order (docx4j-python's fields). The URL is
78
+ * never fetched. `repair: 'all'` reads the internal target instead, a repair of this package's own.
79
+ */
80
+ export class ExternalMainPartException extends InvalidFormatException {
81
+ constructor(urls, targets) {
82
+ super(`${urls.length === 1 ? 'An External officeDocument relationship' : `${urls.length} External officeDocument relationships`} in this package, `
83
+ + `to ${urls.join(', ')}, beside ${targets.length === 1 ? 'an internal one' : `${targets.length} internal ones`}, to ${targets.join(', ')} `
84
+ + "(REQ-206). Word refuses such a package, even through its repair. Load with { repair: 'all' } to read "
85
+ + `${targets[targets.length - 1]} and drop the External relationship, a repair of this package's own (REQ-207)`);
86
+ this.urls = urls;
87
+ this.targets = targets;
88
+ /** The finding's code, the WD's, shared with docx4j and docx4j-python. */
89
+ this.code = 'package.external_main_part';
90
+ this.name = 'ExternalMainPartException';
91
+ }
92
+ }
16
93
  /**
17
94
  * docx4j CyclicStylesException: a style's `w:basedOn` chain comes back to a style it already
18
95
  * holds, or goes deeper than docx4j's limit of 32. Thrown only when
@@ -78,3 +155,34 @@ export class PartUnmarshalException extends Docx4JException {
78
155
  this.column = options === null || options === void 0 ? void 0 : options.column;
79
156
  }
80
157
  }
158
+ /**
159
+ * A save refused for a child its container never admits (CR-016 D2): the part being marshalled holds a run straight in
160
+ * the body, a table in a paragraph, a string in a run, ..., which Word 365 refuses the file for or repairs by dropping
161
+ * content (check 72). Nothing was written. `findings` are the part's, each with its path and docx4j's message naming
162
+ * the fix; `pkg.checkContentOnSave = false` writes the file as held and reports them on `pkg.lastSave.misplaced` instead.
163
+ */
164
+ export class MisplacedContentException extends Docx4JException {
165
+ constructor(
166
+ /** The part refused: `/word/document.xml`. */
167
+ partName, findings, options) {
168
+ super(`Save refused: ${partName} holds ${findings.length === 1 ? 'a child its container never admits' : `${findings.length} children their containers never admit`}, `
169
+ + 'which Word 365 refuses the file for or repairs by dropping content (set pkg.checkContentOnSave = false to write it as held):\n'
170
+ + findings.map((f) => ` ${f.message}`).join('\n'), options);
171
+ this.partName = partName;
172
+ this.findings = findings;
173
+ this.name = 'MisplacedContentException';
174
+ }
175
+ }
176
+ /**
177
+ * A save refused because a part holding what its read dropped was changed, so a marshal would lose that (CR-025 section 2.3, the
178
+ * repair policy's P7). Nothing is written. The code and the wording are docx4j-python's, with this package's way past it.
179
+ */
180
+ export class SaveLossException extends Docx4JException {
181
+ constructor(losses) {
182
+ super(`Saving would lose content Word's own save keeps or isn't measured on: ${losses.map((l) => `${l.partName} holds ${l.count} item${l.count === 1 ? '' : 's'} the load skipped (part.skipped, onSave lost)`).join(', ')}. `
183
+ + `Set pkg.checkLossOnSave = false to write ${losses.length === 1 ? 'the part without it' : 'the parts without them'}.`);
184
+ this.losses = losses;
185
+ this.code = 'save.content_lost';
186
+ this.name = 'SaveLossException';
187
+ }
188
+ }
@@ -4,9 +4,12 @@ export { ContentTypeManager, CONTENT_TYPES_NS } from './ContentTypeManager.mjs';
4
4
  export { type PartStore, type PartSink, type PutOptions, MemoryPartStore, MemoryPartSink } from './PartStore.mjs';
5
5
  export { ZipPartStore, ZipPartSink } from './ZipPartStore.mjs';
6
6
  export { FlatOpcPartStore, FlatOpcPartSink, type FlatOpcSinkOptions, PKG_NS } from './FlatOpcPartStore.mjs';
7
- export { loadPackage, type LoadOptions } from './Load.mjs';
8
- export { savePackage } from './Save.mjs';
9
- export { mceKeep, mcePreprocess, createMcePreprocessor, resolveAlternateContent, preprocessAlternateContent, MCE_NS, KEPT_HOSTS, type McePreprocessOptions, type McBranchesDifferWarning, type PartWarning, type MceResult } from './mce/preprocessor.mjs';
10
- export { UNDERSTOOD_NAMESPACES, UNDERSTOOD_PREFIXES } from './mce/understood.mjs';
11
- export { Docx4JException, InvalidFormatException, PartUnrecognisedException, PartUnmarshalException, CyclicStylesException, PropertyResolverNotCreatedException } from './exceptions.mjs';
7
+ export { loadPackage, type LoadOptions, type RepairMode, REPAIR_MODES } from './Load.mjs';
8
+ export { savePackage, type ValueNormalised, type SaveReport } from './Save.mjs';
9
+ export { mceKeep, mcePreprocess, createMcePreprocessor, resolveAlternateContent, preprocessAlternateContent, MCE_NS, KEPT_HOSTS, type McePreprocessOptions, type McBranchesDifferWarning, type McNothingSelectedWarning, type McUndeclaredPrefixWarning, type ValueKeptWarning, type ValueOutOfRangeWarning, type MisplacedContentWarning, type PartWarning, type MceResult } from './mce/preprocessor.mjs';
10
+ export { repairBreaksOutsideRuns, type BrOutsideRunWarning } from './repair/breaks.mjs';
11
+ export { readMainPartRoot, type UnexpectedRootWarning } from './repair/mainRoot.mjs';
12
+ export type { ContentSkippedWarning } from './skipped.mjs';
13
+ export { UNDERSTOOD_NAMESPACES, TRAVERSAL_NAMESPACES } from './mce/understood.mjs';
14
+ export { Docx4JException, InvalidFormatException, PartUnrecognisedException, PartUnmarshalException, MisplacedContentException, SaveLossException, type ContentLoss, DuplicateEntryException, type DuplicateEntryWarning, MultipleMainPartsException, type MultipleMainPartsWarning, RelationshipsNamespaceException, type RelationshipsNamespaceWarning, ExternalMainPartException, type ExternalMainPartWarning, CyclicStylesException, PropertyResolverNotCreatedException } from './exceptions.mjs';
12
15
  export { parseXml, serializeXml, serializeXmlPart, createDocument, encodeText, decodeXmlText, stripXmlDeclaration, base64Encode, base64Decode, childElements, XML_DECLARATION } from '../xml/dom.mjs';
@@ -5,9 +5,11 @@ export { ContentTypeManager, CONTENT_TYPES_NS } from './ContentTypeManager.mjs';
5
5
  export { MemoryPartStore, MemoryPartSink } from './PartStore.mjs';
6
6
  export { ZipPartStore, ZipPartSink } from './ZipPartStore.mjs';
7
7
  export { FlatOpcPartStore, FlatOpcPartSink, PKG_NS } from './FlatOpcPartStore.mjs';
8
- export { loadPackage } from './Load.mjs';
8
+ export { loadPackage, REPAIR_MODES } from './Load.mjs';
9
9
  export { savePackage } from './Save.mjs';
10
10
  export { mceKeep, mcePreprocess, createMcePreprocessor, resolveAlternateContent, preprocessAlternateContent, MCE_NS, KEPT_HOSTS } from './mce/preprocessor.mjs';
11
- export { UNDERSTOOD_NAMESPACES, UNDERSTOOD_PREFIXES } from './mce/understood.mjs';
12
- export { Docx4JException, InvalidFormatException, PartUnrecognisedException, PartUnmarshalException, CyclicStylesException, PropertyResolverNotCreatedException } from './exceptions.mjs';
11
+ export { repairBreaksOutsideRuns } from './repair/breaks.mjs';
12
+ export { readMainPartRoot } from './repair/mainRoot.mjs';
13
+ export { UNDERSTOOD_NAMESPACES, TRAVERSAL_NAMESPACES } from './mce/understood.mjs';
14
+ export { Docx4JException, InvalidFormatException, PartUnrecognisedException, PartUnmarshalException, MisplacedContentException, SaveLossException, DuplicateEntryException, MultipleMainPartsException, RelationshipsNamespaceException, ExternalMainPartException, CyclicStylesException, PropertyResolverNotCreatedException } from './exceptions.mjs';
13
15
  export { parseXml, serializeXml, serializeXmlPart, createDocument, encodeText, decodeXmlText, stripXmlDeclaration, base64Encode, base64Decode, childElements, XML_DECLARATION } from '../xml/dom.mjs';