@docx4j/core-ts 0.4.0 → 0.5.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 (49) hide show
  1. package/README.md +5 -2
  2. package/dist/html/convert.mjs +38 -14
  3. package/dist/model/content/Body.d.mts +13 -1
  4. package/dist/model/content/Body.mjs +90 -19
  5. package/dist/model/content/Comment.mjs +7 -0
  6. package/dist/model/content/InlinePicture.d.mts +71 -7
  7. package/dist/model/content/InlinePicture.mjs +201 -28
  8. package/dist/model/content/List.mjs +10 -1
  9. package/dist/model/content/Paragraph.d.mts +28 -5
  10. package/dist/model/content/Paragraph.mjs +77 -37
  11. package/dist/model/content/Range.d.mts +18 -2
  12. package/dist/model/content/Range.mjs +194 -64
  13. package/dist/model/content/TrackedChange.d.mts +129 -3
  14. package/dist/model/content/TrackedChange.mjs +577 -12
  15. package/dist/model/content/binder.d.mts +2 -1
  16. package/dist/model/content/binder.mjs +48 -1
  17. package/dist/model/content/index.d.mts +2 -2
  18. package/dist/model/content/index.mjs +1 -1
  19. package/dist/model/content/relationships.d.mts +30 -0
  20. package/dist/model/content/relationships.mjs +133 -0
  21. package/dist/model/content/tree.d.mts +52 -2
  22. package/dist/model/content/tree.mjs +48 -3
  23. package/dist/model/customxml/pictures.d.mts +5 -2
  24. package/dist/model/customxml/pictures.mjs +13 -7
  25. package/dist/model/fonts/families.generated.mjs +2 -2
  26. package/dist/model/fonts/registry.mjs +7 -1
  27. package/dist/model/fonts/substitutions.generated.mjs +2 -2
  28. package/dist/model/fonts/themes.generated.mjs +1 -1
  29. package/dist/model/listnumbering/definitions.mjs +18 -0
  30. package/dist/model/properties/PropertyResolver.d.mts +27 -6
  31. package/dist/model/properties/PropertyResolver.mjs +83 -16
  32. package/dist/model/properties/catalogue.d.mts +15 -1
  33. package/dist/model/properties/catalogue.mjs +80 -27
  34. package/dist/model/properties/table.d.mts +16 -2
  35. package/dist/model/properties/table.mjs +13 -3
  36. package/dist/opc/Load.d.mts +9 -2
  37. package/dist/opc/index.d.mts +2 -2
  38. package/dist/opc/index.mjs +2 -2
  39. package/dist/opc/mce/preprocessor.d.mts +62 -6
  40. package/dist/opc/mce/preprocessor.mjs +142 -35
  41. package/dist/opc/mce/understood.d.mts +10 -0
  42. package/dist/opc/mce/understood.mjs +25 -3
  43. package/dist/packages/OpcPackage.d.mts +7 -0
  44. package/dist/packages/OpcPackage.mjs +15 -3
  45. package/dist/packages/WordprocessingMLPackage.d.mts +35 -2
  46. package/dist/packages/WordprocessingMLPackage.mjs +98 -2
  47. package/dist/parts/XmlPart.d.mts +26 -5
  48. package/dist/parts/XmlPart.mjs +67 -18
  49. package/package.json +2 -2
@@ -25,11 +25,19 @@ const warnedPrefixes = new Set();
25
25
  * element, so the location is everything before the position or the colon - and `w:sz` must not be
26
26
  * cut at its own prefix separator, which a naive split on `:` does.
27
27
  */
28
+ /** The runtime's located message: `w:sz/@w:val (line 12): reason`, the position optional. */
29
+ const LOCATION_PREFIX = /^(.+?)(?: \(line \d+(?:, column \d+)?\))?: /;
28
30
  function locationOf(message, located) {
29
31
  var _a;
30
32
  if (!located)
31
33
  return undefined;
32
- return (_a = /^(.+?)(?: \(line \d+(?:, column \d+)?\))?: /.exec(message)) === null || _a === void 0 ? void 0 : _a[1];
34
+ return (_a = LOCATION_PREFIX.exec(message)) === null || _a === void 0 ? void 0 : _a[1];
35
+ }
36
+ /** ` (line 12, column 9)`, or as much of it as is known. */
37
+ function positionOf(line, column) {
38
+ if (line === undefined)
39
+ return '';
40
+ return column === undefined ? ` (line ${line})` : ` (line ${line}, column ${column})`;
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,14 @@ export class XmlPart extends Part {
65
74
  get isUntouched() {
66
75
  return this.element === undefined && this.bytes === undefined;
67
76
  }
77
+ /**
78
+ * What the preprocessor reported the last time this part was parsed (CR-010 phase 1): an
79
+ * mc:AlternateContent whose branches' text differs (`mce.branches_differ`). Empty until the part
80
+ * is parsed, by `getContents()` or a private read, and again once its contents are set.
81
+ */
82
+ get warnings() {
83
+ return this.parseWarnings;
84
+ }
68
85
  /** The unmarshalled contents (docx4j getJaxbElement()); throws when not yet unmarshalled. */
69
86
  get contents() {
70
87
  if (this.element === undefined)
@@ -77,16 +94,16 @@ export class XmlPart extends Part {
77
94
  }
78
95
  /** Unmarshals on first call (docx4j getContents()). */
79
96
  async getContents() {
80
- var _a, _b, _c;
97
+ var _a, _b;
81
98
  if (this.element === undefined) {
82
99
  const bytes = (_a = this.bytes) !== null && _a !== void 0 ? _a : (await this.loadSourceBytes());
83
100
  if (bytes === undefined)
84
101
  throw new Docx4JException(`Part ${this.partName} has no content: set contents or load it from a container`);
85
- const doc = parseXml(decodeXmlText(bytes));
102
+ const doc = this.parse(bytes);
86
103
  this.recordDeclarations(doc);
87
- (_b = this.preprocessor) === null || _b === void 0 ? void 0 : _b.call(this, doc, this);
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,22 @@ 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));
127
+ const doc = this.parse(bytes);
111
128
  this.recordDeclarations(doc);
112
- (_b = this.preprocessor) === null || _b === void 0 ? void 0 : _b.call(this, doc, this);
129
+ this.preprocess(doc);
113
130
  return (await this.unmarshal(doc)).value;
114
131
  }
132
+ preprocess(doc) {
133
+ var _a;
134
+ const warnings = (_a = this.preprocessor) === null || _a === void 0 ? void 0 : _a.call(this, doc, this);
135
+ this.parseWarnings = warnings ? [...warnings] : [];
136
+ }
115
137
  /** Replaces the contents (docx4j setJaxbElement / setContents). The root name defaults to the part's. */
116
138
  setContents(value, rootName) {
117
139
  var _a, _b;
@@ -120,6 +142,7 @@ export class XmlPart extends Part {
120
142
  throw new Docx4JException(`Part ${this.partName}: no root element name; pass one`);
121
143
  this.element = { name: { namespaceURI: name.namespaceURI, localPart: name.localPart }, value };
122
144
  this.bytes = undefined;
145
+ this.parseWarnings = [];
123
146
  }
124
147
  /** Replaces the contents with raw XML bytes; they are unmarshalled on the next getContents(). */
125
148
  setBytes(bytes) {
@@ -183,28 +206,54 @@ export class XmlPart extends Part {
183
206
  this.declareIgnorablePrefixes(root);
184
207
  return root;
185
208
  }
209
+ /**
210
+ * Parses the part's bytes, and names the part when the XML is not well-formed. xmldom's error
211
+ * (Node) carries the line and column of the fault; a browser's says them in its text, which
212
+ * `parseXml` passes on.
213
+ */
214
+ parse(bytes) {
215
+ try {
216
+ return parseXml(decodeXmlText(bytes));
217
+ }
218
+ catch (cause) {
219
+ const at = cause === null || cause === void 0 ? void 0 : cause.locator;
220
+ const line = typeof (at === null || at === void 0 ? void 0 : at.lineNumber) === 'number' ? at.lineNumber : undefined;
221
+ const column = typeof (at === null || at === void 0 ? void 0 : at.columnNumber) === 'number' ? at.columnNumber : undefined;
222
+ const reason = (cause instanceof Error ? cause.message : String(cause)).replace(/^Malformed XML: /, '');
223
+ throw new PartUnmarshalException(`${this.partName}: Malformed XML${positionOf(line, column)}: ${reason}`, this.partName.name, { cause, line, column });
224
+ }
225
+ }
186
226
  /**
187
227
  * Unmarshals, and names the part when the runtime refuses. The runtime's own message says what is
188
228
  * wrong and, since `@docx4j/jsonix` 3.4.0, where - `w:sz/@w:val (line 12): Argument [NaN] must be
189
229
  * 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).
230
+ * part's XML needs (CR-002 section 27), nor the value it refused. The message names the part, and
231
+ * for an attribute gives the value as written and the column too:
232
+ * `/word/styles.xml: w:sz/@w:val="big" (line 12, column 9): Argument [NaN] must be an integer, ...`.
233
+ * The location it found is lifted onto the exception so a caller does not parse the message; `line`
234
+ * is undefined where the parser supplies no position, which is every browser (only xmldom carries a
235
+ * locator).
193
236
  */
194
237
  async unmarshal(doc) {
195
- var _a, _b;
238
+ var _a, _b, _c, _d, _e, _f;
196
239
  try {
197
240
  return await unmarshalNode(doc);
198
241
  }
199
242
  catch (cause) {
200
243
  const located = cause;
201
244
  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
- });
245
+ const location = locationOf(message, (located === null || located === void 0 ? void 0 : located.jsonixLocated) === true);
246
+ 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;
247
+ 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;
248
+ let detail = message;
249
+ if (location !== undefined) {
250
+ 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);
251
+ const name = located === null || located === void 0 ? void 0 : located.attributeName;
252
+ 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;
253
+ const shown = typeof value === 'string' ? `=${JSON.stringify(value.length > 80 ? `${value.slice(0, 80)}...` : value)}` : '';
254
+ detail = `${location}${shown}${positionOf(line, column)}: ${reason}`;
255
+ }
256
+ throw new PartUnmarshalException(`${this.partName}: ${detail}`, this.partName.name, { cause, location, line, column });
208
257
  }
209
258
  }
210
259
  /** The source root element's namespace declarations, prefix to URI (`xmlns=` is the empty prefix). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docx4j/core-ts",
3
- "version": "0.4.0",
3
+ "version": "0.5.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.4.2",
87
87
  "fflate": "^0.8.2"
88
88
  },
89
89
  "devDependencies": {