@docx4j/core-ts 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +34 -3
  3. package/dist/html/convert.mjs +40 -15
  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 +153 -19
  24. package/dist/model/content/Body.mjs +570 -131
  25. package/dist/model/content/Comment.d.mts +21 -3
  26. package/dist/model/content/Comment.mjs +202 -19
  27. package/dist/model/content/ContentControl.d.mts +197 -18
  28. package/dist/model/content/ContentControl.mjs +664 -95
  29. package/dist/model/content/Font.d.mts +67 -17
  30. package/dist/model/content/Font.mjs +114 -35
  31. package/dist/model/content/InlinePicture.d.mts +82 -7
  32. package/dist/model/content/InlinePicture.mjs +221 -28
  33. package/dist/model/content/List.mjs +13 -1
  34. package/dist/model/content/Paragraph.d.mts +213 -14
  35. package/dist/model/content/Paragraph.mjs +936 -100
  36. package/dist/model/content/Range.d.mts +242 -11
  37. package/dist/model/content/Range.mjs +975 -119
  38. package/dist/model/content/ResolvedView.d.mts +104 -0
  39. package/dist/model/content/ResolvedView.mjs +596 -0
  40. package/dist/model/content/Table.d.mts +29 -3
  41. package/dist/model/content/Table.mjs +109 -33
  42. package/dist/model/content/TrackedChange.d.mts +301 -16
  43. package/dist/model/content/TrackedChange.mjs +1284 -158
  44. package/dist/model/content/binder.d.mts +2 -1
  45. package/dist/model/content/binder.mjs +48 -1
  46. package/dist/model/content/comments.d.mts +20 -6
  47. package/dist/model/content/comments.mjs +67 -57
  48. package/dist/model/content/generalException.d.mts +18 -0
  49. package/dist/model/content/generalException.mjs +24 -0
  50. package/dist/model/content/index.d.mts +8 -3
  51. package/dist/model/content/index.mjs +7 -2
  52. package/dist/model/content/mathText.d.mts +21 -0
  53. package/dist/model/content/mathText.mjs +267 -0
  54. package/dist/model/content/officeText.d.mts +27 -0
  55. package/dist/model/content/officeText.mjs +74 -0
  56. package/dist/model/content/outline.d.mts +5 -0
  57. package/dist/model/content/outline.mjs +13 -0
  58. package/dist/model/content/placeholders.d.mts +110 -0
  59. package/dist/model/content/placeholders.mjs +253 -0
  60. package/dist/model/content/relationships.d.mts +30 -0
  61. package/dist/model/content/relationships.mjs +133 -0
  62. package/dist/model/content/search.d.mts +72 -0
  63. package/dist/model/content/search.mjs +204 -2
  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 +44 -0
  67. package/dist/model/content/story.mjs +92 -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 +100 -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 +28 -0
  79. package/dist/model/content/tracking.mjs +149 -10
  80. package/dist/model/content/tree.d.mts +212 -13
  81. package/dist/model/content/tree.mjs +356 -35
  82. package/dist/model/customxml/CustomXmlPartCollection.d.mts +8 -0
  83. package/dist/model/customxml/CustomXmlPartCollection.mjs +34 -11
  84. package/dist/model/customxml/XmlMapping.d.mts +1 -1
  85. package/dist/model/customxml/XmlMapping.mjs +11 -0
  86. package/dist/model/customxml/bindings.d.mts +21 -2
  87. package/dist/model/customxml/bindings.mjs +76 -32
  88. package/dist/model/customxml/kinds.d.mts +8 -3
  89. package/dist/model/customxml/kinds.mjs +26 -5
  90. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  91. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  92. package/dist/model/customxml/pictures.d.mts +9 -5
  93. package/dist/model/customxml/pictures.mjs +31 -13
  94. package/dist/model/customxml/xhtml.mjs +8 -2
  95. package/dist/model/fonts/families.generated.mjs +2 -2
  96. package/dist/model/fonts/registry.mjs +7 -1
  97. package/dist/model/fonts/substitutions.generated.mjs +2 -2
  98. package/dist/model/fonts/themes.generated.mjs +1 -1
  99. package/dist/model/index.d.mts +2 -0
  100. package/dist/model/index.mjs +4 -0
  101. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  102. package/dist/model/listnumbering/Emulator.mjs +63 -9
  103. package/dist/model/listnumbering/definitions.mjs +18 -0
  104. package/dist/model/properties/PropertyResolver.d.mts +87 -7
  105. package/dist/model/properties/PropertyResolver.mjs +197 -17
  106. package/dist/model/properties/catalogue.d.mts +32 -4
  107. package/dist/model/properties/catalogue.mjs +115 -36
  108. package/dist/model/properties/log.d.mts +1 -1
  109. package/dist/model/properties/log.mjs +5 -5
  110. package/dist/model/properties/table.d.mts +16 -2
  111. package/dist/model/properties/table.mjs +17 -5
  112. package/dist/model/text/Extractor.d.mts +289 -0
  113. package/dist/model/text/Extractor.mjs +2162 -0
  114. package/dist/model/text/LinkTargets.d.mts +45 -0
  115. package/dist/model/text/LinkTargets.mjs +170 -0
  116. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  117. package/dist/model/text/MarkdownExporter.mjs +255 -0
  118. package/dist/model/text/PlainText.d.mts +29 -0
  119. package/dist/model/text/PlainText.mjs +539 -0
  120. package/dist/model/text/TextContext.d.mts +161 -0
  121. package/dist/model/text/TextContext.mjs +425 -0
  122. package/dist/model/text/TextOptions.d.mts +150 -0
  123. package/dist/model/text/TextOptions.mjs +278 -0
  124. package/dist/model/text/TextResult.d.mts +504 -0
  125. package/dist/model/text/TextResult.mjs +526 -0
  126. package/dist/model/text/Texts.d.mts +99 -0
  127. package/dist/model/text/Texts.mjs +187 -0
  128. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  129. package/dist/model/text/WmlToMarkdown.mjs +911 -0
  130. package/dist/model/text/commonmark.d.mts +121 -0
  131. package/dist/model/text/commonmark.mjs +655 -0
  132. package/dist/model/text/index.d.mts +7 -0
  133. package/dist/model/text/index.mjs +8 -0
  134. package/dist/model/text/normalize.d.mts +8 -0
  135. package/dist/model/text/normalize.mjs +13 -0
  136. package/dist/model/text/outline.d.mts +4 -0
  137. package/dist/model/text/outline.mjs +71 -0
  138. package/dist/office-js/fragment.d.mts +7 -5
  139. package/dist/office-js/fragment.mjs +63 -14
  140. package/dist/office-js/proxy.d.mts +8 -0
  141. package/dist/office-js/proxy.mjs +29 -0
  142. package/dist/office-js/run.mjs +2 -0
  143. package/dist/office-js/supported.generated.mjs +16 -0
  144. package/dist/office-js/toApiScript.mjs +21 -5
  145. package/dist/opc/Load.d.mts +9 -2
  146. package/dist/opc/Save.d.mts +17 -0
  147. package/dist/opc/Save.mjs +12 -2
  148. package/dist/opc/index.d.mts +3 -3
  149. package/dist/opc/index.mjs +2 -2
  150. package/dist/opc/mce/preprocessor.d.mts +88 -7
  151. package/dist/opc/mce/preprocessor.mjs +144 -37
  152. package/dist/opc/mce/understood.d.mts +34 -0
  153. package/dist/opc/mce/understood.mjs +55 -3
  154. package/dist/packages/OpcPackage.d.mts +20 -0
  155. package/dist/packages/OpcPackage.mjs +16 -3
  156. package/dist/packages/WordprocessingMLPackage.d.mts +77 -7
  157. package/dist/packages/WordprocessingMLPackage.mjs +242 -11
  158. package/dist/parts/DefaultXmlPart.mjs +2 -2
  159. package/dist/parts/Part.d.mts +10 -2
  160. package/dist/parts/XmlPart.d.mts +35 -32
  161. package/dist/parts/XmlPart.mjs +107 -107
  162. package/dist/parts/wml/comments.mjs +30 -0
  163. package/dist/parts/wml/index.mjs +12 -0
  164. package/dist/xml/dom.d.mts +7 -0
  165. package/dist/xml/dom.mjs +18 -0
  166. package/package.json +2 -2
@@ -1,35 +1,43 @@
1
1
  import { unmarshalNode, marshalNode, NAMESPACE_PREFIXES } from '@docx4j/generated-objects-ts';
2
2
  import { Part } from './Part.mjs';
3
- import { Namespaces } from './Namespaces.mjs';
4
3
  import { Docx4JException, PartUnmarshalException } from '../opc/exceptions.mjs';
5
- import { parseXml, serializeXml, encodeText, decodeXmlText, XML_DECLARATION } from '../xml/dom.mjs';
6
- import { log } from '../model/properties/log.mjs';
4
+ import { parseXml, serializeXml, encodeText, decodeXmlText, XML_DECLARATION, assertXmlCharacters } from '../xml/dom.mjs';
7
5
  import { bindSnapshot, boundsOf } from '../model/content/binder.mjs';
8
- const XMLNS_NS = 'http://www.w3.org/2000/xmlns/';
9
- const MC_NS = Namespaces.MARKUP_COMPATIBILITY;
10
- /** The objects package's prefix table the other way round, prefix to URI, built once. */
11
- let prefixToUri;
12
- function knownUriOf(prefix) {
13
- if (prefixToUri === undefined) {
14
- prefixToUri = new Map();
15
- for (const [uri, p] of Object.entries(NAMESPACE_PREFIXES))
16
- if (p !== '' && !prefixToUri.has(p))
17
- prefixToUri.set(p, uri);
18
- }
19
- return prefixToUri.get(prefix);
20
- }
21
- const warnedPrefixes = new Set();
22
6
  /**
23
7
  * The element or attribute a located runtime error names, out of its message: jsonix writes
24
8
  * `w:sz/@w:val (line 7): ...` when it could place the fault and `w:bogus (line 3): ...` for an
25
9
  * element, so the location is everything before the position or the colon - and `w:sz` must not be
26
10
  * cut at its own prefix separator, which a naive split on `:` does.
27
11
  */
12
+ /** The runtime's located message: `w:sz/@w:val (line 12): reason`, the position optional. */
13
+ const LOCATION_PREFIX = /^(.+?)(?: \(line \d+(?:, column \d+)?\))?: /;
28
14
  function locationOf(message, located) {
29
15
  var _a;
30
16
  if (!located)
31
17
  return undefined;
32
- return (_a = /^(.+?)(?: \(line \d+(?:, column \d+)?\))?: /.exec(message)) === null || _a === void 0 ? void 0 : _a[1];
18
+ return (_a = LOCATION_PREFIX.exec(message)) === null || _a === void 0 ? void 0 : _a[1];
19
+ }
20
+ /** ` (line 12, column 9)`, or as much of it as is known. */
21
+ function positionOf(line, column) {
22
+ if (line === undefined)
23
+ return '';
24
+ return column === undefined ? ` (line ${line})` : ` (line ${line}, column ${column})`;
25
+ }
26
+ /** A value the objects facade read by Word's rule, as a warning on the part (CR-015 D8). */
27
+ function valueKept(reading, partName) {
28
+ var _a, _b, _c;
29
+ const node = reading.element;
30
+ const name = reading.attribute;
31
+ const attribute = (_c = (_b = (_a = node.getAttributeNodeNS) === null || _a === void 0 ? void 0 : _a.call(node, name.namespaceURI || null, name.localPart)) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : name.localPart;
32
+ const value = reading.value;
33
+ const read = value === true ? 'on' : value === undefined ? 'absent' : JSON.stringify(value);
34
+ return {
35
+ code: reading.kind, partName,
36
+ ...(typeof node.lineNumber === 'number' ? { line: node.lineNumber } : {}),
37
+ ...(typeof node.columnNumber === 'number' ? { column: node.columnNumber } : {}),
38
+ element: node.nodeName, attribute, text: reading.text, value,
39
+ message: `${partName}: ${node.nodeName}/@${attribute}=${JSON.stringify(reading.text)}${positionOf(node.lineNumber, node.columnNumber)} is not a value its type allows; read as ${read}, as Word 365 reads it`,
40
+ };
33
41
  }
34
42
  /** The objects package's prefix table as XPath wants it, prefix to URI; built once. */
35
43
  const NAMESPACE_PREFIXES_BY_PREFIX = (() => {
@@ -48,6 +56,7 @@ const NAMESPACE_PREFIXES_BY_PREFIX = (() => {
48
56
  export class XmlPart extends Part {
49
57
  constructor(partName, contentType, relationshipType, rootName) {
50
58
  super(partName, contentType, relationshipType);
59
+ this.parseWarnings = [];
51
60
  this.rootName = rootName;
52
61
  }
53
62
  /** True once contents were unmarshalled or set; the part is then re-marshalled on save. */
@@ -65,6 +74,15 @@ export class XmlPart extends Part {
65
74
  get isUntouched() {
66
75
  return this.element === undefined && this.bytes === undefined;
67
76
  }
77
+ /**
78
+ * What the last parse of this part reported: an mc:AlternateContent whose branches' text differs
79
+ * (`mce.branches_differ`, CR-010 phase 1), and each attribute value its type refuses that was read as
80
+ * Word 365 reads it (`value.kept.exact`, `value.kept.invalid`: CR-015 D8). Empty until the part is
81
+ * parsed, by `getContents()` or a private read, and again once its contents are set.
82
+ */
83
+ get warnings() {
84
+ return this.parseWarnings;
85
+ }
68
86
  /** The unmarshalled contents (docx4j getJaxbElement()); throws when not yet unmarshalled. */
69
87
  get contents() {
70
88
  if (this.element === undefined)
@@ -77,16 +95,15 @@ export class XmlPart extends Part {
77
95
  }
78
96
  /** Unmarshals on first call (docx4j getContents()). */
79
97
  async getContents() {
80
- var _a, _b, _c;
98
+ var _a, _b;
81
99
  if (this.element === undefined) {
82
100
  const bytes = (_a = this.bytes) !== null && _a !== void 0 ? _a : (await this.loadSourceBytes());
83
101
  if (bytes === undefined)
84
102
  throw new Docx4JException(`Part ${this.partName} has no content: set contents or load it from a container`);
85
- const doc = parseXml(decodeXmlText(bytes));
86
- this.recordDeclarations(doc);
87
- (_b = this.preprocessor) === null || _b === void 0 ? void 0 : _b.call(this, doc, this);
103
+ const doc = this.parse(bytes);
104
+ this.preprocess(doc);
88
105
  this.element = await this.unmarshal(doc);
89
- (_c = this.rootName) !== null && _c !== void 0 ? _c : (this.rootName = { namespaceURI: this.element.name.namespaceURI, localPart: this.element.name.localPart });
106
+ (_b = this.rootName) !== null && _b !== void 0 ? _b : (this.rootName = { namespaceURI: this.element.name.namespaceURI, localPart: this.element.name.localPart });
90
107
  this.bytes = undefined;
91
108
  }
92
109
  return this.element.value;
@@ -101,17 +118,21 @@ export class XmlPart extends Part {
101
118
  * reads the styles and numbering parts of a document nobody has otherwise touched.
102
119
  */
103
120
  async readContents() {
104
- var _a, _b;
121
+ var _a;
105
122
  if (this.element !== undefined)
106
123
  return this.element.value;
107
124
  const bytes = (_a = this.bytes) !== null && _a !== void 0 ? _a : (await this.loadSourceBytes());
108
125
  if (bytes === undefined)
109
126
  throw new Docx4JException(`Part ${this.partName} has no content: set contents or load it from a container`);
110
- const doc = parseXml(decodeXmlText(bytes));
111
- this.recordDeclarations(doc);
112
- (_b = this.preprocessor) === null || _b === void 0 ? void 0 : _b.call(this, doc, this);
127
+ const doc = this.parse(bytes);
128
+ this.preprocess(doc);
113
129
  return (await this.unmarshal(doc)).value;
114
130
  }
131
+ preprocess(doc) {
132
+ var _a;
133
+ const warnings = (_a = this.preprocessor) === null || _a === void 0 ? void 0 : _a.call(this, doc, this);
134
+ this.parseWarnings = warnings ? [...warnings] : [];
135
+ }
115
136
  /** Replaces the contents (docx4j setJaxbElement / setContents). The root name defaults to the part's. */
116
137
  setContents(value, rootName) {
117
138
  var _a, _b;
@@ -120,6 +141,7 @@ export class XmlPart extends Part {
120
141
  throw new Docx4JException(`Part ${this.partName}: no root element name; pass one`);
121
142
  this.element = { name: { namespaceURI: name.namespaceURI, localPart: name.localPart }, value };
122
143
  this.bytes = undefined;
144
+ this.parseWarnings = [];
123
145
  }
124
146
  /** Replaces the contents with raw XML bytes; they are unmarshalled on the next getContents(). */
125
147
  setBytes(bytes) {
@@ -135,9 +157,9 @@ export class XmlPart extends Part {
135
157
  return decodeXmlText(await this.getBytes());
136
158
  }
137
159
  /** Marshalled bytes when unmarshalled or set, else the source bytes untouched. */
138
- async getBytes() {
160
+ async getBytes(options) {
139
161
  if (this.element !== undefined)
140
- return encodeText(XML_DECLARATION + serializeXml(await this.marshalToNode()));
162
+ return encodeText(assertXmlCharacters(XML_DECLARATION + serializeXml(await this.marshalToNode(options)), `Part ${this.partName}`));
141
163
  if (this.bytes !== undefined)
142
164
  return this.bytes;
143
165
  const loaded = await this.loadSourceBytes();
@@ -175,99 +197,77 @@ export class XmlPart extends Part {
175
197
  const namespaces = { ...NAMESPACE_PREFIXES_BY_PREFIX, ...options.namespaces };
176
198
  return boundsOf(engine.select(xpath, snapshot.root, namespaces), snapshot);
177
199
  }
178
- /** The root element as a DOM element (docx4j XmlUtils.marshaltoW3CDomDocument). */
179
- async marshalToNode() {
200
+ /**
201
+ * The root element as a DOM element (docx4j XmlUtils.marshaltoW3CDomDocument). Run properties are written in
202
+ * their normal form unless the package's `normaliseOnSave` (else the objects package's `setNormaliseOnSave`) is
203
+ * false (CR-015 D2, the objects facade's CR-013 phase C): the tree keeps what it read.
204
+ */
205
+ async marshalToNode(options) {
206
+ var _a;
180
207
  if (this.element === undefined)
181
208
  await this.getContents();
182
- const root = await marshalNode(this.element);
183
- this.declareIgnorablePrefixes(root);
184
- return root;
209
+ const marshal = {};
210
+ const normalise = (_a = this.package) === null || _a === void 0 ? void 0 : _a.normaliseOnSave;
211
+ if (normalise !== undefined)
212
+ marshal.normaliseOnSave = normalise;
213
+ if ((options === null || options === void 0 ? void 0 : options.onNormalised) !== undefined)
214
+ marshal.onNormalised = options.onNormalised;
215
+ return marshalNode(this.element, marshal);
216
+ }
217
+ /**
218
+ * Parses the part's bytes, and names the part when the XML is not well-formed. xmldom's error
219
+ * (Node) carries the line and column of the fault; a browser's says them in its text, which
220
+ * `parseXml` passes on.
221
+ */
222
+ parse(bytes) {
223
+ try {
224
+ return parseXml(decodeXmlText(bytes));
225
+ }
226
+ catch (cause) {
227
+ const at = cause === null || cause === void 0 ? void 0 : cause.locator;
228
+ const line = typeof (at === null || at === void 0 ? void 0 : at.lineNumber) === 'number' ? at.lineNumber : undefined;
229
+ const column = typeof (at === null || at === void 0 ? void 0 : at.columnNumber) === 'number' ? at.columnNumber : undefined;
230
+ const reason = (cause instanceof Error ? cause.message : String(cause)).replace(/^Malformed XML: /, '');
231
+ throw new PartUnmarshalException(`${this.partName}: Malformed XML${positionOf(line, column)}: ${reason}`, this.partName.name, { cause, line, column });
232
+ }
185
233
  }
186
234
  /**
187
235
  * Unmarshals, and names the part when the runtime refuses. The runtime's own message says what is
188
236
  * wrong and, since `@docx4j/jsonix` 3.4.0, where - `w:sz/@w:val (line 12): Argument [NaN] must be
189
237
  * an integer` - but not which part it was reading, which is the first thing a person editing a
190
- * part's XML needs (CR-002 section 27). The location it found is lifted onto the exception so a
191
- * caller does not parse the message; `line` is undefined where the parser supplies no position,
192
- * which is every browser (only xmldom carries a locator).
238
+ * part's XML needs (CR-002 section 27), nor the value it refused. The message names the part, and
239
+ * for an attribute gives the value as written and the column too:
240
+ * `/word/styles.xml: w:sz/@w:val="big" (line 12, column 9): Argument [NaN] must be an integer, ...`.
241
+ * The location it found is lifted onto the exception so a caller does not parse the message; `line`
242
+ * is undefined where the parser supplies no position, which is every browser (only xmldom carries a
243
+ * locator).
193
244
  */
194
245
  async unmarshal(doc) {
195
- var _a, _b;
246
+ var _a, _b, _c, _d, _e, _f;
247
+ const kept = [];
196
248
  try {
197
- return await unmarshalNode(doc);
249
+ const element = await unmarshalNode(doc, {
250
+ onWordReading: (reading) => kept.push(valueKept(reading, this.partName.name)),
251
+ });
252
+ if (kept.length > 0)
253
+ this.parseWarnings = [...this.parseWarnings, ...kept];
254
+ return element;
198
255
  }
199
256
  catch (cause) {
200
257
  const located = cause;
201
258
  const message = typeof (located === null || located === void 0 ? void 0 : located.message) === 'string' ? located.message : String(cause);
202
- throw new PartUnmarshalException(`${this.partName}: ${message}`, this.partName.name, {
203
- cause,
204
- location: locationOf(message, (located === null || located === void 0 ? void 0 : located.jsonixLocated) === true),
205
- line: typeof ((_a = located === null || located === void 0 ? void 0 : located.node) === null || _a === void 0 ? void 0 : _a.lineNumber) === 'number' ? located.node.lineNumber : undefined,
206
- column: typeof ((_b = located === null || located === void 0 ? void 0 : located.node) === null || _b === void 0 ? void 0 : _b.columnNumber) === 'number' ? located.node.columnNumber : undefined,
207
- });
208
- }
209
- }
210
- /** The source root element's namespace declarations, prefix to URI (`xmlns=` is the empty prefix). */
211
- recordDeclarations(doc) {
212
- var _a;
213
- const root = doc.documentElement;
214
- if (!root)
215
- return;
216
- const map = new Map();
217
- for (const attr of Array.from(root.attributes)) {
218
- if (attr.name === 'xmlns')
219
- map.set('', attr.value);
220
- else if (attr.namespaceURI === XMLNS_NS || attr.name.startsWith('xmlns:'))
221
- map.set((_a = attr.localName) !== null && _a !== void 0 ? _a : attr.name.slice(6), attr.value);
222
- }
223
- this.sourceDeclarations = map;
224
- }
225
- /**
226
- * Every prefix the marshalled root's `mc:Ignorable` names must be declared on that root
227
- * (ECMA-376 Part 3 10.1.2; Word and Excel treat an undeclared one as a corrupt part and offer
228
- * to repair the file). The object model binds only the namespaces it has modules for, so an
229
- * `mc:Ignorable` prefix whose content was dropped on unmarshal - `xr6`, `xr10` and `xr2` on
230
- * Excel's `xl/workbook.xml`, for instance - loses its declaration: the runtime declares one
231
- * prefix per entry of the objects package's table and the facade can only *remove* unused
232
- * declarations, never add one it never made (CR-001 section 17).
233
- *
234
- * So the part re-declares them itself: from what the source root declared, else from the
235
- * objects package's `NAMESPACE_PREFIXES`. A prefix neither knows is dropped from
236
- * `mc:Ignorable` - an undeclared prefix is the one thing that must not be written - and warned
237
- * about once.
238
- */
239
- declareIgnorablePrefixes(root) {
240
- var _a, _b;
241
- const attr = Array.from(root.attributes).find((a) => { var _a; return a.namespaceURI === MC_NS && ((_a = a.localName) !== null && _a !== void 0 ? _a : a.name) === 'Ignorable'; });
242
- if (!attr)
243
- return;
244
- const prefixes = attr.value.split(/\s+/).filter((p) => p !== '');
245
- if (prefixes.length === 0)
246
- return;
247
- const kept = [];
248
- let dropped = false;
249
- for (const prefix of prefixes) {
250
- if (root.getAttributeNS(XMLNS_NS, prefix) || root.getAttribute(`xmlns:${prefix}`)) {
251
- kept.push(prefix);
252
- continue;
253
- }
254
- const uri = (_b = (_a = this.sourceDeclarations) === null || _a === void 0 ? void 0 : _a.get(prefix)) !== null && _b !== void 0 ? _b : knownUriOf(prefix);
255
- if (uri === undefined) {
256
- dropped = true;
257
- if (!warnedPrefixes.has(prefix)) {
258
- warnedPrefixes.add(prefix);
259
- log.warn(`${this.partName}: mc:Ignorable names the prefix "${prefix}", which nothing declares; dropping it (an undeclared prefix makes Word and Excel offer to repair the file)`);
260
- }
261
- continue;
259
+ const location = locationOf(message, (located === null || located === void 0 ? void 0 : located.jsonixLocated) === true);
260
+ const line = typeof ((_a = located === null || located === void 0 ? void 0 : located.node) === null || _a === void 0 ? void 0 : _a.lineNumber) === 'number' ? located.node.lineNumber : undefined;
261
+ const column = typeof ((_b = located === null || located === void 0 ? void 0 : located.node) === null || _b === void 0 ? void 0 : _b.columnNumber) === 'number' ? located.node.columnNumber : undefined;
262
+ let detail = message;
263
+ if (location !== undefined) {
264
+ const reason = message.slice((_d = (_c = LOCATION_PREFIX.exec(message)) === null || _c === void 0 ? void 0 : _c[0].length) !== null && _d !== void 0 ? _d : 0);
265
+ const name = located === null || located === void 0 ? void 0 : located.attributeName;
266
+ const value = (name === null || name === void 0 ? void 0 : name.localPart) ? (_f = (_e = located === null || located === void 0 ? void 0 : located.node) === null || _e === void 0 ? void 0 : _e.getAttributeNS) === null || _f === void 0 ? void 0 : _f.call(_e, name.namespaceURI || null, name.localPart) : undefined;
267
+ const shown = typeof value === 'string' ? `=${JSON.stringify(value.length > 80 ? `${value.slice(0, 80)}...` : value)}` : '';
268
+ detail = `${location}${shown}${positionOf(line, column)}: ${reason}`;
262
269
  }
263
- root.setAttributeNS(XMLNS_NS, `xmlns:${prefix}`, uri);
264
- kept.push(prefix);
270
+ throw new PartUnmarshalException(`${this.partName}: ${detail}`, this.partName.name, { cause, location, line, column });
265
271
  }
266
- if (!dropped)
267
- return;
268
- if (kept.length === 0)
269
- root.removeAttributeNode(attr);
270
- else
271
- root.setAttributeNS(MC_NS, attr.name, kept.join(' '));
272
272
  }
273
273
  }
@@ -47,6 +47,36 @@ class DocumentCommentParts {
47
47
  this.loadedAll = true;
48
48
  return this;
49
49
  }
50
+ async loadExisting() {
51
+ var _a, _b, _c;
52
+ const main = this.main;
53
+ if (main.commentsExtendedPart)
54
+ (_a = this.commentsEx) !== null && _a !== void 0 ? _a : (this.commentsEx = await main.commentsExtendedPart.getContents());
55
+ if (main.commentsIdsPart)
56
+ (_b = this.commentsIds) !== null && _b !== void 0 ? _b : (this.commentsIds = await main.commentsIdsPart.getContents());
57
+ (_c = this.extensible) !== null && _c !== void 0 ? _c : (this.extensible = await loadExtensible(main));
58
+ return this;
59
+ }
60
+ drop(people) {
61
+ var _a, _b;
62
+ const main = this.main;
63
+ const parts = [main.commentsPart, main.commentsExtendedPart, main.commentsIdsPart, main.commentsExtensiblePart, people ? main.peoplePart : undefined];
64
+ for (const part of parts) {
65
+ if (!part)
66
+ continue;
67
+ const rels = main.relationshipsPart;
68
+ const rel = rels === null || rels === void 0 ? void 0 : rels.getRel(part.partName);
69
+ if (rel)
70
+ rels.removeRelationship(rel);
71
+ if (part.sourceRelationships.length > 0)
72
+ continue;
73
+ (_a = part.relationshipsPart) === null || _a === void 0 ? void 0 : _a.removeParts();
74
+ (_b = part.package) === null || _b === void 0 ? void 0 : _b.parts.remove(part.partName);
75
+ }
76
+ main.commentsPart = main.commentsExtendedPart = main.commentsIdsPart = main.commentsExtensiblePart = undefined;
77
+ if (people)
78
+ main.peoplePart = undefined;
79
+ }
50
80
  }
51
81
  /** The document part a body's comments belong to: the body's own part, else the package's main part. */
52
82
  function mainPartOf(body) {
@@ -23,6 +23,15 @@ async function ensurePropertyResolver(part) {
23
23
  const pkg = part.package;
24
24
  await ((_a = pkg === null || pkg === void 0 ? void 0 : pkg.getPropertyResolver) === null || _a === void 0 ? void 0 : _a.call(pkg));
25
25
  }
26
+ /**
27
+ * The glossary's placeholder entries, read privately, which `ContentControl.placeholderText` reads synchronously
28
+ * (CR-002 section 63, D8).
29
+ */
30
+ async function ensureGlossaryEntries(part) {
31
+ var _a, _b;
32
+ const pkg = part.package;
33
+ await ((_a = pkg === null || pkg === void 0 ? void 0 : pkg.glossaryEntries) === null || _a === void 0 ? void 0 : _a.load((_b = pkg.mainDocumentPart) === null || _b === void 0 ? void 0 : _b.glossaryDocumentPart));
34
+ }
26
35
  /** The Body view of a part's block-level container, one per container object. */
27
36
  function bodyOf(part, container, prefix) {
28
37
  if (!container)
@@ -124,6 +133,7 @@ export class MainDocumentPart extends DocumentPart {
124
133
  async getBody() {
125
134
  await this.getContents();
126
135
  await ensurePropertyResolver(this);
136
+ await ensureGlossaryEntries(this);
127
137
  return this.body;
128
138
  }
129
139
  /**
@@ -439,6 +449,7 @@ export class HeaderPart extends XmlPart {
439
449
  async getBody() {
440
450
  await this.getContents();
441
451
  await ensurePropertyResolver(this);
452
+ await ensureGlossaryEntries(this);
442
453
  return this.body;
443
454
  }
444
455
  }
@@ -454,6 +465,7 @@ export class FooterPart extends XmlPart {
454
465
  async getBody() {
455
466
  await this.getContents();
456
467
  await ensurePropertyResolver(this);
468
+ await ensureGlossaryEntries(this);
457
469
  return this.body;
458
470
  }
459
471
  }
@@ -14,6 +14,13 @@ export declare function parseXml(text: string): Document;
14
14
  /** Serialises a node (document or element) without an XML declaration. */
15
15
  export declare function serializeXml(node: Node): string;
16
16
  export declare function createDocument(): Document;
17
+ /**
18
+ * The XML, refused where it holds a character XML 1.0 excludes, which no escape can write (CR-002 section 60 D3): the
19
+ * part would not be well-formed, and a conforming parser must refuse it. The content API's writers drop such characters
20
+ * or write them as their elements; this catches what reached the tree some other way (an attribute, a custom XML
21
+ * node's value, a caller's own edit of the tree).
22
+ */
23
+ export declare function assertXmlCharacters(xml: string, where: string): string;
17
24
  /** XML declaration plus the serialised document element, as one string. */
18
25
  export declare function serializeXmlPart(node: Node): string;
19
26
  /** UTF-8 bytes of a string. */
package/dist/xml/dom.mjs CHANGED
@@ -59,6 +59,24 @@ export function serializeXml(node) {
59
59
  export function createDocument() {
60
60
  return DOM.createDocument();
61
61
  }
62
+ /** A character XML 1.0 excludes: a C0 control but tab, line feed and carriage return, U+FFFE, U+FFFF, an unpaired surrogate. */
63
+ const NOT_XML = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
64
+ /**
65
+ * The XML, refused where it holds a character XML 1.0 excludes, which no escape can write (CR-002 section 60 D3): the
66
+ * part would not be well-formed, and a conforming parser must refuse it. The content API's writers drop such characters
67
+ * or write them as their elements; this catches what reached the tree some other way (an attribute, a custom XML
68
+ * node's value, a caller's own edit of the tree).
69
+ */
70
+ export function assertXmlCharacters(xml, where) {
71
+ const m = NOT_XML.exec(xml);
72
+ if (m) {
73
+ const code = m[0].charCodeAt(0).toString(16).toUpperCase().padStart(4, '0');
74
+ const before = xml.slice(Math.max(0, m.index - 40), m.index).replace(/[^\x20-\x7e]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
75
+ throw new Docx4JException(`${where} holds U+${code}, which XML 1.0 excludes, so it can't be written as well-formed XML `
76
+ + `(character ${m.index}, after "${before}"); remove it, or write it as the element it stands for (CR-002 section 60)`);
77
+ }
78
+ return xml;
79
+ }
62
80
  /** XML declaration plus the serialised document element, as one string. */
63
81
  export function serializeXmlPart(node) {
64
82
  const el = node.nodeType === 9 ? node.documentElement : node;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docx4j/core-ts",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "docx4j-core for TypeScript: Open Packaging (docx/pptx/xlsx zip and flat OPC), typed parts and relationships, style, numbering and font resolution over @docx4j/generated-objects-ts. Node, browsers, Word add-ins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -83,7 +83,7 @@
83
83
  },
84
84
  "license": "Apache-2.0",
85
85
  "dependencies": {
86
- "@docx4j/generated-objects-ts": "^0.3.1",
86
+ "@docx4j/generated-objects-ts": "^0.5.0",
87
87
  "fflate": "^0.8.2"
88
88
  },
89
89
  "devDependencies": {