@docx4j/core-ts 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +4 -0
- package/README.md +34 -3
- package/dist/html/convert.mjs +40 -15
- 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 +153 -19
- package/dist/model/content/Body.mjs +570 -131
- package/dist/model/content/Comment.d.mts +21 -3
- package/dist/model/content/Comment.mjs +202 -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 +82 -7
- package/dist/model/content/InlinePicture.mjs +221 -28
- package/dist/model/content/List.mjs +13 -1
- package/dist/model/content/Paragraph.d.mts +213 -14
- package/dist/model/content/Paragraph.mjs +936 -100
- package/dist/model/content/Range.d.mts +242 -11
- package/dist/model/content/Range.mjs +975 -119
- 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 +301 -16
- package/dist/model/content/TrackedChange.mjs +1284 -158
- package/dist/model/content/binder.d.mts +2 -1
- package/dist/model/content/binder.mjs +48 -1
- 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/relationships.d.mts +30 -0
- package/dist/model/content/relationships.mjs +133 -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 +212 -13
- package/dist/model/content/tree.mjs +356 -35
- 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 +9 -5
- package/dist/model/customxml/pictures.mjs +31 -13
- package/dist/model/customxml/xhtml.mjs +8 -2
- package/dist/model/fonts/families.generated.mjs +2 -2
- package/dist/model/fonts/registry.mjs +7 -1
- package/dist/model/fonts/substitutions.generated.mjs +2 -2
- package/dist/model/fonts/themes.generated.mjs +1 -1
- 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/listnumbering/definitions.mjs +18 -0
- package/dist/model/properties/PropertyResolver.d.mts +87 -7
- package/dist/model/properties/PropertyResolver.mjs +197 -17
- package/dist/model/properties/catalogue.d.mts +32 -4
- package/dist/model/properties/catalogue.mjs +115 -36
- package/dist/model/properties/log.d.mts +1 -1
- package/dist/model/properties/log.mjs +5 -5
- package/dist/model/properties/table.d.mts +16 -2
- package/dist/model/properties/table.mjs +17 -5
- 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/Load.d.mts +9 -2
- 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 +2 -2
- package/dist/opc/mce/preprocessor.d.mts +88 -7
- package/dist/opc/mce/preprocessor.mjs +144 -37
- package/dist/opc/mce/understood.d.mts +34 -0
- package/dist/opc/mce/understood.mjs +55 -3
- package/dist/packages/OpcPackage.d.mts +20 -0
- package/dist/packages/OpcPackage.mjs +16 -3
- package/dist/packages/WordprocessingMLPackage.d.mts +77 -7
- package/dist/packages/WordprocessingMLPackage.mjs +242 -11
- package/dist/parts/DefaultXmlPart.mjs +2 -2
- package/dist/parts/Part.d.mts +10 -2
- package/dist/parts/XmlPart.d.mts +35 -32
- package/dist/parts/XmlPart.mjs +107 -107
- 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
|
@@ -4,24 +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, trackedChangesOfStory } from '../model/content/Body.mjs';
|
|
14
|
+
import { pieceMatcher } from '../model/content/trackedChangeFilter.mjs';
|
|
13
15
|
import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
|
|
14
16
|
import { DefaultXPathEngine } from '../model/customxml/xpath.mjs';
|
|
15
17
|
import { ChangeTracker, highestAnnotationId } from '../model/content/tracking.mjs';
|
|
16
18
|
import { NumberingFacade } from '../model/content/List.mjs';
|
|
17
19
|
import { StylesFacade } from '../model/content/stylesFacade.mjs';
|
|
18
20
|
import { flushPendingCommentRemovals } from '../model/content/Comment.mjs';
|
|
21
|
+
import { GlossaryEntries } from '../model/content/placeholders.mjs';
|
|
19
22
|
import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
|
|
20
23
|
import { PropertyResolverNotCreatedException } from '../opc/exceptions.mjs';
|
|
24
|
+
import { flushPendingNoteRemovals, notesGoing } from '../model/content/TrackedChange.mjs';
|
|
25
|
+
import { flushPendingRelationshipRemovals } from '../model/content/relationships.mjs';
|
|
21
26
|
import { XmlPart } from '../parts/XmlPart.mjs';
|
|
22
27
|
// Registers the comment parts with the content API (CR-002 phase G); no cycle: the model half
|
|
23
28
|
// never imports a part, as packages/registry.mts does for the package classes.
|
|
24
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';
|
|
25
34
|
const MAIN_CONTENT_TYPES = [
|
|
26
35
|
ContentTypes.WORDPROCESSINGML_DOCUMENT,
|
|
27
36
|
ContentTypes.WORDPROCESSINGML_DOCUMENT_MACROENABLED,
|
|
@@ -88,6 +97,26 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
88
97
|
* the package is saved (check 32; `TrackedChange`). An extension.
|
|
89
98
|
*/
|
|
90
99
|
this.pendingCommentRemovals = new Set();
|
|
100
|
+
/**
|
|
101
|
+
* Footnotes and endnotes whose references went with content a tracked change took away (a rejected
|
|
102
|
+
* insertion, an accepted deletion, a row or cell, a move's other half): their entries go from the
|
|
103
|
+
* notes parts when the package is saved, each unless a reference to it still stands, as Word took
|
|
104
|
+
* them (CR-002 section 44; `TrackedChange`). An extension.
|
|
105
|
+
*/
|
|
106
|
+
this.pendingNoteRemovals = { footnote: new Set(), endnote: new Set() };
|
|
107
|
+
/**
|
|
108
|
+
* Relationships, by the name of their part, that a picture removed outright referenced (tracking off,
|
|
109
|
+
* or a picture taken back from its author's own insertion): each goes when the package is saved if
|
|
110
|
+
* nothing then references it, and its part with it when nothing else targets that (CR-002 section
|
|
111
|
+
* 47). Settled on save, not at once, so a picture cut and pasted back keeps its image. An extension.
|
|
112
|
+
*/
|
|
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();
|
|
91
120
|
/**
|
|
92
121
|
* The parts `seedAnnotationIds()` has read, with what it read: `true` for a part still holding its
|
|
93
122
|
* source, whose bytes cannot change, and otherwise the bytes that were set, which stay the same
|
|
@@ -220,6 +249,10 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
220
249
|
this.resolver = resolver;
|
|
221
250
|
this.resolverPending = undefined;
|
|
222
251
|
return resolver;
|
|
252
|
+
}, (e) => {
|
|
253
|
+
// not kept: a styles part put right (setXml) is read again on the next call
|
|
254
|
+
this.resolverPending = undefined;
|
|
255
|
+
throw e;
|
|
223
256
|
}));
|
|
224
257
|
return this.resolverPending;
|
|
225
258
|
}
|
|
@@ -393,12 +426,99 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
393
426
|
}
|
|
394
427
|
/**
|
|
395
428
|
* Office JS `document.getTrackedChanges()`: every tracked change in the main document part,
|
|
396
|
-
* in document order (headers and footers have their own `Body`
|
|
397
|
-
* 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.
|
|
398
431
|
*/
|
|
399
432
|
getTrackedChanges() {
|
|
400
433
|
return this.body.getTrackedChanges();
|
|
401
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
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Accepts every tracked change in every story: the main document, the footnotes, the endnotes and
|
|
457
|
+
* the comments, the headers and footers, and the text boxes in each. Word's
|
|
458
|
+
* `Document.AcceptAllRevisions` did that on docx4j's CR-043 probe (Word 16.0.20326), and left no
|
|
459
|
+
* revision in any story; `Body.acceptAll` resolves its own story only, as Office JS's `body` does
|
|
460
|
+
* (CR-002 section 49). A story part with no revision markup is not read, so it keeps its bytes.
|
|
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.
|
|
465
|
+
*/
|
|
466
|
+
async acceptAllRevisions(filter) {
|
|
467
|
+
return this.resolveEveryStory('accept', filter);
|
|
468
|
+
}
|
|
469
|
+
/** Rejects every tracked change in every story, as `acceptAllRevisions` accepts them (Word's `Document.RejectAllRevisions`). */
|
|
470
|
+
async rejectAllRevisions(filter) {
|
|
471
|
+
return this.resolveEveryStory('reject', filter);
|
|
472
|
+
}
|
|
473
|
+
async resolveEveryStory(what, filter) {
|
|
474
|
+
if (filter !== undefined)
|
|
475
|
+
pieceMatcher(filter); // a filter misread throws before anything is read or resolved
|
|
476
|
+
let count = 0;
|
|
477
|
+
for (const body of await this.revisedStories())
|
|
478
|
+
count += resolveStory(body, what, filter);
|
|
479
|
+
return count;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* The body of every story whose part holds revision markup, in docx4j's order (its CR-043
|
|
483
|
+
* `TrackedChanges.in`): the main document, each footnote, each endnote, each comment, then the
|
|
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.
|
|
486
|
+
*/
|
|
487
|
+
async revisedStories() {
|
|
488
|
+
var _a, _b;
|
|
489
|
+
const main = this.getMainDocumentPart();
|
|
490
|
+
const out = [];
|
|
491
|
+
if (await holdsRevisions(main))
|
|
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;
|
|
496
|
+
for (const [part, kind] of [[main.footnotesPart, 'footnote'], [main.endnotesPart, 'endnote']]) {
|
|
497
|
+
if (!part || !(await holdsRevisions(part)))
|
|
498
|
+
continue;
|
|
499
|
+
const contents = await part.getContents();
|
|
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;
|
|
503
|
+
out.push(new Body(part, note, `${kind}:${note.id}`, this));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const comments = main.commentsPart;
|
|
507
|
+
if (comments && (await holdsRevisions(comments))) {
|
|
508
|
+
for (const comment of (_b = (await comments.getContents()).comment) !== null && _b !== void 0 ? _b : []) {
|
|
509
|
+
if (this.pendingCommentRemovals.has(comment.id))
|
|
510
|
+
continue;
|
|
511
|
+
out.push(new Body(comments, comment, `comment:${comment.id}`, this));
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const revised = [];
|
|
515
|
+
for (const part of [...main.headerParts, ...main.footerParts])
|
|
516
|
+
if (await holdsRevisions(part))
|
|
517
|
+
revised.push(part);
|
|
518
|
+
for (const part of revised.length > 1 ? await inSectionOrder(main, revised) : revised)
|
|
519
|
+
out.push(await part.getBody());
|
|
520
|
+
return out;
|
|
521
|
+
}
|
|
402
522
|
/** The tracker every content-API mutation asks for; undefined while the mode is `Off`. */
|
|
403
523
|
get changeTracker() {
|
|
404
524
|
const mode = this.changeTrackingMode;
|
|
@@ -506,6 +626,13 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
506
626
|
target.author = { ...this.author };
|
|
507
627
|
for (const id of this.pendingCommentRemovals)
|
|
508
628
|
target.pendingCommentRemovals.add(id);
|
|
629
|
+
for (const id of this.pendingNoteRemovals.footnote)
|
|
630
|
+
target.pendingNoteRemovals.footnote.add(id);
|
|
631
|
+
for (const id of this.pendingNoteRemovals.endnote)
|
|
632
|
+
target.pendingNoteRemovals.endnote.add(id);
|
|
633
|
+
for (const [name, ids] of this.pendingRelationshipRemovals)
|
|
634
|
+
target.pendingRelationshipRemovals.set(name, new Set(ids));
|
|
635
|
+
this.glossaryEntries.copyTo(target.glossaryEntries);
|
|
509
636
|
target.trackedChangeDate = this.trackedChangeDate;
|
|
510
637
|
target.fonts.defaultTheme = this.fonts.defaultTheme;
|
|
511
638
|
target.xpathEngine = this.xpathEngine;
|
|
@@ -514,15 +641,35 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
514
641
|
var _a;
|
|
515
642
|
if (this.trackingPending)
|
|
516
643
|
await this.setChangeTrackingMode((_a = this.trackingMode) !== null && _a !== void 0 ? _a : 'Off');
|
|
517
|
-
|
|
518
|
-
|
|
644
|
+
// what removed content took with it, until nothing more goes: a removed note takes the comments
|
|
645
|
+
// anchored in it, and a removed note or comment the relationships its content held, which the last
|
|
646
|
+
// step settles (CR-002 section 50; docx4j's Removals.flush repeats the same way)
|
|
647
|
+
const notes = this.pendingNoteRemovals;
|
|
648
|
+
for (let round = 0; round < 10 && this.pendingCommentRemovals.size + notes.footnote.size + notes.endnote.size > 0; round++) {
|
|
649
|
+
if (this.pendingCommentRemovals.size > 0)
|
|
650
|
+
await flushPendingCommentRemovals(await this.getBody());
|
|
651
|
+
if (notes.footnote.size + notes.endnote.size > 0)
|
|
652
|
+
await flushPendingNoteRemovals(this.getMainDocumentPart(), notes, this);
|
|
653
|
+
}
|
|
654
|
+
if (this.pendingRelationshipRemovals.size > 0)
|
|
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
|
+
}
|
|
519
662
|
if (this.requiredStyles.size > 0) {
|
|
520
663
|
await this.styles.ensure([...this.requiredStyles]);
|
|
521
664
|
this.requiredStyles.clear();
|
|
522
665
|
}
|
|
523
666
|
return super.saveTo(sink);
|
|
524
667
|
}
|
|
525
|
-
/**
|
|
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
|
+
*/
|
|
526
673
|
async paragraphAt(address) {
|
|
527
674
|
for (const body of await this.bodies(address)) {
|
|
528
675
|
const p = body.paragraphAt(address);
|
|
@@ -531,28 +678,44 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
531
678
|
}
|
|
532
679
|
return undefined;
|
|
533
680
|
}
|
|
534
|
-
/**
|
|
535
|
-
|
|
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) {
|
|
536
687
|
var _a, _b, _c, _d;
|
|
537
688
|
const main = await this.getBody();
|
|
538
|
-
const
|
|
689
|
+
const ctx = context !== null && context !== void 0 ? context : await Texts.contextOf(this);
|
|
690
|
+
const out = { ...await main.outline(options, ctx), headers: [], footers: [] };
|
|
539
691
|
for (const part of this.getMainDocumentPart().headerParts) {
|
|
540
692
|
const body = await part.getBody();
|
|
541
|
-
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) });
|
|
542
694
|
}
|
|
543
695
|
for (const part of this.getMainDocumentPart().footerParts) {
|
|
544
696
|
const body = await part.getBody();
|
|
545
|
-
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) });
|
|
546
698
|
}
|
|
547
699
|
return out;
|
|
548
700
|
}
|
|
549
701
|
async bodies(address) {
|
|
702
|
+
var _a;
|
|
550
703
|
const main = this.getMainDocumentPart();
|
|
551
704
|
if (typeof address === 'string' && !address.startsWith('w14:')) {
|
|
552
705
|
const prefix = address.split('/')[0];
|
|
553
706
|
if (prefix === 'body')
|
|
554
707
|
return [await main.getBody()];
|
|
555
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
|
+
}
|
|
556
719
|
const parts = kind === 'header' ? main.headerParts : kind === 'footer' ? main.footerParts : [];
|
|
557
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; });
|
|
558
721
|
return part instanceof HeaderPart || part instanceof FooterPart ? [await part.getBody()] : [];
|
|
@@ -628,6 +791,74 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
628
791
|
return 'Word.Document';
|
|
629
792
|
}
|
|
630
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
|
+
}
|
|
853
|
+
/** Revision markup, by local name in any prefix: what a story part holds when it has a tracked change to resolve. */
|
|
854
|
+
const REVISION_MARKUP = /<(?:[\w.-]+:)?(?:ins|del|moveFrom|moveTo|rPrChange|pPrChange|sectPrChange|tblPrChange|trPrChange|tcPrChange|tblGridChange|tblPrExChange|cellIns|cellDel|cellMerge|numberingChange|customXmlInsRangeStart|customXmlDelRangeStart)[\s/>]/;
|
|
855
|
+
/**
|
|
856
|
+
* True when a story part may hold a tracked change: always once it is unmarshalled, else when its
|
|
857
|
+
* source has revision markup, read without unmarshalling it, so a part with none keeps its bytes.
|
|
858
|
+
*/
|
|
859
|
+
async function holdsRevisions(part) {
|
|
860
|
+
return part.isUnmarshalled || REVISION_MARKUP.test(await part.getXml());
|
|
861
|
+
}
|
|
631
862
|
/**
|
|
632
863
|
* `w:trackRevisions` is a flag, so a file cannot distinguish `TrackAll` from `TrackMineOnly`;
|
|
633
864
|
* a document that has it on reads as `TrackAll`, and either value writes it.
|
|
@@ -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,7 +1,8 @@
|
|
|
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
|
+
import type { PartWarning } from '../opc/mce/preprocessor.mjs';
|
|
5
6
|
/** What `selectObjects` needs: the engine to evaluate with, and any prefixes beyond the defaults. */
|
|
6
7
|
export interface SelectOptions {
|
|
7
8
|
/** The engine; `pkg.selectObjects` and `Body.select` pass the package's. It is readied on the snapshot. */
|
|
@@ -17,8 +18,11 @@ export interface RootName {
|
|
|
17
18
|
namespaceURI: string;
|
|
18
19
|
localPart: string;
|
|
19
20
|
}
|
|
20
|
-
/**
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* A hook run over the DOM before unmarshalling (the MCE preprocessor); set by the package on load.
|
|
23
|
+
* What it returns becomes the part's `warnings`.
|
|
24
|
+
*/
|
|
25
|
+
export type DomPreprocessor = (doc: Document, part?: XmlPart<unknown>) => void | readonly PartWarning[];
|
|
22
26
|
/**
|
|
23
27
|
* A part whose content is a typed element of the object model (docx4j JaxbXmlPart<E>). `T` is the
|
|
24
28
|
* root element's value type (`Document`, `Styles`, ...). Contents are unmarshalled on first
|
|
@@ -32,12 +36,7 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
32
36
|
rootName: RootName | undefined;
|
|
33
37
|
/** Runs over the DOM before unmarshalling; the package sets its MCE preprocessor here. */
|
|
34
38
|
preprocessor: DomPreprocessor | undefined;
|
|
35
|
-
|
|
36
|
-
* The namespace declarations the source root element carried, prefix to URI, recorded when the
|
|
37
|
-
* part was parsed. They are what `mc:Ignorable` prefixes the object model does not bind are
|
|
38
|
-
* re-declared from on marshal; see `declareIgnorablePrefixes`.
|
|
39
|
-
*/
|
|
40
|
-
private sourceDeclarations;
|
|
39
|
+
private parseWarnings;
|
|
41
40
|
constructor(partName: PartName | string, contentType: string, relationshipType: string, rootName?: RootName);
|
|
42
41
|
/** True once contents were unmarshalled or set; the part is then re-marshalled on save. */
|
|
43
42
|
get isUnmarshalled(): boolean;
|
|
@@ -48,6 +47,13 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
48
47
|
* which is what lets a reader remember it (CR-002 section 31).
|
|
49
48
|
*/
|
|
50
49
|
get isUntouched(): boolean;
|
|
50
|
+
/**
|
|
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.
|
|
55
|
+
*/
|
|
56
|
+
get warnings(): readonly PartWarning[];
|
|
51
57
|
/** The unmarshalled contents (docx4j getJaxbElement()); throws when not yet unmarshalled. */
|
|
52
58
|
get contents(): T;
|
|
53
59
|
/** The root element as [name, value]; undefined until unmarshalled. */
|
|
@@ -64,6 +70,7 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
64
70
|
* reads the styles and numbering parts of a document nobody has otherwise touched.
|
|
65
71
|
*/
|
|
66
72
|
readContents(): Promise<T>;
|
|
73
|
+
private preprocess;
|
|
67
74
|
/** Replaces the contents (docx4j setJaxbElement / setContents). The root name defaults to the part's. */
|
|
68
75
|
setContents(value: T, rootName?: RootName): void;
|
|
69
76
|
/** Replaces the contents with raw XML bytes; they are unmarshalled on the next getContents(). */
|
|
@@ -73,7 +80,7 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
73
80
|
/** The XML as it would be saved (docx4j XmlUtils.marshaltoString on the part). */
|
|
74
81
|
getXml(): Promise<string>;
|
|
75
82
|
/** Marshalled bytes when unmarshalled or set, else the source bytes untouched. */
|
|
76
|
-
getBytes(): Promise<Uint8Array>;
|
|
83
|
+
getBytes(options?: PartBytesOptions): Promise<Uint8Array>;
|
|
77
84
|
/**
|
|
78
85
|
* The objects an XPath selects in this part, through a DOM marshalled for the purpose
|
|
79
86
|
* (CR-006; docx4j `JaxbXmlPart.getJAXBNodesViaXPath`, which does it with a JAXB `Binder`).
|
|
@@ -92,32 +99,28 @@ export declare class XmlPart<T = unknown> extends Part {
|
|
|
92
99
|
* (CR-002 section 31).
|
|
93
100
|
*/
|
|
94
101
|
selectObjects(xpath: string, options?: SelectOptions): Promise<Bound[]>;
|
|
95
|
-
/**
|
|
96
|
-
|
|
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>;
|
|
108
|
+
/**
|
|
109
|
+
* Parses the part's bytes, and names the part when the XML is not well-formed. xmldom's error
|
|
110
|
+
* (Node) carries the line and column of the fault; a browser's says them in its text, which
|
|
111
|
+
* `parseXml` passes on.
|
|
112
|
+
*/
|
|
113
|
+
private parse;
|
|
97
114
|
/**
|
|
98
115
|
* Unmarshals, and names the part when the runtime refuses. The runtime's own message says what is
|
|
99
116
|
* wrong and, since `@docx4j/jsonix` 3.4.0, where - `w:sz/@w:val (line 12): Argument [NaN] must be
|
|
100
117
|
* an integer` - but not which part it was reading, which is the first thing a person editing a
|
|
101
|
-
* part's XML needs (CR-002 section 27)
|
|
102
|
-
*
|
|
103
|
-
*
|
|
118
|
+
* part's XML needs (CR-002 section 27), nor the value it refused. The message names the part, and
|
|
119
|
+
* for an attribute gives the value as written and the column too:
|
|
120
|
+
* `/word/styles.xml: w:sz/@w:val="big" (line 12, column 9): Argument [NaN] must be an integer, ...`.
|
|
121
|
+
* The location it found is lifted onto the exception so a caller does not parse the message; `line`
|
|
122
|
+
* is undefined where the parser supplies no position, which is every browser (only xmldom carries a
|
|
123
|
+
* locator).
|
|
104
124
|
*/
|
|
105
125
|
private unmarshal;
|
|
106
|
-
/** The source root element's namespace declarations, prefix to URI (`xmlns=` is the empty prefix). */
|
|
107
|
-
private recordDeclarations;
|
|
108
|
-
/**
|
|
109
|
-
* Every prefix the marshalled root's `mc:Ignorable` names must be declared on that root
|
|
110
|
-
* (ECMA-376 Part 3 10.1.2; Word and Excel treat an undeclared one as a corrupt part and offer
|
|
111
|
-
* to repair the file). The object model binds only the namespaces it has modules for, so an
|
|
112
|
-
* `mc:Ignorable` prefix whose content was dropped on unmarshal - `xr6`, `xr10` and `xr2` on
|
|
113
|
-
* Excel's `xl/workbook.xml`, for instance - loses its declaration: the runtime declares one
|
|
114
|
-
* prefix per entry of the objects package's table and the facade can only *remove* unused
|
|
115
|
-
* declarations, never add one it never made (CR-001 section 17).
|
|
116
|
-
*
|
|
117
|
-
* So the part re-declares them itself: from what the source root declared, else from the
|
|
118
|
-
* objects package's `NAMESPACE_PREFIXES`. A prefix neither knows is dropped from
|
|
119
|
-
* `mc:Ignorable` - an undeclared prefix is the one thing that must not be written - and warned
|
|
120
|
-
* about once.
|
|
121
|
-
*/
|
|
122
|
-
private declareIgnorablePrefixes;
|
|
123
126
|
}
|