@docx4j/core-ts 0.6.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.
- package/README.md +60 -0
- package/dist/model/content/Body.mjs +6 -17
- package/dist/model/content/Comment.d.mts +2 -2
- package/dist/model/content/Comment.mjs +12 -7
- package/dist/model/content/ContentControl.d.mts +1 -1
- package/dist/model/content/ContentControl.mjs +8 -4
- package/dist/model/content/Font.d.mts +4 -1
- package/dist/model/content/Font.mjs +6 -2
- package/dist/model/content/List.d.mts +6 -3
- package/dist/model/content/List.mjs +15 -8
- package/dist/model/content/Paragraph.d.mts +12 -2
- package/dist/model/content/Paragraph.mjs +31 -11
- package/dist/model/content/Table.mjs +26 -16
- package/dist/model/content/TrackedChange.d.mts +2 -2
- package/dist/model/content/TrackedChange.mjs +6 -3
- package/dist/model/content/index.d.mts +3 -1
- package/dist/model/content/index.mjs +4 -1
- package/dist/model/content/ooxml.mjs +12 -1
- package/dist/model/content/paraIds.d.mts +5 -0
- package/dist/model/content/paraIds.mjs +54 -0
- package/dist/model/content/search.d.mts +2 -0
- package/dist/model/content/search.mjs +51 -7
- package/dist/model/content/story.d.mts +5 -2
- package/dist/model/content/story.mjs +6 -3
- package/dist/model/content/tableRules.mjs +2 -0
- package/dist/model/content/tracking.d.mts +35 -6
- package/dist/model/content/tracking.mjs +93 -12
- package/dist/model/content/tree.d.mts +7 -8
- package/dist/model/content/tree.mjs +7 -9
- package/dist/model/content/wordRange.d.mts +48 -0
- package/dist/model/content/wordRange.mjs +97 -0
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +22 -1
- package/dist/model/customxml/CustomXmlPartCollection.mjs +48 -2
- package/dist/model/customxml/XmlMapping.d.mts +31 -7
- package/dist/model/customxml/XmlMapping.mjs +53 -10
- package/dist/model/customxml/bindings.d.mts +12 -2
- package/dist/model/customxml/bindings.mjs +98 -16
- package/dist/model/customxml/index.d.mts +1 -0
- package/dist/model/customxml/index.mjs +1 -0
- package/dist/model/customxml/opendope.d.mts +4 -1
- package/dist/model/customxml/opendope.mjs +9 -6
- package/dist/model/customxml/pictures.mjs +5 -3
- package/dist/model/customxml/storeItems.d.mts +57 -0
- package/dist/model/customxml/storeItems.mjs +122 -0
- package/dist/model/customxml/xhtml.mjs +15 -20
- package/dist/model/dateZone.d.mts +25 -0
- package/dist/model/dateZone.mjs +57 -0
- package/dist/model/index.d.mts +1 -0
- package/dist/model/index.mjs +1 -0
- package/dist/model/properties/PropertyResolver.d.mts +14 -1
- package/dist/model/properties/PropertyResolver.mjs +18 -3
- package/dist/model/properties/index.d.mts +1 -1
- package/dist/model/properties/log.mjs +2 -2
- package/dist/model/properties/styleUtil.d.mts +3 -1
- package/dist/model/properties/styleUtil.mjs +20 -24
- package/dist/model/text/CaseMapping.d.mts +38 -0
- package/dist/model/text/CaseMapping.mjs +86 -0
- package/dist/model/text/Extractor.d.mts +66 -6
- package/dist/model/text/Extractor.mjs +300 -56
- package/dist/model/text/PlainText.mjs +7 -4
- package/dist/model/text/TextContext.d.mts +103 -8
- package/dist/model/text/TextContext.mjs +228 -53
- package/dist/model/text/TextOptions.d.mts +88 -5
- package/dist/model/text/TextOptions.mjs +158 -17
- package/dist/model/text/TextResult.d.mts +126 -9
- package/dist/model/text/TextResult.mjs +115 -12
- package/dist/model/text/WmlToMarkdown.mjs +32 -7
- package/dist/model/text/caseMapping.generated.d.mts +7 -0
- package/dist/model/text/caseMapping.generated.mjs +214 -0
- package/dist/model/text/index.d.mts +3 -2
- package/dist/model/text/index.mjs +1 -0
- package/dist/model/wordIntegers.d.mts +29 -0
- package/dist/model/wordIntegers.mjs +78 -0
- package/dist/office-js/document.mjs +15 -1
- package/dist/office-js/toApiScript.mjs +8 -7
- package/dist/opc/DirectoryPartStore.d.mts +6 -2
- package/dist/opc/DirectoryPartStore.mjs +11 -4
- package/dist/opc/FlatOpcPartStore.d.mts +4 -2
- package/dist/opc/FlatOpcPartStore.mjs +11 -8
- package/dist/opc/Load.d.mts +32 -0
- package/dist/opc/Load.mjs +115 -5
- package/dist/opc/PartStore.d.mts +34 -1
- package/dist/opc/PartStore.mjs +71 -8
- package/dist/opc/Save.d.mts +17 -2
- package/dist/opc/Save.mjs +100 -4
- package/dist/opc/ZipPartStore.d.mts +4 -2
- package/dist/opc/ZipPartStore.mjs +12 -7
- package/dist/opc/exceptions.d.mts +140 -0
- package/dist/opc/exceptions.mjs +108 -0
- package/dist/opc/index.d.mts +7 -4
- package/dist/opc/index.mjs +5 -3
- package/dist/opc/mce/preprocessor.d.mts +121 -10
- package/dist/opc/mce/preprocessor.mjs +122 -21
- package/dist/opc/mce/understood.d.mts +3 -35
- package/dist/opc/mce/understood.mjs +27 -53
- package/dist/opc/repair/breaks.d.mts +23 -0
- package/dist/opc/repair/breaks.mjs +288 -0
- package/dist/opc/repair/hosts.d.mts +12 -0
- package/dist/opc/repair/hosts.mjs +33 -0
- package/dist/opc/repair/mainRoot.d.mts +19 -0
- package/dist/opc/repair/mainRoot.mjs +168 -0
- package/dist/opc/repair/unknownElements.d.mts +8 -0
- package/dist/opc/repair/unknownElements.mjs +180 -0
- package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
- package/dist/opc/repair/wmlNames.generated.mjs +80 -0
- package/dist/opc/skipped.d.mts +50 -0
- package/dist/opc/skipped.mjs +140 -0
- package/dist/packages/OpcPackage.d.mts +98 -5
- package/dist/packages/OpcPackage.mjs +122 -7
- package/dist/packages/WordprocessingMLPackage.mjs +3 -1
- package/dist/packages/index.d.mts +1 -1
- package/dist/parts/Part.d.mts +5 -1
- package/dist/parts/RelationshipsPart.d.mts +15 -0
- package/dist/parts/RelationshipsPart.mjs +66 -1
- package/dist/parts/XmlPart.d.mts +54 -5
- package/dist/parts/XmlPart.mjs +203 -10
- package/dist/parts/wml/index.d.mts +12 -1
- package/dist/parts/wml/index.mjs +25 -1
- package/package.json +2 -2
package/dist/parts/XmlPart.mjs
CHANGED
|
@@ -3,6 +3,10 @@ import { Part } from './Part.mjs';
|
|
|
3
3
|
import { Docx4JException, PartUnmarshalException } from '../opc/exceptions.mjs';
|
|
4
4
|
import { parseXml, serializeXml, encodeText, decodeXmlText, XML_DECLARATION, assertXmlCharacters } from '../xml/dom.mjs';
|
|
5
5
|
import { bindSnapshot, boundsOf } from '../model/content/binder.mjs';
|
|
6
|
+
import { repairBreaksOutsideRuns } from '../opc/repair/breaks.mjs';
|
|
7
|
+
import { readThroughUnknownElements } from '../opc/repair/unknownElements.mjs';
|
|
8
|
+
import { skippedAttribute, skippedElement, skippedText } from '../opc/skipped.mjs';
|
|
9
|
+
import { rangeOf, describeReading, UNMEASURED_RANGE } from '../model/wordIntegers.mjs';
|
|
6
10
|
/**
|
|
7
11
|
* The element or attribute a located runtime error names, out of its message: jsonix writes
|
|
8
12
|
* `w:sz/@w:val (line 7): ...` when it could place the fault and `w:bogus (line 3): ...` for an
|
|
@@ -31,14 +35,88 @@ function valueKept(reading, partName) {
|
|
|
31
35
|
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
36
|
const value = reading.value;
|
|
33
37
|
const read = value === true ? 'on' : value === undefined ? 'absent' : JSON.stringify(value);
|
|
38
|
+
// a form Word refuses a document for is dropped (the objects package's CR-015; CR-017 P1)
|
|
39
|
+
const outcome = reading.kind === 'value.refused' ? 'dropped: Word 365 refuses a document with this value' : `read as ${read}, as Word 365 reads it`;
|
|
34
40
|
return {
|
|
35
41
|
code: reading.kind, partName,
|
|
36
42
|
...(typeof node.lineNumber === 'number' ? { line: node.lineNumber } : {}),
|
|
37
43
|
...(typeof node.columnNumber === 'number' ? { column: node.columnNumber } : {}),
|
|
38
44
|
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;
|
|
45
|
+
message: `${partName}: ${node.nodeName}/@${attribute}=${JSON.stringify(reading.text)}${positionOf(node.lineNumber, node.columnNumber)} is not a value its type allows; ${outcome}`,
|
|
40
46
|
};
|
|
41
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* An integer attribute value Word 365 reads differently, as the objects facade reports it on read or on save, as a
|
|
50
|
+
* warning (CR-017 P2 and P3). The value stays as written; the message says what Word would read, the storage and the
|
|
51
|
+
* range Word keeps as written, from the table entry the report names (`storage`, `property` and `rule`, objects 0.7.0).
|
|
52
|
+
*/
|
|
53
|
+
export function valueOutOfRange(report, partName) {
|
|
54
|
+
var _a, _b, _c;
|
|
55
|
+
const node = report.element;
|
|
56
|
+
const name = report.attribute;
|
|
57
|
+
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 : `w:${name.localPart}`;
|
|
58
|
+
const reading = report.wordReads;
|
|
59
|
+
const unmeasured = !report.storage.measured;
|
|
60
|
+
// the rule beside a line or a height (`report.rule`, from the tree) decides what Word keeps there
|
|
61
|
+
const range = rangeOf(report.storage, report.property, report.rule);
|
|
62
|
+
const at = report.path !== undefined ? `${report.path}=${report.value}` : `${node.nodeName}/@${attribute}=${report.value}${positionOf(node.lineNumber, node.columnNumber)}`;
|
|
63
|
+
const where = unmeasured
|
|
64
|
+
? `is outside ${UNMEASURED_RANGE[0]} to ${UNMEASURED_RANGE[1]}, where Word 365 changes every measured value of its kind (${node.nodeName}/@${attribute} is unmeasured); what Word reads is not known`
|
|
65
|
+
: `is past what Word 365 stores there (${reading.storage}${range ? `, ${range[0]} to ${range[1]}` : ''}); Word reads it as ${describeReading(reading, name.localPart)}`;
|
|
66
|
+
const prefix = partName === undefined ? '' : `${partName}: `;
|
|
67
|
+
return {
|
|
68
|
+
code: 'value.out_of_range', partName,
|
|
69
|
+
...(report.path === undefined && typeof node.lineNumber === 'number' ? { line: node.lineNumber } : {}),
|
|
70
|
+
...(report.path === undefined && typeof node.columnNumber === 'number' ? { column: node.columnNumber } : {}),
|
|
71
|
+
...(report.path !== undefined ? { path: report.path } : {}),
|
|
72
|
+
element: node.nodeName, attribute, value: report.value, wordReads: reading.value,
|
|
73
|
+
...(reading.attribute !== undefined && reading.attribute !== name.localPart ? { readAs: `w:${reading.attribute}` } : {}),
|
|
74
|
+
...(reading.rule !== undefined ? { rule: reading.rule } : {}),
|
|
75
|
+
storage: reading.storage, range,
|
|
76
|
+
message: `${prefix}${at} ${where}`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** The last segment of an objects `TYPE_NAME`, docx4j's class name: `org_docx4j_wml.R` is `R`. */
|
|
80
|
+
const className = (typeName) => typeName.slice(typeName.lastIndexOf('.') + 1);
|
|
81
|
+
/**
|
|
82
|
+
* A child its container never admits, as the objects facade reports it on read or on save (its CR-017's
|
|
83
|
+
* `onMisplaced`), as a warning (CR-016 D7, D2): docx4j-python's code and fields (`target.misplaced`; `holder` and `item`
|
|
84
|
+
* docx4j's class names), docx4j's message after the part and the place (the path on save; the container, the child's
|
|
85
|
+
* place in its list and the line on read).
|
|
86
|
+
*/
|
|
87
|
+
export function misplacedContent(report, partName) {
|
|
88
|
+
var _a;
|
|
89
|
+
const container = report.element;
|
|
90
|
+
const located = (_a = report.childElement) !== null && _a !== void 0 ? _a : container;
|
|
91
|
+
const isText = report.child === '#text';
|
|
92
|
+
const element = isText ? undefined : qualifiedName(report.child);
|
|
93
|
+
const onRead = report.path === undefined;
|
|
94
|
+
const line = onRead && typeof located.lineNumber === 'number' ? located.lineNumber : undefined;
|
|
95
|
+
const column = onRead && typeof located.columnNumber === 'number' ? located.columnNumber : undefined;
|
|
96
|
+
const shown = report.text === undefined ? '' : ` ${JSON.stringify(report.text.length > 80 ? `${report.text.slice(0, 80)}...` : report.text)}`;
|
|
97
|
+
const at = onRead
|
|
98
|
+
? `${container.nodeName}${report.via === undefined ? '' : `/${report.via}`}, child ${report.index} (${element !== null && element !== void 0 ? element : 'a string'}${shown})${positionOf(line, column)}`
|
|
99
|
+
: report.path;
|
|
100
|
+
const prefix = partName === undefined ? '' : `${partName}: `;
|
|
101
|
+
return {
|
|
102
|
+
code: 'target.misplaced', partName,
|
|
103
|
+
...(line !== undefined ? { line } : {}),
|
|
104
|
+
...(column !== undefined ? { column } : {}),
|
|
105
|
+
...(onRead ? {} : { path: report.path }),
|
|
106
|
+
holder: className(report.container), index: report.index,
|
|
107
|
+
...(report.childType !== undefined ? { item: className(report.childType) } : {}),
|
|
108
|
+
...(element !== undefined ? { element } : {}),
|
|
109
|
+
rule: report.rule,
|
|
110
|
+
...(report.text !== undefined ? { text: report.text } : {}),
|
|
111
|
+
message: `${prefix}${at}: ${report.message}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** `w:tbl` for a child's name: its prefix as the report has it, else the objects package's for the namespace. */
|
|
115
|
+
function qualifiedName(name) {
|
|
116
|
+
var _a;
|
|
117
|
+
const prefix = (_a = name.prefix) !== null && _a !== void 0 ? _a : NAMESPACE_PREFIXES[name.namespaceURI];
|
|
118
|
+
return prefix ? `${prefix}:${name.localPart}` : name.localPart;
|
|
119
|
+
}
|
|
42
120
|
/** The objects package's prefix table as XPath wants it, prefix to URI; built once. */
|
|
43
121
|
const NAMESPACE_PREFIXES_BY_PREFIX = (() => {
|
|
44
122
|
const out = {};
|
|
@@ -76,9 +154,13 @@ export class XmlPart extends Part {
|
|
|
76
154
|
}
|
|
77
155
|
/**
|
|
78
156
|
* What the last parse of this part reported: an mc:AlternateContent whose branches' text differs
|
|
79
|
-
* (`mce.branches_differ`, CR-010 phase 1),
|
|
80
|
-
* Word 365 reads it (`value.kept.exact`, `value.kept.invalid`: CR-015 D8
|
|
81
|
-
*
|
|
157
|
+
* (`mce.branches_differ`, CR-010 phase 1), each attribute value its type refuses that was read as
|
|
158
|
+
* Word 365 reads it (`value.kept.exact`, `value.kept.invalid`, `value.truncated`, `value.refused`: CR-015 D8,
|
|
159
|
+
* CR-017 P1), each integer attribute value past what Word stores, kept as written (`value.out_of_range`,
|
|
160
|
+
* CR-017 P2), and each child its container never admits, kept as read but a string the runtime drops
|
|
161
|
+
* (`target.misplaced`, CR-016 D7), and a w:br outside a w:r read as Word reads it (`br.outside_run`, CR-021).
|
|
162
|
+
* Empty until the part is parsed, by `getContents()` or a private read, and again
|
|
163
|
+
* once its contents are set.
|
|
82
164
|
*/
|
|
83
165
|
get warnings() {
|
|
84
166
|
return this.parseWarnings;
|
|
@@ -98,6 +180,7 @@ export class XmlPart extends Part {
|
|
|
98
180
|
var _a, _b;
|
|
99
181
|
if (this.element === undefined) {
|
|
100
182
|
const bytes = (_a = this.bytes) !== null && _a !== void 0 ? _a : (await this.loadSourceBytes());
|
|
183
|
+
this.parsedBytes = this.bytes;
|
|
101
184
|
if (bytes === undefined)
|
|
102
185
|
throw new Docx4JException(`Part ${this.partName} has no content: set contents or load it from a container`);
|
|
103
186
|
const doc = this.parse(bytes);
|
|
@@ -118,20 +201,61 @@ export class XmlPart extends Part {
|
|
|
118
201
|
* reads the styles and numbering parts of a document nobody has otherwise touched.
|
|
119
202
|
*/
|
|
120
203
|
async readContents() {
|
|
204
|
+
return (await this.readElement()).value;
|
|
205
|
+
}
|
|
206
|
+
/** `readContents`'s typed element: the live one, else a private tree from the part's bytes. */
|
|
207
|
+
async readElement() {
|
|
121
208
|
var _a;
|
|
122
209
|
if (this.element !== undefined)
|
|
123
|
-
return this.element
|
|
210
|
+
return this.element;
|
|
124
211
|
const bytes = (_a = this.bytes) !== null && _a !== void 0 ? _a : (await this.loadSourceBytes());
|
|
125
212
|
if (bytes === undefined)
|
|
126
213
|
throw new Docx4JException(`Part ${this.partName} has no content: set contents or load it from a container`);
|
|
127
214
|
const doc = this.parse(bytes);
|
|
128
215
|
this.preprocess(doc);
|
|
129
|
-
return
|
|
216
|
+
return this.unmarshal(doc);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Every child the part holds that its container never admits (CR-016 D6, the check on request): what a save would
|
|
220
|
+
* refuse the part for, each with its path, the rule and docx4j's message naming the fix, found by the objects
|
|
221
|
+
* facade's walk over the tree (a marshal to nothing); the part is not changed, and one never unmarshalled stays
|
|
222
|
+
* untouched, read privately. `[]` for a part whose content is all in its place.
|
|
223
|
+
*/
|
|
224
|
+
async checkContent() {
|
|
225
|
+
const element = await this.readElement();
|
|
226
|
+
const out = [];
|
|
227
|
+
try {
|
|
228
|
+
await marshalNode(element, { onMisplaced: (report) => out.push(misplacedContent(report, this.partName.name)) });
|
|
229
|
+
}
|
|
230
|
+
catch (cause) {
|
|
231
|
+
// the runtime refuses to write what the walk reported (a string in a run); with nothing reported, the fault is another
|
|
232
|
+
if (out.length === 0)
|
|
233
|
+
throw new Docx4JException(`Part ${this.partName}: its content cannot be written`, { cause });
|
|
234
|
+
}
|
|
235
|
+
return out;
|
|
130
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* The DOM before unmarshalling: a w:br outside a w:r put in a run, as Word reads it (CR-021: a reading of the file,
|
|
239
|
+
* not an option, so ahead of the package's hook, which sees the repaired DOM), then the hook.
|
|
240
|
+
*/
|
|
131
241
|
preprocess(doc) {
|
|
242
|
+
this.parseWarnings = this.preprocessed(doc);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Reads the part's root before anything else meets the DOM; nothing by default. A main document part reads a root other than
|
|
246
|
+
* `w:document` here (WD REQ-318 to REQ-320, CR-028), throwing for one Word refuses.
|
|
247
|
+
*/
|
|
248
|
+
readRoot(_doc) {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
preprocessed(doc) {
|
|
132
252
|
var _a;
|
|
253
|
+
const rooted = this.readRoot(doc);
|
|
254
|
+
// ahead of CR-021's, which then gives a w:br the element held a run, as Word does (`76t42`)
|
|
255
|
+
const read = readThroughUnknownElements(doc, this.partName.name);
|
|
256
|
+
const repaired = repairBreaksOutsideRuns(doc, this.partName.name);
|
|
133
257
|
const warnings = (_a = this.preprocessor) === null || _a === void 0 ? void 0 : _a.call(this, doc, this);
|
|
134
|
-
|
|
258
|
+
return [...rooted, ...read, ...repaired, ...(warnings !== null && warnings !== void 0 ? warnings : [])];
|
|
135
259
|
}
|
|
136
260
|
/** Replaces the contents (docx4j setJaxbElement / setContents). The root name defaults to the part's. */
|
|
137
261
|
setContents(value, rootName) {
|
|
@@ -141,12 +265,58 @@ export class XmlPart extends Part {
|
|
|
141
265
|
throw new Docx4JException(`Part ${this.partName}: no root element name; pass one`);
|
|
142
266
|
this.element = { name: { namespaceURI: name.namespaceURI, localPart: name.localPart }, value };
|
|
143
267
|
this.bytes = undefined;
|
|
268
|
+
this.parsedBytes = undefined;
|
|
144
269
|
this.parseWarnings = [];
|
|
145
270
|
}
|
|
146
271
|
/** Replaces the contents with raw XML bytes; they are unmarshalled on the next getContents(). */
|
|
147
272
|
setBytes(bytes) {
|
|
148
273
|
this.bytes = bytes;
|
|
149
274
|
this.element = undefined;
|
|
275
|
+
this.parsedBytes = undefined;
|
|
276
|
+
}
|
|
277
|
+
/** What the read of the tree held now dropped (CR-025): nothing for a part not unmarshalled, or given contents. */
|
|
278
|
+
get skippedByRead() {
|
|
279
|
+
if (this.element === undefined)
|
|
280
|
+
return [];
|
|
281
|
+
return this.parseWarnings.filter((w) => w.code === 'part.skipped');
|
|
282
|
+
}
|
|
283
|
+
/** The bytes the tree held now was read from. */
|
|
284
|
+
async bytesRead() {
|
|
285
|
+
var _a;
|
|
286
|
+
return (_a = this.parsedBytes) !== null && _a !== void 0 ? _a : this.loadSourceBytes();
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Whether the tree is still what its source reads as (CR-025 section 2.2): the source read again and the two marshalled
|
|
290
|
+
* alike. The save has no change log to ask, so this is for a part that holds skipped content, and only that: such a part,
|
|
291
|
+
* read and not changed, is copied, where a marshal would lose what the read dropped. What can't be compared counts as changed.
|
|
292
|
+
*/
|
|
293
|
+
async isUnchangedSinceRead() {
|
|
294
|
+
var _a;
|
|
295
|
+
if (this.element === undefined)
|
|
296
|
+
return true;
|
|
297
|
+
const bytes = await this.bytesRead();
|
|
298
|
+
if (bytes === undefined)
|
|
299
|
+
return false;
|
|
300
|
+
const marshal = {};
|
|
301
|
+
const normalise = (_a = this.package) === null || _a === void 0 ? void 0 : _a.normaliseOnSave;
|
|
302
|
+
if (normalise !== undefined)
|
|
303
|
+
marshal.normaliseOnSave = normalise;
|
|
304
|
+
try {
|
|
305
|
+
const doc = this.parse(bytes);
|
|
306
|
+
this.preprocessed(doc);
|
|
307
|
+
// read with the read's callbacks, their reports discarded: without onUnexpectedElement the runtime refuses an unknown
|
|
308
|
+
// element in the hosts route B skips it in (CR-026), and the part would count as changed
|
|
309
|
+
const ignore = () => { };
|
|
310
|
+
const source = await unmarshalNode(doc, {
|
|
311
|
+
onWordReading: ignore, onOutOfRange: ignore, onMisplaced: ignore,
|
|
312
|
+
onUnexpectedElement: ignore, onUnexpectedAttribute: ignore, onUnexpectedText: ignore,
|
|
313
|
+
});
|
|
314
|
+
return serializeXml(await marshalNode(source, marshal))
|
|
315
|
+
=== serializeXml(await marshalNode(this.element, marshal));
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
150
320
|
}
|
|
151
321
|
/** Replaces the contents with XML text (docx4j setContents from a string). */
|
|
152
322
|
setXml(xml) {
|
|
@@ -212,6 +382,10 @@ export class XmlPart extends Part {
|
|
|
212
382
|
marshal.normaliseOnSave = normalise;
|
|
213
383
|
if ((options === null || options === void 0 ? void 0 : options.onNormalised) !== undefined)
|
|
214
384
|
marshal.onNormalised = options.onNormalised;
|
|
385
|
+
if ((options === null || options === void 0 ? void 0 : options.onOutOfRange) !== undefined)
|
|
386
|
+
marshal.onOutOfRange = options.onOutOfRange; // the report carries its rule (objects 0.7.0)
|
|
387
|
+
if ((options === null || options === void 0 ? void 0 : options.onMisplaced) !== undefined)
|
|
388
|
+
marshal.onMisplaced = options.onMisplaced;
|
|
215
389
|
return marshalNode(this.element, marshal);
|
|
216
390
|
}
|
|
217
391
|
/**
|
|
@@ -245,12 +419,31 @@ export class XmlPart extends Part {
|
|
|
245
419
|
async unmarshal(doc) {
|
|
246
420
|
var _a, _b, _c, _d, _e, _f;
|
|
247
421
|
const kept = [];
|
|
422
|
+
const partName = this.partName.name;
|
|
423
|
+
// A string CR-016's walk reports as misplaced isn't reported twice: that walk runs after the text's own callback.
|
|
424
|
+
const textHolders = new Map();
|
|
425
|
+
const misplacedStrings = new Set();
|
|
248
426
|
try {
|
|
249
427
|
const element = await unmarshalNode(doc, {
|
|
250
|
-
onWordReading: (reading) => kept.push(valueKept(reading,
|
|
428
|
+
onWordReading: (reading) => kept.push(valueKept(reading, partName)),
|
|
429
|
+
onOutOfRange: (report) => kept.push(valueOutOfRange(report, partName)),
|
|
430
|
+
onMisplaced: (report) => {
|
|
431
|
+
kept.push(misplacedContent(report, partName));
|
|
432
|
+
if (report.child === '#text')
|
|
433
|
+
misplacedStrings.add(report.element);
|
|
434
|
+
},
|
|
435
|
+
// What the read drops (CR-025). These stay at this one call: objects CR-007 keeps them per call.
|
|
436
|
+
onUnexpectedElement: (_name, node, classInfo) => kept.push(skippedElement(node, partName, classInfo.name)),
|
|
437
|
+
onUnexpectedAttribute: (name, node, classInfo) => kept.push(skippedAttribute(name, node, partName, classInfo.name)),
|
|
438
|
+
onUnexpectedText: (text, node, classInfo) => {
|
|
439
|
+
const skipped = skippedText(text, node, partName, classInfo.name);
|
|
440
|
+
textHolders.set(skipped, node.parentNode);
|
|
441
|
+
kept.push(skipped);
|
|
442
|
+
},
|
|
251
443
|
});
|
|
252
|
-
|
|
253
|
-
|
|
444
|
+
const reported = kept.filter((w) => !(w.code === 'part.skipped' && misplacedStrings.has(textHolders.get(w))));
|
|
445
|
+
if (reported.length > 0)
|
|
446
|
+
this.parseWarnings = [...this.parseWarnings, ...reported];
|
|
254
447
|
return element;
|
|
255
448
|
}
|
|
256
449
|
catch (cause) {
|
|
@@ -9,6 +9,7 @@ import { PartName } from '../../opc/PartName.mjs';
|
|
|
9
9
|
import { DefaultXmlPart } from '../DefaultXmlPart.mjs';
|
|
10
10
|
import { ThemePart } from '../dml/index.mjs';
|
|
11
11
|
import { Body } from '../../model/content/Body.mjs';
|
|
12
|
+
import type { PartWarning } from '../../opc/mce/preprocessor.mjs';
|
|
12
13
|
import type { AbstractListDefinition, ListDefinition } from '../../model/listnumbering/definitions.mjs';
|
|
13
14
|
import { NumberingDefinitions } from '../../model/listnumbering/definitions.mjs';
|
|
14
15
|
import { Emulator } from '../../model/listnumbering/Emulator.mjs';
|
|
@@ -44,7 +45,17 @@ export declare class MainDocumentPart extends DocumentPart<wml.Document> {
|
|
|
44
45
|
glossaryDocumentPart: GlossaryDocumentPart | undefined;
|
|
45
46
|
constructor(partName?: PartName | string, contentType?: string);
|
|
46
47
|
setPartShortcut(part: Part, relationshipType: string): boolean;
|
|
47
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* The root's qualified name where it is one Word opens showing nothing of (WD REQ-320, CR-028 D11), read as an empty
|
|
50
|
+
* document; undefined for a `w:document`, a root read as one, or contents a caller set.
|
|
51
|
+
*/
|
|
52
|
+
get unexpectedRoot(): string | undefined;
|
|
53
|
+
protected readRoot(doc: Document): readonly PartWarning[];
|
|
54
|
+
/**
|
|
55
|
+
* The Office JS-shaped view of `w:body`; the part must be unmarshalled (`getBody()` does that). Refused where the root is one
|
|
56
|
+
* Word shows nothing of, or `mc:AlternateContent` (CR-028 D10): either reads as no document here, and a write there would go
|
|
57
|
+
* nowhere a save keeps.
|
|
58
|
+
*/
|
|
48
59
|
get body(): Body;
|
|
49
60
|
getBody(): Promise<Body>;
|
|
50
61
|
private fontSelector;
|
package/dist/parts/wml/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { DefaultXmlPart } from '../DefaultXmlPart.mjs';
|
|
|
5
5
|
import { ThemePart } from '../dml/index.mjs';
|
|
6
6
|
import { Body } from '../../model/content/Body.mjs';
|
|
7
7
|
import { Docx4JException } from '../../opc/exceptions.mjs';
|
|
8
|
+
import { readMainPartRoot } from '../../opc/repair/mainRoot.mjs';
|
|
8
9
|
import { NumberingDefinitions } from '../../model/listnumbering/definitions.mjs';
|
|
9
10
|
import { Emulator } from '../../model/listnumbering/Emulator.mjs';
|
|
10
11
|
import { DEFAULT_NUMBERING_XML } from './defaultNumbering.mjs';
|
|
@@ -123,10 +124,33 @@ export class MainDocumentPart extends DocumentPart {
|
|
|
123
124
|
}
|
|
124
125
|
return super.setPartShortcut(part, relationshipType);
|
|
125
126
|
}
|
|
126
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* The root's qualified name where it is one Word opens showing nothing of (WD REQ-320, CR-028 D11), read as an empty
|
|
129
|
+
* document; undefined for a `w:document`, a root read as one, or contents a caller set.
|
|
130
|
+
*/
|
|
131
|
+
get unexpectedRoot() {
|
|
132
|
+
var _a;
|
|
133
|
+
return (_a = this.warnings.find((w) => w.code === 'part.unexpected_root')) === null || _a === void 0 ? void 0 : _a.root;
|
|
134
|
+
}
|
|
135
|
+
readRoot(doc) {
|
|
136
|
+
return readMainPartRoot(doc, this.partName.name);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The Office JS-shaped view of `w:body`; the part must be unmarshalled (`getBody()` does that). Refused where the root is one
|
|
140
|
+
* Word shows nothing of, or `mc:AlternateContent` (CR-028 D10): either reads as no document here, and a write there would go
|
|
141
|
+
* nowhere a save keeps.
|
|
142
|
+
*/
|
|
127
143
|
get body() {
|
|
128
144
|
var _a;
|
|
129
145
|
const doc = this.contents;
|
|
146
|
+
const unexpected = this.unexpectedRoot;
|
|
147
|
+
if (unexpected !== undefined) {
|
|
148
|
+
throw new Docx4JException(`${this.partName}: its root is ${unexpected}, which Word opens showing nothing of (WD REQ-320), so it has no body to read or write`);
|
|
149
|
+
}
|
|
150
|
+
if (doc.TYPE_NAME === 'org_docx4j_mce.AlternateContent') {
|
|
151
|
+
// the branch isn't read as the document yet (WD REQ-317), so a body added here would go nowhere a save writes (CR-028 D10)
|
|
152
|
+
throw new Docx4JException(`${this.partName}: its root is mc:AlternateContent, whose branch this package doesn't yet read as the document (WD REQ-317), so it has no body to read or write`);
|
|
153
|
+
}
|
|
130
154
|
(_a = doc.body) !== null && _a !== void 0 ? _a : (doc.body = { TYPE_NAME: 'org_docx4j_wml.Body' });
|
|
131
155
|
return bodyOf(this, doc.body, 'body');
|
|
132
156
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docx4j/core-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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.
|
|
86
|
+
"@docx4j/generated-objects-ts": "^0.8.0",
|
|
87
87
|
"fflate": "^0.8.2"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|