@docx4j/core-ts 0.5.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.
- package/NOTICE +4 -0
- package/README.md +32 -4
- package/dist/html/convert.mjs +2 -1
- package/dist/html/elements.mjs +2 -1
- package/dist/model/color/ColorMath.d.mts +29 -0
- package/dist/model/color/ColorMath.mjs +146 -0
- package/dist/model/color/ColorTables.d.mts +6 -0
- package/dist/model/color/ColorTables.mjs +83 -0
- package/dist/model/color/DrawingMLColors.d.mts +52 -0
- package/dist/model/color/DrawingMLColors.mjs +374 -0
- package/dist/model/color/ResolvedColor.d.mts +36 -0
- package/dist/model/color/ResolvedColor.mjs +65 -0
- package/dist/model/color/SpreadsheetColors.d.mts +36 -0
- package/dist/model/color/SpreadsheetColors.mjs +84 -0
- package/dist/model/color/StyleFill.d.mts +28 -0
- package/dist/model/color/StyleFill.mjs +21 -0
- package/dist/model/color/ThemeColors.d.mts +86 -0
- package/dist/model/color/ThemeColors.mjs +304 -0
- package/dist/model/color/WordColors.d.mts +71 -0
- package/dist/model/color/WordColors.mjs +121 -0
- package/dist/model/color/index.d.mts +6 -0
- package/dist/model/color/index.mjs +30 -0
- package/dist/model/content/Body.d.mts +145 -23
- package/dist/model/content/Body.mjs +509 -141
- package/dist/model/content/Comment.d.mts +21 -3
- package/dist/model/content/Comment.mjs +195 -19
- package/dist/model/content/ContentControl.d.mts +197 -18
- package/dist/model/content/ContentControl.mjs +664 -95
- package/dist/model/content/Font.d.mts +67 -17
- package/dist/model/content/Font.mjs +114 -35
- package/dist/model/content/InlinePicture.d.mts +11 -0
- package/dist/model/content/InlinePicture.mjs +21 -1
- package/dist/model/content/List.mjs +3 -0
- package/dist/model/content/Paragraph.d.mts +189 -13
- package/dist/model/content/Paragraph.mjs +870 -74
- package/dist/model/content/Range.d.mts +227 -12
- package/dist/model/content/Range.mjs +785 -59
- package/dist/model/content/ResolvedView.d.mts +104 -0
- package/dist/model/content/ResolvedView.mjs +596 -0
- package/dist/model/content/Table.d.mts +29 -3
- package/dist/model/content/Table.mjs +109 -33
- package/dist/model/content/TrackedChange.d.mts +172 -13
- package/dist/model/content/TrackedChange.mjs +728 -167
- package/dist/model/content/comments.d.mts +20 -6
- package/dist/model/content/comments.mjs +67 -57
- package/dist/model/content/generalException.d.mts +18 -0
- package/dist/model/content/generalException.mjs +24 -0
- package/dist/model/content/index.d.mts +8 -3
- package/dist/model/content/index.mjs +7 -2
- package/dist/model/content/mathText.d.mts +21 -0
- package/dist/model/content/mathText.mjs +267 -0
- package/dist/model/content/officeText.d.mts +27 -0
- package/dist/model/content/officeText.mjs +74 -0
- package/dist/model/content/outline.d.mts +5 -0
- package/dist/model/content/outline.mjs +13 -0
- package/dist/model/content/placeholders.d.mts +110 -0
- package/dist/model/content/placeholders.mjs +253 -0
- package/dist/model/content/search.d.mts +72 -0
- package/dist/model/content/search.mjs +204 -2
- package/dist/model/content/spanEdits.d.mts +159 -0
- package/dist/model/content/spanEdits.mjs +728 -0
- package/dist/model/content/story.d.mts +44 -0
- package/dist/model/content/story.mjs +92 -0
- package/dist/model/content/tableColumns.d.mts +1 -1
- package/dist/model/content/tableColumns.mjs +108 -80
- package/dist/model/content/tableRevisions.d.mts +11 -3
- package/dist/model/content/tableRevisions.mjs +72 -42
- package/dist/model/content/tableRules.d.mts +30 -0
- package/dist/model/content/tableRules.mjs +100 -0
- package/dist/model/content/textBoxes.d.mts +18 -0
- package/dist/model/content/textBoxes.mjs +105 -0
- package/dist/model/content/trackedChangeFilter.d.mts +39 -0
- package/dist/model/content/trackedChangeFilter.mjs +81 -0
- package/dist/model/content/tracking.d.mts +28 -0
- package/dist/model/content/tracking.mjs +149 -10
- package/dist/model/content/tree.d.mts +171 -22
- package/dist/model/content/tree.mjs +329 -53
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +8 -0
- package/dist/model/customxml/CustomXmlPartCollection.mjs +34 -11
- package/dist/model/customxml/XmlMapping.d.mts +1 -1
- package/dist/model/customxml/XmlMapping.mjs +11 -0
- package/dist/model/customxml/bindings.d.mts +21 -2
- package/dist/model/customxml/bindings.mjs +76 -32
- package/dist/model/customxml/kinds.d.mts +8 -3
- package/dist/model/customxml/kinds.mjs +26 -5
- package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
- package/dist/model/customxml/picturePlaceholder.mjs +32 -0
- package/dist/model/customxml/pictures.d.mts +4 -3
- package/dist/model/customxml/pictures.mjs +18 -6
- package/dist/model/customxml/xhtml.mjs +8 -2
- package/dist/model/index.d.mts +2 -0
- package/dist/model/index.mjs +4 -0
- package/dist/model/listnumbering/Emulator.d.mts +37 -5
- package/dist/model/listnumbering/Emulator.mjs +63 -9
- package/dist/model/properties/PropertyResolver.d.mts +60 -1
- package/dist/model/properties/PropertyResolver.mjs +115 -2
- package/dist/model/properties/catalogue.d.mts +19 -5
- package/dist/model/properties/catalogue.mjs +41 -15
- package/dist/model/properties/log.d.mts +1 -1
- package/dist/model/properties/log.mjs +5 -5
- package/dist/model/properties/table.mjs +4 -2
- package/dist/model/text/Extractor.d.mts +289 -0
- package/dist/model/text/Extractor.mjs +2162 -0
- package/dist/model/text/LinkTargets.d.mts +45 -0
- package/dist/model/text/LinkTargets.mjs +170 -0
- package/dist/model/text/MarkdownExporter.d.mts +140 -0
- package/dist/model/text/MarkdownExporter.mjs +255 -0
- package/dist/model/text/PlainText.d.mts +29 -0
- package/dist/model/text/PlainText.mjs +539 -0
- package/dist/model/text/TextContext.d.mts +161 -0
- package/dist/model/text/TextContext.mjs +425 -0
- package/dist/model/text/TextOptions.d.mts +150 -0
- package/dist/model/text/TextOptions.mjs +278 -0
- package/dist/model/text/TextResult.d.mts +504 -0
- package/dist/model/text/TextResult.mjs +526 -0
- package/dist/model/text/Texts.d.mts +99 -0
- package/dist/model/text/Texts.mjs +187 -0
- package/dist/model/text/WmlToMarkdown.d.mts +120 -0
- package/dist/model/text/WmlToMarkdown.mjs +911 -0
- package/dist/model/text/commonmark.d.mts +121 -0
- package/dist/model/text/commonmark.mjs +655 -0
- package/dist/model/text/index.d.mts +7 -0
- package/dist/model/text/index.mjs +8 -0
- package/dist/model/text/normalize.d.mts +8 -0
- package/dist/model/text/normalize.mjs +13 -0
- package/dist/model/text/outline.d.mts +4 -0
- package/dist/model/text/outline.mjs +71 -0
- package/dist/office-js/fragment.d.mts +7 -5
- package/dist/office-js/fragment.mjs +63 -14
- package/dist/office-js/proxy.d.mts +8 -0
- package/dist/office-js/proxy.mjs +29 -0
- package/dist/office-js/run.mjs +2 -0
- package/dist/office-js/supported.generated.mjs +16 -0
- package/dist/office-js/toApiScript.mjs +21 -5
- package/dist/opc/Save.d.mts +17 -0
- package/dist/opc/Save.mjs +12 -2
- package/dist/opc/index.d.mts +3 -3
- package/dist/opc/index.mjs +1 -1
- package/dist/opc/mce/preprocessor.d.mts +28 -3
- package/dist/opc/mce/preprocessor.mjs +4 -4
- package/dist/opc/mce/understood.d.mts +30 -6
- package/dist/opc/mce/understood.mjs +37 -7
- package/dist/packages/OpcPackage.d.mts +13 -0
- package/dist/packages/OpcPackage.mjs +1 -0
- package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
- package/dist/packages/WordprocessingMLPackage.mjs +155 -20
- package/dist/parts/DefaultXmlPart.mjs +2 -2
- package/dist/parts/Part.d.mts +10 -2
- package/dist/parts/XmlPart.d.mts +12 -30
- package/dist/parts/XmlPart.mjs +44 -93
- package/dist/parts/wml/comments.mjs +30 -0
- package/dist/parts/wml/index.mjs +12 -0
- package/dist/xml/dom.d.mts +7 -0
- package/dist/xml/dom.mjs +18 -0
- package/package.json +2 -2
|
@@ -137,13 +137,43 @@ export const UNDERSTOOD_NAMESPACES = new Set([
|
|
|
137
137
|
'http://schemas.microsoft.com/office/drawing/2015/9/8/chartex',
|
|
138
138
|
'http://schemas.microsoft.com/office/drawing/2015/10/21/chartex',
|
|
139
139
|
]);
|
|
140
|
+
const prefixesOf = (namespaces) => [...namespaces].map((uri) => NAMESPACE_PREFIXES[uri]).filter((prefix) => prefix !== undefined && prefix !== '');
|
|
140
141
|
/**
|
|
141
|
-
* The conventional prefixes of `UNDERSTOOD_NAMESPACES` (`NAMESPACE_PREFIXES`),
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* wherever the document writes the conventional prefixes. An understood namespace with no conventional
|
|
142
|
+
* The conventional prefixes of `UNDERSTOOD_NAMESPACES` (`NAMESPACE_PREFIXES`), the object model's namespaces
|
|
143
|
+
* expressed as prefixes (CR-010 section 11.5): the unmarshalled model does not keep the declarations in
|
|
144
|
+
* force at the element, so the objects package's `mcBranchOf` compares prefixes, and its default set,
|
|
145
|
+
* every prefix `NAMESPACE_PREFIXES` knows, is wider than what load understands. The readers match
|
|
146
|
+
* against `READ_UNDERSTOOD_PREFIXES`, this and four more. An understood namespace with no conventional
|
|
147
147
|
* prefix has no entry.
|
|
148
148
|
*/
|
|
149
|
-
export const UNDERSTOOD_PREFIXES = new Set(
|
|
149
|
+
export const UNDERSTOOD_PREFIXES = new Set(prefixesOf(UNDERSTOOD_NAMESPACES));
|
|
150
|
+
/**
|
|
151
|
+
* The namespaces a reader of a kept mc:AlternateContent counts as understood beyond `UNDERSTOOD_NAMESPACES`
|
|
152
|
+
* (CR-010 section 15): Word 365 takes a Choice requiring any of them (measured 2026-10-20), and docx4j's
|
|
153
|
+
* published understood list (`understood-namespaces.txt`) has all four, among the 11 its JAXB contexts
|
|
154
|
+
* bind and no generated module here does. The name is CR-010's, when only the readers counted them;
|
|
155
|
+
* since CR-013 (D3) resolving does too (`READ_UNDERSTOOD_NAMESPACES`). Resolving turns the Choice it takes
|
|
156
|
+
* into typed content, which no module types here, but what Word writes in these namespaces survives a
|
|
157
|
+
* re-marshal: in every file seen it is attributes only (`w16du:dateUtc`, `w16sdtdh:storeItemChecksum`,
|
|
158
|
+
* `x14ac:dyDescent` and `x14ac:knownFonts`; `w16sdtfl` is only declared), measured 2026-10-21.
|
|
159
|
+
*/
|
|
160
|
+
export const READ_ONLY_UNDERSTOOD_NAMESPACES = new Set([
|
|
161
|
+
'http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash', // w16sdtdh
|
|
162
|
+
'http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock', // w16sdtfl
|
|
163
|
+
'http://schemas.microsoft.com/office/word/2023/wordml/word16du', // w16du
|
|
164
|
+
'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac', // x14ac
|
|
165
|
+
]);
|
|
166
|
+
/**
|
|
167
|
+
* What a reader of a kept mc:AlternateContent matches `mc:Choice/@Requires` against (`selectedBranchOf`,
|
|
168
|
+
* docx4j's `McMode.READ`): `UNDERSTOOD_PREFIXES` and the conventional prefixes of
|
|
169
|
+
* `READ_ONLY_UNDERSTOOD_NAMESPACES`. A Choice requiring only these is taken by the gate alone, as REQ-302
|
|
170
|
+
* of the text extraction specification reads, whatever its content (CR-010 section 15).
|
|
171
|
+
*/
|
|
172
|
+
export const READ_UNDERSTOOD_PREFIXES = new Set([...UNDERSTOOD_PREFIXES, ...prefixesOf(READ_ONLY_UNDERSTOOD_NAMESPACES)]);
|
|
173
|
+
/**
|
|
174
|
+
* What load selects by, as namespaces: `UNDERSTOOD_NAMESPACES` and `READ_ONLY_UNDERSTOOD_NAMESPACES`, the
|
|
175
|
+
* readers' set (`READ_UNDERSTOOD_PREFIXES`) by URI. Resolving (`mcePreprocess: true`) takes the Choice it
|
|
176
|
+
* names, and the default load's `mce.branches_differ` reports it as the selected branch, so a resolved load
|
|
177
|
+
* takes the branch the readers of a kept load take, as Word 365 does (CR-013 D3).
|
|
178
|
+
*/
|
|
179
|
+
export const READ_UNDERSTOOD_NAMESPACES = new Set([...UNDERSTOOD_NAMESPACES, ...READ_ONLY_UNDERSTOOD_NAMESPACES]);
|
|
@@ -4,6 +4,7 @@ import { ContentTypeManager } from '../opc/ContentTypeManager.mjs';
|
|
|
4
4
|
import { type PartStore, type PartSink } from '../opc/PartStore.mjs';
|
|
5
5
|
import { type FlatOpcSinkOptions } from '../opc/FlatOpcPartStore.mjs';
|
|
6
6
|
import { type LoadOptions } from '../opc/Load.mjs';
|
|
7
|
+
import { type SaveReport } from '../opc/Save.mjs';
|
|
7
8
|
import { Part, type RelationshipSource } from '../parts/Part.mjs';
|
|
8
9
|
import { Parts } from '../parts/Parts.mjs';
|
|
9
10
|
import { RelationshipsPart, type AddPartBehaviour } from '../parts/RelationshipsPart.mjs';
|
|
@@ -31,6 +32,18 @@ export declare class OpcPackage implements RelationshipSource {
|
|
|
31
32
|
docPropsCorePart: DocPropsCorePart | undefined;
|
|
32
33
|
docPropsExtendedPart: DocPropsExtendedPart | undefined;
|
|
33
34
|
docPropsCustomPart: DocPropsCustomPart | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Whether a save writes run properties in their normal form (CR-015 D2; docx4j CR-061's
|
|
37
|
+
* `setNormaliseOnSave`): a colour Word accepts as upper-case `RRGGBB`, one it rejects left out (a text or
|
|
38
|
+
* underline colour) or `auto` (a fill's, a border's), a `w:highlight`, `w:vertAlign` or `w:em` Word repairs away
|
|
39
|
+
* left out; a revision's former properties too. Only what is written changes: the tree keeps what it read, and a
|
|
40
|
+
* part nobody unmarshalled is still copied byte for byte. Undefined defers to the objects package's process-wide
|
|
41
|
+
* `setNormaliseOnSave` (on unless set off); a package's own setting wins over it. False writes values as read.
|
|
42
|
+
* On/off values and `w:u`'s are settled when the part is read, so they are written the same either way.
|
|
43
|
+
*/
|
|
44
|
+
normaliseOnSave: boolean | undefined;
|
|
45
|
+
/** What the last save did beyond writing the package: each value it normalised (CR-015 D8). Undefined until one. */
|
|
46
|
+
lastSave: SaveReport | undefined;
|
|
34
47
|
constructor();
|
|
35
48
|
get package(): OpcPackage;
|
|
36
49
|
/**
|
|
@@ -135,6 +135,7 @@ export class OpcPackage {
|
|
|
135
135
|
if (copy.constructor !== this.constructor) {
|
|
136
136
|
throw new Docx4JException(`Cloning ${this.constructor.name} produced ${copy.constructor.name}`);
|
|
137
137
|
}
|
|
138
|
+
copy.normaliseOnSave = this.normaliseOnSave;
|
|
138
139
|
this.copyPackageSettingsTo(copy);
|
|
139
140
|
return copy;
|
|
140
141
|
}
|
|
@@ -4,6 +4,7 @@ import type { Part } from '../parts/Part.mjs';
|
|
|
4
4
|
import { MainDocumentPart, StyleDefinitionsPart, type NumberingDefinitionsPart } from '../parts/wml/index.mjs';
|
|
5
5
|
import { type FontSettings, type DefaultThemeValue } from '../model/fonts/defaultTheme.mjs';
|
|
6
6
|
import { Body, type Address, type Outline, type OutlineParagraph, type OutlineTable } from '../model/content/Body.mjs';
|
|
7
|
+
import { type TrackedChangeSelection } from '../model/content/trackedChangeFilter.mjs';
|
|
7
8
|
import type { Paragraph } from '../model/content/Paragraph.mjs';
|
|
8
9
|
import type { Author } from '../model/content/comments.mjs';
|
|
9
10
|
import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
|
|
@@ -11,6 +12,7 @@ import { type XPathEngine } from '../model/customxml/xpath.mjs';
|
|
|
11
12
|
import { ChangeTracker, type ChangeTrackingMode, type TrackingHost, type TrackingScope } from '../model/content/tracking.mjs';
|
|
12
13
|
import { NumberingFacade } from '../model/content/List.mjs';
|
|
13
14
|
import { StylesFacade } from '../model/content/stylesFacade.mjs';
|
|
15
|
+
import { GlossaryEntries } from '../model/content/placeholders.mjs';
|
|
14
16
|
import type { Bound } from '../model/content/binder.mjs';
|
|
15
17
|
import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
|
|
16
18
|
import type { Emulator } from '../model/listnumbering/Emulator.mjs';
|
|
@@ -19,6 +21,9 @@ import { type RelationshipRemovals } from '../model/content/relationships.mjs';
|
|
|
19
21
|
import { XmlPart } from '../parts/XmlPart.mjs';
|
|
20
22
|
import type { PartSink } from '../opc/PartStore.mjs';
|
|
21
23
|
import '../parts/wml/comments.mjs';
|
|
24
|
+
import '../model/text/outline.mjs';
|
|
25
|
+
import type { TextContext } from '../model/text/TextContext.mjs';
|
|
26
|
+
import type { TextOptions, TextOptionsInit } from '../model/text/TextOptions.mjs';
|
|
22
27
|
/** The outline of a document: the body's paragraphs and tables, then each header's and footer's (loaded ones only). */
|
|
23
28
|
export interface DocumentOutline extends Outline {
|
|
24
29
|
headers: {
|
|
@@ -102,6 +107,12 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
|
|
|
102
107
|
* 47). Settled on save, not at once, so a picture cut and pasted back keeps its image. An extension.
|
|
103
108
|
*/
|
|
104
109
|
readonly pendingRelationshipRemovals: RelationshipRemovals;
|
|
110
|
+
/**
|
|
111
|
+
* The glossary's placeholder entries: read privately when a body is first read (`getBody`, `Word.run`), and those a
|
|
112
|
+
* placeholder written since names, which go into the glossary when the package is saved, the glossary made where the
|
|
113
|
+
* file has none (CR-002 section 63, D8 and D9). An extension.
|
|
114
|
+
*/
|
|
115
|
+
readonly glossaryEntries: GlossaryEntries;
|
|
105
116
|
/**
|
|
106
117
|
* The parts `seedAnnotationIds()` has read, with what it read: `true` for a part still holding its
|
|
107
118
|
* source, whose bytes cannot change, and otherwise the bytes that were set, which stay the same
|
|
@@ -212,10 +223,24 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
|
|
|
212
223
|
private settingsPart;
|
|
213
224
|
/**
|
|
214
225
|
* Office JS `document.getTrackedChanges()`: every tracked change in the main document part,
|
|
215
|
-
* in document order (headers and footers have their own `Body`
|
|
216
|
-
* unmarshalled, as `body` needs it to be.
|
|
226
|
+
* in document order (headers and footers have their own `Body`; `getAllTrackedChanges` lists
|
|
227
|
+
* every story). The part must be unmarshalled, as `body` needs it to be.
|
|
217
228
|
*/
|
|
218
229
|
getTrackedChanges(): TrackedChange[];
|
|
230
|
+
/**
|
|
231
|
+
* Every tracked change in every story, in docx4j's order (its CR-043 `TrackedChanges.in`, CR-011):
|
|
232
|
+
* the main document, each footnote, each endnote, each comment, then the headers and footers in the
|
|
233
|
+
* order the sections reference them; a text box's after the story it is in. Each story's are its
|
|
234
|
+
* `Body.getTrackedChanges()`, grouped as Office JS groups them, so changes never group across two
|
|
235
|
+
* stories. `TrackedChange.part` says which part each is in.
|
|
236
|
+
*
|
|
237
|
+
* With a filter, the changes with a piece it matches, each whole (docx4j's `in(pkg, filter)`).
|
|
238
|
+
*
|
|
239
|
+
* A story part whose source holds no revision markup is not read, so it keeps its bytes; one that
|
|
240
|
+
* does is unmarshalled, since the views returned must be resolvable, and so is re-marshalled on save.
|
|
241
|
+
* An extension: Office JS lists one body at a time.
|
|
242
|
+
*/
|
|
243
|
+
getAllTrackedChanges(filter?: TrackedChangeSelection): Promise<TrackedChange[]>;
|
|
219
244
|
/**
|
|
220
245
|
* Accepts every tracked change in every story: the main document, the footnotes, the endnotes and
|
|
221
246
|
* the comments, the headers and footers, and the text boxes in each. Word's
|
|
@@ -223,15 +248,19 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
|
|
|
223
248
|
* revision in any story; `Body.acceptAll` resolves its own story only, as Office JS's `body` does
|
|
224
249
|
* (CR-002 section 49). A story part with no revision markup is not read, so it keeps its bytes.
|
|
225
250
|
* Returns how many changes were listed, story by story. An extension, named after Word's verb.
|
|
251
|
+
*
|
|
252
|
+
* With a filter (CR-011), only the single changes it matches are accepted, as `Body.acceptAll`
|
|
253
|
+
* takes one, and the count is of the listed changes with a matching piece.
|
|
226
254
|
*/
|
|
227
|
-
acceptAllRevisions(): Promise<number>;
|
|
255
|
+
acceptAllRevisions(filter?: TrackedChangeSelection): Promise<number>;
|
|
228
256
|
/** Rejects every tracked change in every story, as `acceptAllRevisions` accepts them (Word's `Document.RejectAllRevisions`). */
|
|
229
|
-
rejectAllRevisions(): Promise<number>;
|
|
257
|
+
rejectAllRevisions(filter?: TrackedChangeSelection): Promise<number>;
|
|
230
258
|
private resolveEveryStory;
|
|
231
259
|
/**
|
|
232
260
|
* The body of every story whose part holds revision markup, in docx4j's order (its CR-043
|
|
233
261
|
* `TrackedChanges.in`): the main document, each footnote, each endnote, each comment, then the
|
|
234
|
-
* headers and footers. A footnote, an endnote or a comment is a
|
|
262
|
+
* headers and footers in section order (`inSectionOrder`). A footnote, an endnote or a comment is a
|
|
263
|
+
* body of its own over its content.
|
|
235
264
|
*/
|
|
236
265
|
private revisedStories;
|
|
237
266
|
/** The tracker every content-API mutation asks for; undefined while the mode is `Off`. */
|
|
@@ -294,10 +323,18 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
|
|
|
294
323
|
/** A clone carries the identity, the tracking date, the theme setting, the XPath engine and the styles still to ensure. */
|
|
295
324
|
protected copyPackageSettingsTo(target: OpcPackage): void;
|
|
296
325
|
saveTo<R>(sink: PartSink<R>): Promise<R>;
|
|
297
|
-
/**
|
|
326
|
+
/**
|
|
327
|
+
* The paragraph at an address anywhere in the document: 'body/3', 'header:rId5/0', 'footnote:2/0',
|
|
328
|
+
* 'endnote:1/0', 'comment:5/0', 'body/3/textbox:0/1' (a text box's paragraph, read-only: CR-012 D4 and
|
|
329
|
+
* D5), a paraId, or a text match. Undefined where the address names no paragraph.
|
|
330
|
+
*/
|
|
298
331
|
paragraphAt(address: Address): Promise<Paragraph | undefined>;
|
|
299
|
-
/**
|
|
300
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Every paragraph and table with its address, style and text (CR-002 section 3.3), read by the text model
|
|
334
|
+
* under one context (CR-012 D3: `Body.outline`, whose options it takes): the main document, then each
|
|
335
|
+
* header and footer. Unmarshals the main part, headers and footers.
|
|
336
|
+
*/
|
|
337
|
+
outline(options?: TextOptionsInit | TextOptions, context?: TextContext): Promise<DocumentOutline>;
|
|
301
338
|
private bodies;
|
|
302
339
|
/**
|
|
303
340
|
* The XPath engine the custom XML views use (CR-002 section 3.6): `document.evaluate` in a
|
|
@@ -4,27 +4,33 @@ import { registerPackageClass } from './registry.mjs';
|
|
|
4
4
|
import { ContentTypes } from '../opc/ContentTypes.mjs';
|
|
5
5
|
import { Docx4JException } from '../opc/exceptions.mjs';
|
|
6
6
|
import { Namespaces } from '../parts/Namespaces.mjs';
|
|
7
|
-
import { MainDocumentPart, StyleDefinitionsPart, DocumentSettingsPart } from '../parts/wml/index.mjs';
|
|
7
|
+
import { MainDocumentPart, StyleDefinitionsPart, DocumentSettingsPart, GlossaryDocumentPart } from '../parts/wml/index.mjs';
|
|
8
8
|
import { DocPropsCorePart, DocPropsExtendedPart } from '../parts/docProps/index.mjs';
|
|
9
9
|
import { DEFAULT_STYLES_XML } from '../parts/wml/defaultStyles.mjs';
|
|
10
10
|
import { ThemePart } from '../parts/dml/index.mjs';
|
|
11
11
|
import { newFontSettings, themeOfSettings, } from '../model/fonts/defaultTheme.mjs';
|
|
12
12
|
import { HeaderPart, FooterPart } from '../parts/wml/index.mjs';
|
|
13
|
-
import { Body, resolveStory } from '../model/content/Body.mjs';
|
|
13
|
+
import { Body, resolveStory, trackedChangesOfStory } from '../model/content/Body.mjs';
|
|
14
|
+
import { pieceMatcher } from '../model/content/trackedChangeFilter.mjs';
|
|
14
15
|
import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
|
|
15
16
|
import { DefaultXPathEngine } from '../model/customxml/xpath.mjs';
|
|
16
17
|
import { ChangeTracker, highestAnnotationId } from '../model/content/tracking.mjs';
|
|
17
18
|
import { NumberingFacade } from '../model/content/List.mjs';
|
|
18
19
|
import { StylesFacade } from '../model/content/stylesFacade.mjs';
|
|
19
20
|
import { flushPendingCommentRemovals } from '../model/content/Comment.mjs';
|
|
21
|
+
import { GlossaryEntries } from '../model/content/placeholders.mjs';
|
|
20
22
|
import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
|
|
21
23
|
import { PropertyResolverNotCreatedException } from '../opc/exceptions.mjs';
|
|
22
|
-
import { flushPendingNoteRemovals } from '../model/content/TrackedChange.mjs';
|
|
24
|
+
import { flushPendingNoteRemovals, notesGoing } from '../model/content/TrackedChange.mjs';
|
|
23
25
|
import { flushPendingRelationshipRemovals } from '../model/content/relationships.mjs';
|
|
24
26
|
import { XmlPart } from '../parts/XmlPart.mjs';
|
|
25
27
|
// Registers the comment parts with the content API (CR-002 phase G); no cycle: the model half
|
|
26
28
|
// never imports a part, as packages/registry.mts does for the package classes.
|
|
27
29
|
import '../parts/wml/comments.mjs';
|
|
30
|
+
// Registers the text model's outline reader with Body.outline (CR-012 D3), the same way: the content API
|
|
31
|
+
// can't import the text model, which imports it.
|
|
32
|
+
import '../model/text/outline.mjs';
|
|
33
|
+
import { Texts } from '../model/text/Texts.mjs';
|
|
28
34
|
const MAIN_CONTENT_TYPES = [
|
|
29
35
|
ContentTypes.WORDPROCESSINGML_DOCUMENT,
|
|
30
36
|
ContentTypes.WORDPROCESSINGML_DOCUMENT_MACROENABLED,
|
|
@@ -105,6 +111,12 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
105
111
|
* 47). Settled on save, not at once, so a picture cut and pasted back keeps its image. An extension.
|
|
106
112
|
*/
|
|
107
113
|
this.pendingRelationshipRemovals = new Map();
|
|
114
|
+
/**
|
|
115
|
+
* The glossary's placeholder entries: read privately when a body is first read (`getBody`, `Word.run`), and those a
|
|
116
|
+
* placeholder written since names, which go into the glossary when the package is saved, the glossary made where the
|
|
117
|
+
* file has none (CR-002 section 63, D8 and D9). An extension.
|
|
118
|
+
*/
|
|
119
|
+
this.glossaryEntries = new GlossaryEntries();
|
|
108
120
|
/**
|
|
109
121
|
* The parts `seedAnnotationIds()` has read, with what it read: `true` for a part still holding its
|
|
110
122
|
* source, whose bytes cannot change, and otherwise the bytes that were set, which stay the same
|
|
@@ -414,12 +426,32 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
414
426
|
}
|
|
415
427
|
/**
|
|
416
428
|
* Office JS `document.getTrackedChanges()`: every tracked change in the main document part,
|
|
417
|
-
* in document order (headers and footers have their own `Body`
|
|
418
|
-
* unmarshalled, as `body` needs it to be.
|
|
429
|
+
* in document order (headers and footers have their own `Body`; `getAllTrackedChanges` lists
|
|
430
|
+
* every story). The part must be unmarshalled, as `body` needs it to be.
|
|
419
431
|
*/
|
|
420
432
|
getTrackedChanges() {
|
|
421
433
|
return this.body.getTrackedChanges();
|
|
422
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Every tracked change in every story, in docx4j's order (its CR-043 `TrackedChanges.in`, CR-011):
|
|
437
|
+
* the main document, each footnote, each endnote, each comment, then the headers and footers in the
|
|
438
|
+
* order the sections reference them; a text box's after the story it is in. Each story's are its
|
|
439
|
+
* `Body.getTrackedChanges()`, grouped as Office JS groups them, so changes never group across two
|
|
440
|
+
* stories. `TrackedChange.part` says which part each is in.
|
|
441
|
+
*
|
|
442
|
+
* With a filter, the changes with a piece it matches, each whole (docx4j's `in(pkg, filter)`).
|
|
443
|
+
*
|
|
444
|
+
* A story part whose source holds no revision markup is not read, so it keeps its bytes; one that
|
|
445
|
+
* does is unmarshalled, since the views returned must be resolvable, and so is re-marshalled on save.
|
|
446
|
+
* An extension: Office JS lists one body at a time.
|
|
447
|
+
*/
|
|
448
|
+
async getAllTrackedChanges(filter) {
|
|
449
|
+
const matches = filter === undefined ? undefined : pieceMatcher(filter);
|
|
450
|
+
const out = [];
|
|
451
|
+
for (const body of await this.revisedStories())
|
|
452
|
+
out.push(...trackedChangesOfStory(body));
|
|
453
|
+
return matches ? out.filter((change) => change.pieces.some(matches)) : out;
|
|
454
|
+
}
|
|
423
455
|
/**
|
|
424
456
|
* Accepts every tracked change in every story: the main document, the footnotes, the endnotes and
|
|
425
457
|
* the comments, the headers and footers, and the text boxes in each. Word's
|
|
@@ -427,24 +459,30 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
427
459
|
* revision in any story; `Body.acceptAll` resolves its own story only, as Office JS's `body` does
|
|
428
460
|
* (CR-002 section 49). A story part with no revision markup is not read, so it keeps its bytes.
|
|
429
461
|
* Returns how many changes were listed, story by story. An extension, named after Word's verb.
|
|
462
|
+
*
|
|
463
|
+
* With a filter (CR-011), only the single changes it matches are accepted, as `Body.acceptAll`
|
|
464
|
+
* takes one, and the count is of the listed changes with a matching piece.
|
|
430
465
|
*/
|
|
431
|
-
async acceptAllRevisions() {
|
|
432
|
-
return this.resolveEveryStory('accept');
|
|
466
|
+
async acceptAllRevisions(filter) {
|
|
467
|
+
return this.resolveEveryStory('accept', filter);
|
|
433
468
|
}
|
|
434
469
|
/** Rejects every tracked change in every story, as `acceptAllRevisions` accepts them (Word's `Document.RejectAllRevisions`). */
|
|
435
|
-
async rejectAllRevisions() {
|
|
436
|
-
return this.resolveEveryStory('reject');
|
|
470
|
+
async rejectAllRevisions(filter) {
|
|
471
|
+
return this.resolveEveryStory('reject', filter);
|
|
437
472
|
}
|
|
438
|
-
async resolveEveryStory(what) {
|
|
473
|
+
async resolveEveryStory(what, filter) {
|
|
474
|
+
if (filter !== undefined)
|
|
475
|
+
pieceMatcher(filter); // a filter misread throws before anything is read or resolved
|
|
439
476
|
let count = 0;
|
|
440
477
|
for (const body of await this.revisedStories())
|
|
441
|
-
count += resolveStory(body, what);
|
|
478
|
+
count += resolveStory(body, what, filter);
|
|
442
479
|
return count;
|
|
443
480
|
}
|
|
444
481
|
/**
|
|
445
482
|
* The body of every story whose part holds revision markup, in docx4j's order (its CR-043
|
|
446
483
|
* `TrackedChanges.in`): the main document, each footnote, each endnote, each comment, then the
|
|
447
|
-
* headers and footers. A footnote, an endnote or a comment is a
|
|
484
|
+
* headers and footers in section order (`inSectionOrder`). A footnote, an endnote or a comment is a
|
|
485
|
+
* body of its own over its content.
|
|
448
486
|
*/
|
|
449
487
|
async revisedStories() {
|
|
450
488
|
var _a, _b;
|
|
@@ -452,22 +490,33 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
452
490
|
const out = [];
|
|
453
491
|
if (await holdsRevisions(main))
|
|
454
492
|
out.push(await main.getBody());
|
|
493
|
+
// a note or comment a resolution has taken the reference or anchor of goes on save; it is no story now
|
|
494
|
+
const pending = this.pendingNoteRemovals;
|
|
495
|
+
const going = pending.footnote.size + pending.endnote.size > 0 ? notesGoing(await main.readContents(), pending) : pending;
|
|
455
496
|
for (const [part, kind] of [[main.footnotesPart, 'footnote'], [main.endnotesPart, 'endnote']]) {
|
|
456
497
|
if (!part || !(await holdsRevisions(part)))
|
|
457
498
|
continue;
|
|
458
499
|
const contents = await part.getContents();
|
|
459
500
|
for (const note of (_a = (kind === 'footnote' ? contents.footnote : contents.endnote)) !== null && _a !== void 0 ? _a : []) {
|
|
501
|
+
if ((note.type === undefined || note.type === 'normal') && going[kind].has(Number(note.id)))
|
|
502
|
+
continue;
|
|
460
503
|
out.push(new Body(part, note, `${kind}:${note.id}`, this));
|
|
461
504
|
}
|
|
462
505
|
}
|
|
463
506
|
const comments = main.commentsPart;
|
|
464
507
|
if (comments && (await holdsRevisions(comments))) {
|
|
465
|
-
for (const comment of (_b = (await comments.getContents()).comment) !== null && _b !== void 0 ? _b : [])
|
|
508
|
+
for (const comment of (_b = (await comments.getContents()).comment) !== null && _b !== void 0 ? _b : []) {
|
|
509
|
+
if (this.pendingCommentRemovals.has(comment.id))
|
|
510
|
+
continue;
|
|
466
511
|
out.push(new Body(comments, comment, `comment:${comment.id}`, this));
|
|
512
|
+
}
|
|
467
513
|
}
|
|
514
|
+
const revised = [];
|
|
468
515
|
for (const part of [...main.headerParts, ...main.footerParts])
|
|
469
516
|
if (await holdsRevisions(part))
|
|
470
|
-
|
|
517
|
+
revised.push(part);
|
|
518
|
+
for (const part of revised.length > 1 ? await inSectionOrder(main, revised) : revised)
|
|
519
|
+
out.push(await part.getBody());
|
|
471
520
|
return out;
|
|
472
521
|
}
|
|
473
522
|
/** The tracker every content-API mutation asks for; undefined while the mode is `Off`. */
|
|
@@ -583,6 +632,7 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
583
632
|
target.pendingNoteRemovals.endnote.add(id);
|
|
584
633
|
for (const [name, ids] of this.pendingRelationshipRemovals)
|
|
585
634
|
target.pendingRelationshipRemovals.set(name, new Set(ids));
|
|
635
|
+
this.glossaryEntries.copyTo(target.glossaryEntries);
|
|
586
636
|
target.trackedChangeDate = this.trackedChangeDate;
|
|
587
637
|
target.fonts.defaultTheme = this.fonts.defaultTheme;
|
|
588
638
|
target.xpathEngine = this.xpathEngine;
|
|
@@ -603,13 +653,23 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
603
653
|
}
|
|
604
654
|
if (this.pendingRelationshipRemovals.size > 0)
|
|
605
655
|
flushPendingRelationshipRemovals(this, this.pendingRelationshipRemovals);
|
|
656
|
+
if (this.glossaryEntries.waiting) {
|
|
657
|
+
await this.glossaryEntries.flush(this, {
|
|
658
|
+
glossary: () => new GlossaryDocumentPart(),
|
|
659
|
+
styles: () => new StyleDefinitionsPart('/word/glossary/styles.xml'),
|
|
660
|
+
});
|
|
661
|
+
}
|
|
606
662
|
if (this.requiredStyles.size > 0) {
|
|
607
663
|
await this.styles.ensure([...this.requiredStyles]);
|
|
608
664
|
this.requiredStyles.clear();
|
|
609
665
|
}
|
|
610
666
|
return super.saveTo(sink);
|
|
611
667
|
}
|
|
612
|
-
/**
|
|
668
|
+
/**
|
|
669
|
+
* The paragraph at an address anywhere in the document: 'body/3', 'header:rId5/0', 'footnote:2/0',
|
|
670
|
+
* 'endnote:1/0', 'comment:5/0', 'body/3/textbox:0/1' (a text box's paragraph, read-only: CR-012 D4 and
|
|
671
|
+
* D5), a paraId, or a text match. Undefined where the address names no paragraph.
|
|
672
|
+
*/
|
|
613
673
|
async paragraphAt(address) {
|
|
614
674
|
for (const body of await this.bodies(address)) {
|
|
615
675
|
const p = body.paragraphAt(address);
|
|
@@ -618,28 +678,44 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
618
678
|
}
|
|
619
679
|
return undefined;
|
|
620
680
|
}
|
|
621
|
-
/**
|
|
622
|
-
|
|
681
|
+
/**
|
|
682
|
+
* Every paragraph and table with its address, style and text (CR-002 section 3.3), read by the text model
|
|
683
|
+
* under one context (CR-012 D3: `Body.outline`, whose options it takes): the main document, then each
|
|
684
|
+
* header and footer. Unmarshals the main part, headers and footers.
|
|
685
|
+
*/
|
|
686
|
+
async outline(options, context) {
|
|
623
687
|
var _a, _b, _c, _d;
|
|
624
688
|
const main = await this.getBody();
|
|
625
|
-
const
|
|
689
|
+
const ctx = context !== null && context !== void 0 ? context : await Texts.contextOf(this);
|
|
690
|
+
const out = { ...await main.outline(options, ctx), headers: [], footers: [] };
|
|
626
691
|
for (const part of this.getMainDocumentPart().headerParts) {
|
|
627
692
|
const body = await part.getBody();
|
|
628
|
-
out.headers.push({ relId: (_b = (_a = part.sourceRelationship) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '', partName: part.partName.name, ...body.outline() });
|
|
693
|
+
out.headers.push({ relId: (_b = (_a = part.sourceRelationship) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : '', partName: part.partName.name, ...await body.outline(options, ctx) });
|
|
629
694
|
}
|
|
630
695
|
for (const part of this.getMainDocumentPart().footerParts) {
|
|
631
696
|
const body = await part.getBody();
|
|
632
|
-
out.footers.push({ relId: (_d = (_c = part.sourceRelationship) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : '', partName: part.partName.name, ...body.outline() });
|
|
697
|
+
out.footers.push({ relId: (_d = (_c = part.sourceRelationship) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : '', partName: part.partName.name, ...await body.outline(options, ctx) });
|
|
633
698
|
}
|
|
634
699
|
return out;
|
|
635
700
|
}
|
|
636
701
|
async bodies(address) {
|
|
702
|
+
var _a;
|
|
637
703
|
const main = this.getMainDocumentPart();
|
|
638
704
|
if (typeof address === 'string' && !address.startsWith('w14:')) {
|
|
639
705
|
const prefix = address.split('/')[0];
|
|
640
706
|
if (prefix === 'body')
|
|
641
707
|
return [await main.getBody()];
|
|
642
708
|
const [kind, relId] = prefix.split(':');
|
|
709
|
+
if (kind === 'footnote' || kind === 'endnote' || kind === 'comment') {
|
|
710
|
+
// a note's or a comment's body, by its w:id, as the text model and Comment address them (CR-012 D4)
|
|
711
|
+
const part = kind === 'footnote' ? main.footnotesPart : kind === 'endnote' ? main.endnotesPart : main.commentsPart;
|
|
712
|
+
if (!part)
|
|
713
|
+
return [];
|
|
714
|
+
const contents = await part.getContents();
|
|
715
|
+
const entry = ((_a = contents[kind]) !== null && _a !== void 0 ? _a : []).find((e) => String(e.id) === relId);
|
|
716
|
+
await this.getPropertyResolver().catch(() => undefined);
|
|
717
|
+
return entry ? [new Body(part, entry, `${kind}:${relId}`, this)] : [];
|
|
718
|
+
}
|
|
643
719
|
const parts = kind === 'header' ? main.headerParts : kind === 'footer' ? main.footerParts : [];
|
|
644
720
|
const part = parts.find((p) => { var _a; return ((_a = p.sourceRelationship) === null || _a === void 0 ? void 0 : _a.id) === relId || p.partName.fileName === relId; });
|
|
645
721
|
return part instanceof HeaderPart || part instanceof FooterPart ? [await part.getBody()] : [];
|
|
@@ -715,6 +791,65 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
715
791
|
return 'Word.Document';
|
|
716
792
|
}
|
|
717
793
|
}
|
|
794
|
+
/**
|
|
795
|
+
* Headers and footers in docx4j's order (its CR-043 `Lister.headersAndFooters`): as the sections
|
|
796
|
+
* reference them, in document order, a part once, then any other in the order of the main part's
|
|
797
|
+
* relationships. The main part's tree is read privately, so a main part nobody has otherwise read keeps
|
|
798
|
+
* its bytes.
|
|
799
|
+
*/
|
|
800
|
+
async function inSectionOrder(main, parts) {
|
|
801
|
+
var _a;
|
|
802
|
+
const rels = main.relationshipsPart;
|
|
803
|
+
if (!rels)
|
|
804
|
+
return parts;
|
|
805
|
+
const order = [];
|
|
806
|
+
const add = (part) => {
|
|
807
|
+
const known = parts.find((p) => p === part);
|
|
808
|
+
if (known && !order.includes(known))
|
|
809
|
+
order.push(known);
|
|
810
|
+
};
|
|
811
|
+
const body = (await main.readContents()).body;
|
|
812
|
+
for (const sectPr of sectionsOf(body))
|
|
813
|
+
for (const ref of (_a = sectPr.egHdrFtrReferences) !== null && _a !== void 0 ? _a : [])
|
|
814
|
+
add(rels.getPart(ref.id));
|
|
815
|
+
for (const rel of rels.list)
|
|
816
|
+
add(rels.getPart(rel));
|
|
817
|
+
for (const part of parts)
|
|
818
|
+
if (!order.includes(part))
|
|
819
|
+
order.push(part);
|
|
820
|
+
return order;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* The body's `w:sectPr`s in document order, the paragraphs' first and the body's own last, as docx4j's
|
|
824
|
+
* walk finds them: not inside a run (where a text box's paragraphs are), DOM the model does not type
|
|
825
|
+
* left alone.
|
|
826
|
+
*/
|
|
827
|
+
function sectionsOf(body) {
|
|
828
|
+
const out = [];
|
|
829
|
+
const visit = (o) => {
|
|
830
|
+
if (typeof o !== 'object' || o === null || typeof o.nodeType === 'number')
|
|
831
|
+
return;
|
|
832
|
+
if (Array.isArray(o)) {
|
|
833
|
+
for (const item of o)
|
|
834
|
+
visit(item);
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
const typeName = o.TYPE_NAME;
|
|
838
|
+
if (typeName === 'org_docx4j_wml.SectPr') {
|
|
839
|
+
out.push(o);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (typeName === 'org_docx4j_wml.R')
|
|
843
|
+
return;
|
|
844
|
+
for (const key in o)
|
|
845
|
+
if (key !== 'PARENT')
|
|
846
|
+
visit(o[key]);
|
|
847
|
+
};
|
|
848
|
+
visit(body === null || body === void 0 ? void 0 : body.content);
|
|
849
|
+
if (body === null || body === void 0 ? void 0 : body.sectPr)
|
|
850
|
+
out.push(body.sectPr);
|
|
851
|
+
return out;
|
|
852
|
+
}
|
|
718
853
|
/** Revision markup, by local name in any prefix: what a story part holds when it has a tracked change to resolve. */
|
|
719
854
|
const REVISION_MARKUP = /<(?:[\w.-]+:)?(?:ins|del|moveFrom|moveTo|rPrChange|pPrChange|sectPrChange|tblPrChange|trPrChange|tcPrChange|tblGridChange|tblPrExChange|cellIns|cellDel|cellMerge|numberingChange|customXmlInsRangeStart|customXmlDelRangeStart)[\s/>]/;
|
|
720
855
|
/**
|
|
@@ -2,7 +2,7 @@ import { Part } from './Part.mjs';
|
|
|
2
2
|
import { ContentTypes } from '../opc/ContentTypes.mjs';
|
|
3
3
|
import { Namespaces } from './Namespaces.mjs';
|
|
4
4
|
import { Docx4JException } from '../opc/exceptions.mjs';
|
|
5
|
-
import { parseXml, serializeXmlPart, encodeText, decodeXmlText } from '../xml/dom.mjs';
|
|
5
|
+
import { parseXml, serializeXmlPart, encodeText, decodeXmlText, assertXmlCharacters } from '../xml/dom.mjs';
|
|
6
6
|
/**
|
|
7
7
|
* An XML part the object model does not type, held as a DOM (docx4j DefaultXmlPart / XmlPart).
|
|
8
8
|
* The document is parsed on first `getDocument()`; a part whose document was never requested is
|
|
@@ -71,7 +71,7 @@ export class DefaultXmlPart extends Part {
|
|
|
71
71
|
}
|
|
72
72
|
async getBytes() {
|
|
73
73
|
if (this.document !== undefined)
|
|
74
|
-
return encodeText(serializeXmlPart(this.document));
|
|
74
|
+
return encodeText(assertXmlCharacters(serializeXmlPart(this.document), `Part ${this.partName}`));
|
|
75
75
|
if (this.bytes !== undefined)
|
|
76
76
|
return this.bytes;
|
|
77
77
|
const loaded = await this.loadSourceBytes();
|
package/dist/parts/Part.d.mts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { Relationship } from '@docx4j/generated-objects-ts/modules/org_docx4j_relationships';
|
|
2
|
+
import type { Normalisation } from '@docx4j/generated-objects-ts';
|
|
2
3
|
import { PartName } from '../opc/PartName.mjs';
|
|
3
4
|
import type { RelationshipsPart, AddPartBehaviour } from './RelationshipsPart.mjs';
|
|
4
5
|
import type { OpcPackage } from '../packages/OpcPackage.mjs';
|
|
6
|
+
/** What a save asks of a part's bytes (CR-015 D8): to be told of each value the objects facade's normaliser rewrote. */
|
|
7
|
+
export interface PartBytesOptions {
|
|
8
|
+
onNormalised?(normalisation: Normalisation): void;
|
|
9
|
+
}
|
|
5
10
|
/** Something that owns a relationships part: a part or the package (docx4j Base). */
|
|
6
11
|
export interface RelationshipSource {
|
|
7
12
|
readonly partName: PartName;
|
|
@@ -49,8 +54,11 @@ export declare abstract class Part implements RelationshipSource {
|
|
|
49
54
|
setPartShortcut(_part: Part, _relationshipType: string): boolean;
|
|
50
55
|
/** The bytes this part was loaded from, if it came from a container. Undefined for new parts. */
|
|
51
56
|
protected loadSourceBytes(): Promise<Uint8Array | undefined>;
|
|
52
|
-
/**
|
|
53
|
-
|
|
57
|
+
/**
|
|
58
|
+
* The bytes to write on save. Untouched parts come back from the source container unchanged. A part
|
|
59
|
+
* marshalled through the objects facade tells `options.onNormalised` of each value written in its normal form.
|
|
60
|
+
*/
|
|
61
|
+
abstract getBytes(options?: PartBytesOptions): Promise<Uint8Array>;
|
|
54
62
|
/** Whether the part carries content of its own (set or unmarshalled) rather than relying on the source container. */
|
|
55
63
|
abstract get isLoaded(): boolean;
|
|
56
64
|
}
|
package/dist/parts/XmlPart.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Jsonix } from '@docx4j/generated-objects-ts';
|
|
2
|
-
import { Part } from './Part.mjs';
|
|
2
|
+
import { Part, type PartBytesOptions } from './Part.mjs';
|
|
3
3
|
import { PartName } from '../opc/PartName.mjs';
|
|
4
4
|
import { type Bound } from '../model/content/binder.mjs';
|
|
5
5
|
import type { PartWarning } from '../opc/mce/preprocessor.mjs';
|
|
@@ -36,12 +36,6 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
36
36
|
rootName: RootName | undefined;
|
|
37
37
|
/** Runs over the DOM before unmarshalling; the package sets its MCE preprocessor here. */
|
|
38
38
|
preprocessor: DomPreprocessor | undefined;
|
|
39
|
-
/**
|
|
40
|
-
* The namespace declarations the source root element carried, prefix to URI, recorded when the
|
|
41
|
-
* part was parsed. They are what `mc:Ignorable` prefixes the object model does not bind are
|
|
42
|
-
* re-declared from on marshal; see `declareIgnorablePrefixes`.
|
|
43
|
-
*/
|
|
44
|
-
private sourceDeclarations;
|
|
45
39
|
private parseWarnings;
|
|
46
40
|
constructor(partName: PartName | string, contentType: string, relationshipType: string, rootName?: RootName);
|
|
47
41
|
/** True once contents were unmarshalled or set; the part is then re-marshalled on save. */
|
|
@@ -54,9 +48,10 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
54
48
|
*/
|
|
55
49
|
get isUntouched(): boolean;
|
|
56
50
|
/**
|
|
57
|
-
* What the
|
|
58
|
-
*
|
|
59
|
-
*
|
|
51
|
+
* What the last parse of this part reported: an mc:AlternateContent whose branches' text differs
|
|
52
|
+
* (`mce.branches_differ`, CR-010 phase 1), and each attribute value its type refuses that was read as
|
|
53
|
+
* Word 365 reads it (`value.kept.exact`, `value.kept.invalid`: CR-015 D8). Empty until the part is
|
|
54
|
+
* parsed, by `getContents()` or a private read, and again once its contents are set.
|
|
60
55
|
*/
|
|
61
56
|
get warnings(): readonly PartWarning[];
|
|
62
57
|
/** The unmarshalled contents (docx4j getJaxbElement()); throws when not yet unmarshalled. */
|
|
@@ -85,7 +80,7 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
85
80
|
/** The XML as it would be saved (docx4j XmlUtils.marshaltoString on the part). */
|
|
86
81
|
getXml(): Promise<string>;
|
|
87
82
|
/** Marshalled bytes when unmarshalled or set, else the source bytes untouched. */
|
|
88
|
-
getBytes(): Promise<Uint8Array>;
|
|
83
|
+
getBytes(options?: PartBytesOptions): Promise<Uint8Array>;
|
|
89
84
|
/**
|
|
90
85
|
* The objects an XPath selects in this part, through a DOM marshalled for the purpose
|
|
91
86
|
* (CR-006; docx4j `JaxbXmlPart.getJAXBNodesViaXPath`, which does it with a JAXB `Binder`).
|
|
@@ -104,8 +99,12 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
104
99
|
* (CR-002 section 31).
|
|
105
100
|
*/
|
|
106
101
|
selectObjects(xpath: string, options?: SelectOptions): Promise<Bound[]>;
|
|
107
|
-
/**
|
|
108
|
-
|
|
102
|
+
/**
|
|
103
|
+
* The root element as a DOM element (docx4j XmlUtils.marshaltoW3CDomDocument). Run properties are written in
|
|
104
|
+
* their normal form unless the package's `normaliseOnSave` (else the objects package's `setNormaliseOnSave`) is
|
|
105
|
+
* false (CR-015 D2, the objects facade's CR-013 phase C): the tree keeps what it read.
|
|
106
|
+
*/
|
|
107
|
+
marshalToNode(options?: PartBytesOptions): Promise<Element>;
|
|
109
108
|
/**
|
|
110
109
|
* Parses the part's bytes, and names the part when the XML is not well-formed. xmldom's error
|
|
111
110
|
* (Node) carries the line and column of the fault; a browser's says them in its text, which
|
|
@@ -124,21 +123,4 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
124
123
|
* locator).
|
|
125
124
|
*/
|
|
126
125
|
private unmarshal;
|
|
127
|
-
/** The source root element's namespace declarations, prefix to URI (`xmlns=` is the empty prefix). */
|
|
128
|
-
private recordDeclarations;
|
|
129
|
-
/**
|
|
130
|
-
* Every prefix the marshalled root's `mc:Ignorable` names must be declared on that root
|
|
131
|
-
* (ECMA-376 Part 3 10.1.2; Word and Excel treat an undeclared one as a corrupt part and offer
|
|
132
|
-
* to repair the file). The object model binds only the namespaces it has modules for, so an
|
|
133
|
-
* `mc:Ignorable` prefix whose content was dropped on unmarshal - `xr6`, `xr10` and `xr2` on
|
|
134
|
-
* Excel's `xl/workbook.xml`, for instance - loses its declaration: the runtime declares one
|
|
135
|
-
* prefix per entry of the objects package's table and the facade can only *remove* unused
|
|
136
|
-
* declarations, never add one it never made (CR-001 section 17).
|
|
137
|
-
*
|
|
138
|
-
* So the part re-declares them itself: from what the source root declared, else from the
|
|
139
|
-
* objects package's `NAMESPACE_PREFIXES`. A prefix neither knows is dropped from
|
|
140
|
-
* `mc:Ignorable` - an undeclared prefix is the one thing that must not be written - and warned
|
|
141
|
-
* about once.
|
|
142
|
-
*/
|
|
143
|
-
private declareIgnorablePrefixes;
|
|
144
126
|
}
|