@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
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
|
+
import type * as w15 from '@docx4j/generated-objects-ts/modules/org_docx4j_w15';
|
|
3
|
+
import type * as core from '@docx4j/generated-objects-ts/modules/org_docx4j_docProps_core';
|
|
4
|
+
import type * as extended from '@docx4j/generated-objects-ts/modules/org_docx4j_docProps_extended';
|
|
5
|
+
import type * as custom from '@docx4j/generated-objects-ts/modules/org_docx4j_docProps_custom';
|
|
6
|
+
import type { Part } from '../../parts/Part.mjs';
|
|
7
|
+
import type { XmlPart } from '../../parts/XmlPart.mjs';
|
|
8
|
+
import type { PropertyResolver } from '../properties/PropertyResolver.mjs';
|
|
9
|
+
import type { NumberingDefinitions } from '../listnumbering/definitions.mjs';
|
|
10
|
+
import type { NumberingPartLike } from '../listnumbering/Emulator.mjs';
|
|
11
|
+
import { NumberingStates } from '../listnumbering/state.mjs';
|
|
12
|
+
import { Body } from '../content/Body.mjs';
|
|
13
|
+
import { ResolvedView } from '../content/ResolvedView.mjs';
|
|
14
|
+
import type { XPathEngine } from '../customxml/xpath.mjs';
|
|
15
|
+
import type { NoteType } from './TextResult.mjs';
|
|
16
|
+
/** As much of a `WordprocessingMLPackage` as a reading uses, so that this module does not import the package. */
|
|
17
|
+
export interface TextPackage {
|
|
18
|
+
getMainDocumentPart(): MainLike;
|
|
19
|
+
getPropertyResolver(): Promise<PropertyResolver>;
|
|
20
|
+
getNumberingEmulator(): Promise<unknown>;
|
|
21
|
+
readonly propertyResolverOrUndefined?: PropertyResolver;
|
|
22
|
+
readonly docPropsCorePart?: XmlPart<core.CoreProperties>;
|
|
23
|
+
readonly docPropsExtendedPart?: XmlPart<extended.Properties>;
|
|
24
|
+
readonly docPropsCustomPart?: XmlPart<custom.Properties>;
|
|
25
|
+
readonly customXmlDataStorageParts: ReadonlyMap<string, {
|
|
26
|
+
parseDocument(): Promise<Document>;
|
|
27
|
+
}>;
|
|
28
|
+
xpathEngine: XPathEngine;
|
|
29
|
+
}
|
|
30
|
+
/** As much of a `MainDocumentPart` as a reading uses. */
|
|
31
|
+
export interface MainLike extends XmlPart<wml.Document> {
|
|
32
|
+
readonly styleDefinitionsPart?: Part;
|
|
33
|
+
readonly numberingDefinitionsPart?: XmlPart<wml.Numbering> & NumberingPartLike & {
|
|
34
|
+
getDefinitions(): Promise<NumberingDefinitions>;
|
|
35
|
+
};
|
|
36
|
+
readonly documentSettingsPart?: XmlPart<wml.CTSettings>;
|
|
37
|
+
readonly footnotesPart?: XmlPart<wml.CTFootnotes>;
|
|
38
|
+
readonly endnotesPart?: XmlPart<wml.CTEndnotes>;
|
|
39
|
+
readonly commentsPart?: XmlPart<wml.Comments>;
|
|
40
|
+
readonly commentsExtendedPart?: XmlPart<w15.CTCommentsEx>;
|
|
41
|
+
readonly glossaryDocumentPart?: XmlPart<wml.GlossaryDocument>;
|
|
42
|
+
readonly headerParts: XmlPart<wml.Hdr>[];
|
|
43
|
+
readonly footerParts: XmlPart<wml.Ftr>[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The trees one reading walks, each read **privately** where its part was not unmarshalled
|
|
47
|
+
* (`XmlPart.readContents`), so that reading a document costs no part its byte-for-byte round trip
|
|
48
|
+
* (REQ-204), and the live tree where it was. Every story is read, so that the views' plan covers them
|
|
49
|
+
* all ("the view is the package's"); the glossary only when it is included.
|
|
50
|
+
*/
|
|
51
|
+
export declare class PackageTrees {
|
|
52
|
+
readonly pkg: TextPackage | undefined;
|
|
53
|
+
main: {
|
|
54
|
+
part: MainLike;
|
|
55
|
+
document: wml.Document;
|
|
56
|
+
} | undefined;
|
|
57
|
+
footnotes: {
|
|
58
|
+
part: Part;
|
|
59
|
+
tree: wml.CTFootnotes;
|
|
60
|
+
} | undefined;
|
|
61
|
+
endnotes: {
|
|
62
|
+
part: Part;
|
|
63
|
+
tree: wml.CTEndnotes;
|
|
64
|
+
} | undefined;
|
|
65
|
+
comments: {
|
|
66
|
+
part: Part;
|
|
67
|
+
tree: wml.Comments;
|
|
68
|
+
} | undefined;
|
|
69
|
+
commentsExtended: w15.CTCommentsEx | undefined;
|
|
70
|
+
/** Each header and footer part related from the main document part, with its content. */
|
|
71
|
+
readonly headersAndFooters: Map<Part, wml.Ftr | wml.Hdr>;
|
|
72
|
+
glossary: {
|
|
73
|
+
part: Part;
|
|
74
|
+
tree: wml.GlossaryDocument;
|
|
75
|
+
} | undefined;
|
|
76
|
+
settings: wml.CTSettings | undefined;
|
|
77
|
+
/** The document properties under `core`, `app` and `custom` (REQ-515). */
|
|
78
|
+
properties: Record<string, unknown> | undefined;
|
|
79
|
+
/** The resolver, where the package has a styles part (docx4j makes none without one). */
|
|
80
|
+
resolver: PropertyResolver | undefined;
|
|
81
|
+
numberingPart: NumberingPartLike | undefined;
|
|
82
|
+
numbering: NumberingDefinitions | undefined;
|
|
83
|
+
/** Each binding store's DOM, by its upper-cased item id. */
|
|
84
|
+
private readonly stores;
|
|
85
|
+
private xpath;
|
|
86
|
+
private anchored;
|
|
87
|
+
private constructor();
|
|
88
|
+
/** The trees of a package. */
|
|
89
|
+
static read(pkg: TextPackage): Promise<PackageTrees>;
|
|
90
|
+
/** Trees with no package: content read as it stands (docx4j's planless `Texts.of(content)`). */
|
|
91
|
+
static none(): PackageTrees;
|
|
92
|
+
/** The glossary document, read when `include: glossary` first asks for it. */
|
|
93
|
+
readGlossary(): Promise<void>;
|
|
94
|
+
private readStores;
|
|
95
|
+
/**
|
|
96
|
+
* A data binding's value, docx4j `BoundValues`: the binding's XPath, with its own prefix mappings,
|
|
97
|
+
* against the custom XML part its `w:storeItemID` names (or the core or application properties); the
|
|
98
|
+
* string value of the first node selected. Undefined where the binding does not resolve.
|
|
99
|
+
*/
|
|
100
|
+
boundValue(binding: wml.CTDataBinding): string | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* The ids of the comments anchored in the document: a `w:commentReference` or a `w:commentRangeStart`
|
|
103
|
+
* in the main document, a header or footer, or a note, in any branch.
|
|
104
|
+
*/
|
|
105
|
+
anchoredComments(): Set<string>;
|
|
106
|
+
/** Every story's body, over these trees, for the views' plan: the main document, each note and comment, the headers and footers. */
|
|
107
|
+
stories(): Body[];
|
|
108
|
+
/** The part whose tree holds an object, by its `PARENT`s, or undefined. */
|
|
109
|
+
partOf(object: unknown): Part | undefined;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* What a story needs from the rest of the document (CR-012 section 4.4): the note references' order, for
|
|
113
|
+
* `[n]`; the numbering states per story, for list labels and `value`; the bookmarks, for `fields: update`;
|
|
114
|
+
* and, made once, each view's plan of what Accept All or Reject All would leave. A call given a context
|
|
115
|
+
* uses it and adds to it, so that the editor's calls over one part at a time, in the order the
|
|
116
|
+
* specification reads the stories (REQ-501), number the notes and count the lists as one reading of the
|
|
117
|
+
* whole package does; `TextResult.concat` assembles their results.
|
|
118
|
+
*
|
|
119
|
+
* A context is a snapshot of the package as it was read (`Texts.contextOf`): after the package changes,
|
|
120
|
+
* make another. It is for one reading, in one view: the calls under it take the same options, as the parts
|
|
121
|
+
* of one `Texts.of(pkg)` would.
|
|
122
|
+
*/
|
|
123
|
+
export declare class TextContext {
|
|
124
|
+
readonly trees: PackageTrees;
|
|
125
|
+
/** Notes referenced, in reference order: id to number, 0 for a note with a custom mark. */
|
|
126
|
+
readonly footnotes: Map<string, number>;
|
|
127
|
+
readonly endnotes: Map<string, number>;
|
|
128
|
+
private footnoteCount;
|
|
129
|
+
private endnoteCount;
|
|
130
|
+
/** The numbering states, one per story (`Emulator`). */
|
|
131
|
+
readonly numberingStates: NumberingStates;
|
|
132
|
+
/** The `w:lastRenderedPageBreak`s of the main story so far (REQ-708). */
|
|
133
|
+
pageMarkers: number;
|
|
134
|
+
/** The bookmarks' text, by lower-cased name (REQ-506's REF, CR-012 phase 5a). */
|
|
135
|
+
readonly bookmarks: Map<string, string>;
|
|
136
|
+
/** Whether the main story has been read under this context, which numbers the notes. */
|
|
137
|
+
mainRead: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* The view the context's first call read in: its note numbers and counts are that view's, so a call in
|
|
140
|
+
* another view is refused (`Texts.of`).
|
|
141
|
+
*/
|
|
142
|
+
view: 'accepted' | 'original' | 'markup' | undefined;
|
|
143
|
+
private readonly plans;
|
|
144
|
+
/** Per container, then per options, what the blocks begin inside (`Extractor.fieldsAtBlocks`), made once; shared with siblings. */
|
|
145
|
+
private starts;
|
|
146
|
+
constructor(trees: PackageTrees);
|
|
147
|
+
/** What `make` gives for a container's blocks under options keyed `key`, made once in this context (CR-012 section 17.13). */
|
|
148
|
+
blockStarts<T>(container: object, key: string, make: () => T): T;
|
|
149
|
+
/** The package this context reads. */
|
|
150
|
+
get pkg(): TextPackage | undefined;
|
|
151
|
+
/** A note's number, given at its first reference: in reference order, footnotes and endnotes apart, 0 for a custom mark (REQ-503). */
|
|
152
|
+
noteNumber(type: NoteType, id: string, customMark: boolean): number;
|
|
153
|
+
/** The plan of Accept All (`accepted`) or Reject All, over every story, made once. */
|
|
154
|
+
plan(accepted: boolean): ResolvedView;
|
|
155
|
+
/** A context over the same trees and plans, its own notes and states: for a reading whose blocks are not the result's. */
|
|
156
|
+
sibling(): TextContext;
|
|
157
|
+
/** Adopts the note numbers another context gave (`sibling`'s, for a notes part read before its story). */
|
|
158
|
+
adoptNotes(other: TextContext): void;
|
|
159
|
+
}
|
|
160
|
+
/** An XML calendar as its lexical form. */
|
|
161
|
+
export declare function calendarText(date: unknown): string | undefined;
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { NumberingStates } from '../listnumbering/state.mjs';
|
|
2
|
+
import { Body } from '../content/Body.mjs';
|
|
3
|
+
import { ResolvedView } from '../content/ResolvedView.mjs';
|
|
4
|
+
import { parsePrefixMappings } from '../customxml/xpath.mjs';
|
|
5
|
+
import { parseXml, decodeXmlText } from '../../xml/dom.mjs';
|
|
6
|
+
import { walk } from '@docx4j/generated-objects-ts/builders/wml';
|
|
7
|
+
/** The `w:storeItemID`s of the core and application properties, which a control can be bound to (docx4j `BindingHandler`). */
|
|
8
|
+
const CORE_PROPERTIES_STOREITEMID = '{6C3C8BC8-F283-45AE-878A-BAB7291924A1}';
|
|
9
|
+
const EXTENDED_PROPERTIES_STOREITEMID = '{6668398D-A668-4E3E-A5EB-62B293D839F1}';
|
|
10
|
+
/** `readContents()`, undefined for a part that cannot be read. */
|
|
11
|
+
async function readQuietly(part) {
|
|
12
|
+
if (!part)
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
return await part.readContents();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The trees one reading walks, each read **privately** where its part was not unmarshalled
|
|
23
|
+
* (`XmlPart.readContents`), so that reading a document costs no part its byte-for-byte round trip
|
|
24
|
+
* (REQ-204), and the live tree where it was. Every story is read, so that the views' plan covers them
|
|
25
|
+
* all ("the view is the package's"); the glossary only when it is included.
|
|
26
|
+
*/
|
|
27
|
+
export class PackageTrees {
|
|
28
|
+
constructor(pkg) {
|
|
29
|
+
this.pkg = pkg;
|
|
30
|
+
/** Each header and footer part related from the main document part, with its content. */
|
|
31
|
+
this.headersAndFooters = new Map();
|
|
32
|
+
/** Each binding store's DOM, by its upper-cased item id. */
|
|
33
|
+
this.stores = new Map();
|
|
34
|
+
}
|
|
35
|
+
/** The trees of a package. */
|
|
36
|
+
static async read(pkg) {
|
|
37
|
+
const trees = new PackageTrees(pkg);
|
|
38
|
+
let main;
|
|
39
|
+
try {
|
|
40
|
+
main = pkg.getMainDocumentPart();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
main = undefined;
|
|
44
|
+
}
|
|
45
|
+
if (main) {
|
|
46
|
+
trees.main = { part: main, document: await main.readContents() };
|
|
47
|
+
if (main.styleDefinitionsPart) {
|
|
48
|
+
try {
|
|
49
|
+
trees.resolver = await pkg.getPropertyResolver();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
trees.resolver = undefined; // hidden text and indents not resolved through styles
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const numbering = main.numberingDefinitionsPart;
|
|
56
|
+
if (numbering) {
|
|
57
|
+
try {
|
|
58
|
+
await pkg.getNumberingEmulator();
|
|
59
|
+
trees.numbering = await numbering.getDefinitions();
|
|
60
|
+
trees.numberingPart = numbering;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
trees.numberingPart = undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
trees.settings = await readQuietly(main.documentSettingsPart);
|
|
67
|
+
const footnotes = await readQuietly(main.footnotesPart);
|
|
68
|
+
if (footnotes && main.footnotesPart)
|
|
69
|
+
trees.footnotes = { part: main.footnotesPart, tree: footnotes };
|
|
70
|
+
const endnotes = await readQuietly(main.endnotesPart);
|
|
71
|
+
if (endnotes && main.endnotesPart)
|
|
72
|
+
trees.endnotes = { part: main.endnotesPart, tree: endnotes };
|
|
73
|
+
const comments = await readQuietly(main.commentsPart);
|
|
74
|
+
if (comments && main.commentsPart)
|
|
75
|
+
trees.comments = { part: main.commentsPart, tree: comments };
|
|
76
|
+
trees.commentsExtended = await readQuietly(main.commentsExtendedPart);
|
|
77
|
+
for (const part of [...main.headerParts, ...main.footerParts]) {
|
|
78
|
+
const content = await readQuietly(part);
|
|
79
|
+
if (content)
|
|
80
|
+
trees.headersAndFooters.set(part, content);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
trees.properties = await properties(pkg);
|
|
84
|
+
await trees.readStores(pkg);
|
|
85
|
+
return trees;
|
|
86
|
+
}
|
|
87
|
+
/** Trees with no package: content read as it stands (docx4j's planless `Texts.of(content)`). */
|
|
88
|
+
static none() {
|
|
89
|
+
return new PackageTrees(undefined);
|
|
90
|
+
}
|
|
91
|
+
/** The glossary document, read when `include: glossary` first asks for it. */
|
|
92
|
+
async readGlossary() {
|
|
93
|
+
var _a;
|
|
94
|
+
const part = (_a = this.main) === null || _a === void 0 ? void 0 : _a.part.glossaryDocumentPart;
|
|
95
|
+
if (this.glossary || !part)
|
|
96
|
+
return;
|
|
97
|
+
const tree = await readQuietly(part);
|
|
98
|
+
if (tree)
|
|
99
|
+
this.glossary = { part, tree };
|
|
100
|
+
}
|
|
101
|
+
// --- bound values (REQ-509) ---------------------------------------------------------------------
|
|
102
|
+
async readStores(pkg) {
|
|
103
|
+
let context;
|
|
104
|
+
for (const [id, part] of pkg.customXmlDataStorageParts) {
|
|
105
|
+
try {
|
|
106
|
+
const doc = await part.parseDocument();
|
|
107
|
+
this.stores.set(id.toUpperCase(), doc);
|
|
108
|
+
context !== null && context !== void 0 ? context : (context = doc);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
this.stores.set(id.toUpperCase(), undefined);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const [id, part] of [[CORE_PROPERTIES_STOREITEMID, pkg.docPropsCorePart], [EXTENDED_PROPERTIES_STOREITEMID, pkg.docPropsExtendedPart]]) {
|
|
115
|
+
if (!part)
|
|
116
|
+
continue;
|
|
117
|
+
try {
|
|
118
|
+
// the part's XML as it would be saved, parsed apart from it: the part keeps its round trip
|
|
119
|
+
const doc = parseXml(decodeXmlText(await part.getBytes()));
|
|
120
|
+
this.stores.set(id, doc);
|
|
121
|
+
context !== null && context !== void 0 ? context : (context = doc);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
this.stores.set(id, undefined);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (context === undefined)
|
|
128
|
+
return;
|
|
129
|
+
try {
|
|
130
|
+
await pkg.xpathEngine.ready(context);
|
|
131
|
+
this.xpath = pkg.xpathEngine;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
this.xpath = undefined; // no XPath here: every control's surface is read
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* A data binding's value, docx4j `BoundValues`: the binding's XPath, with its own prefix mappings,
|
|
139
|
+
* against the custom XML part its `w:storeItemID` names (or the core or application properties); the
|
|
140
|
+
* string value of the first node selected. Undefined where the binding does not resolve.
|
|
141
|
+
*/
|
|
142
|
+
boundValue(binding) {
|
|
143
|
+
var _a;
|
|
144
|
+
if (!binding.xpath || !binding.storeItemID || !this.xpath)
|
|
145
|
+
return undefined;
|
|
146
|
+
const doc = this.stores.get(binding.storeItemID.toUpperCase());
|
|
147
|
+
if (!doc)
|
|
148
|
+
return undefined;
|
|
149
|
+
try {
|
|
150
|
+
const mappings = parsePrefixMappings(binding.prefixMappings);
|
|
151
|
+
delete mappings[''];
|
|
152
|
+
const nodes = this.xpath.select(binding.xpath, doc, mappings);
|
|
153
|
+
const node = nodes[0];
|
|
154
|
+
if (!node)
|
|
155
|
+
return undefined;
|
|
156
|
+
return node.nodeType === 2 ? node.value : ((_a = node.textContent) !== null && _a !== void 0 ? _a : '');
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// --- the comments anchored in the document (REQ-504) -----------------------------------------------
|
|
163
|
+
/**
|
|
164
|
+
* The ids of the comments anchored in the document: a `w:commentReference` or a `w:commentRangeStart`
|
|
165
|
+
* in the main document, a header or footer, or a note, in any branch.
|
|
166
|
+
*/
|
|
167
|
+
anchoredComments() {
|
|
168
|
+
var _a, _b, _c;
|
|
169
|
+
if (this.anchored)
|
|
170
|
+
return this.anchored;
|
|
171
|
+
const ids = new Set();
|
|
172
|
+
const roots = [(_a = this.main) === null || _a === void 0 ? void 0 : _a.document, ...this.headersAndFooters.values(), (_b = this.footnotes) === null || _b === void 0 ? void 0 : _b.tree, (_c = this.endnotes) === null || _c === void 0 ? void 0 : _c.tree];
|
|
173
|
+
for (const root of roots) {
|
|
174
|
+
if (root === undefined)
|
|
175
|
+
continue;
|
|
176
|
+
walk(root, (v) => {
|
|
177
|
+
const tn = v.TYPE_NAME;
|
|
178
|
+
if (tn === 'org_docx4j_wml.R.CommentReference' || tn === 'org_docx4j_wml.CommentRangeStart') {
|
|
179
|
+
const id = v.id;
|
|
180
|
+
if (id !== undefined && id !== null)
|
|
181
|
+
ids.add(String(id));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return (this.anchored = ids);
|
|
186
|
+
}
|
|
187
|
+
/** Every story's body, over these trees, for the views' plan: the main document, each note and comment, the headers and footers. */
|
|
188
|
+
stories() {
|
|
189
|
+
var _a, _b, _c, _d;
|
|
190
|
+
const pkg = this.pkg;
|
|
191
|
+
const out = [];
|
|
192
|
+
if ((_a = this.main) === null || _a === void 0 ? void 0 : _a.document.body)
|
|
193
|
+
out.push(new Body(this.main.part, this.main.document.body, 'body', pkg));
|
|
194
|
+
for (const [holder, kind] of [[this.footnotes, 'footnote'], [this.endnotes, 'endnote']]) {
|
|
195
|
+
if (!holder)
|
|
196
|
+
continue;
|
|
197
|
+
const notes = (_b = (kind === 'footnote' ? holder.tree.footnote : holder.tree.endnote)) !== null && _b !== void 0 ? _b : [];
|
|
198
|
+
for (const note of notes)
|
|
199
|
+
out.push(new Body(holder.part, note, `${kind}:${note.id}`, pkg));
|
|
200
|
+
}
|
|
201
|
+
for (const comment of (_d = (_c = this.comments) === null || _c === void 0 ? void 0 : _c.tree.comment) !== null && _d !== void 0 ? _d : []) {
|
|
202
|
+
out.push(new Body(this.comments.part, comment, `comment:${comment.id}`, pkg));
|
|
203
|
+
}
|
|
204
|
+
for (const [part, content] of this.headersAndFooters)
|
|
205
|
+
out.push(new Body(part, content, 'story', pkg));
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
/** The part whose tree holds an object, by its `PARENT`s, or undefined. */
|
|
209
|
+
partOf(object) {
|
|
210
|
+
let root = object;
|
|
211
|
+
for (let o = object; o; o = o.PARENT)
|
|
212
|
+
root = o;
|
|
213
|
+
if (this.main && (root === this.main.document || root === this.main.document.body))
|
|
214
|
+
return this.main.part;
|
|
215
|
+
for (const [part, content] of this.headersAndFooters)
|
|
216
|
+
if (root === content)
|
|
217
|
+
return part;
|
|
218
|
+
if (this.footnotes && root === this.footnotes.tree)
|
|
219
|
+
return this.footnotes.part;
|
|
220
|
+
if (this.endnotes && root === this.endnotes.tree)
|
|
221
|
+
return this.endnotes.part;
|
|
222
|
+
if (this.comments && root === this.comments.tree)
|
|
223
|
+
return this.comments.part;
|
|
224
|
+
if (this.glossary && root === this.glossary.tree)
|
|
225
|
+
return this.glossary.part;
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* What a story needs from the rest of the document (CR-012 section 4.4): the note references' order, for
|
|
231
|
+
* `[n]`; the numbering states per story, for list labels and `value`; the bookmarks, for `fields: update`;
|
|
232
|
+
* and, made once, each view's plan of what Accept All or Reject All would leave. A call given a context
|
|
233
|
+
* uses it and adds to it, so that the editor's calls over one part at a time, in the order the
|
|
234
|
+
* specification reads the stories (REQ-501), number the notes and count the lists as one reading of the
|
|
235
|
+
* whole package does; `TextResult.concat` assembles their results.
|
|
236
|
+
*
|
|
237
|
+
* A context is a snapshot of the package as it was read (`Texts.contextOf`): after the package changes,
|
|
238
|
+
* make another. It is for one reading, in one view: the calls under it take the same options, as the parts
|
|
239
|
+
* of one `Texts.of(pkg)` would.
|
|
240
|
+
*/
|
|
241
|
+
export class TextContext {
|
|
242
|
+
constructor(trees) {
|
|
243
|
+
this.trees = trees;
|
|
244
|
+
/** Notes referenced, in reference order: id to number, 0 for a note with a custom mark. */
|
|
245
|
+
this.footnotes = new Map();
|
|
246
|
+
this.endnotes = new Map();
|
|
247
|
+
this.footnoteCount = 0;
|
|
248
|
+
this.endnoteCount = 0;
|
|
249
|
+
/** The numbering states, one per story (`Emulator`). */
|
|
250
|
+
this.numberingStates = new NumberingStates();
|
|
251
|
+
/** The `w:lastRenderedPageBreak`s of the main story so far (REQ-708). */
|
|
252
|
+
this.pageMarkers = 0;
|
|
253
|
+
/** The bookmarks' text, by lower-cased name (REQ-506's REF, CR-012 phase 5a). */
|
|
254
|
+
this.bookmarks = new Map();
|
|
255
|
+
/** Whether the main story has been read under this context, which numbers the notes. */
|
|
256
|
+
this.mainRead = false;
|
|
257
|
+
this.plans = new Map();
|
|
258
|
+
/** Per container, then per options, what the blocks begin inside (`Extractor.fieldsAtBlocks`), made once; shared with siblings. */
|
|
259
|
+
this.starts = new WeakMap();
|
|
260
|
+
}
|
|
261
|
+
/** What `make` gives for a container's blocks under options keyed `key`, made once in this context (CR-012 section 17.13). */
|
|
262
|
+
blockStarts(container, key, make) {
|
|
263
|
+
let byKey = this.starts.get(container);
|
|
264
|
+
if (!byKey)
|
|
265
|
+
this.starts.set(container, byKey = new Map());
|
|
266
|
+
if (!byKey.has(key))
|
|
267
|
+
byKey.set(key, make());
|
|
268
|
+
return byKey.get(key);
|
|
269
|
+
}
|
|
270
|
+
/** The package this context reads. */
|
|
271
|
+
get pkg() {
|
|
272
|
+
return this.trees.pkg;
|
|
273
|
+
}
|
|
274
|
+
/** A note's number, given at its first reference: in reference order, footnotes and endnotes apart, 0 for a custom mark (REQ-503). */
|
|
275
|
+
noteNumber(type, id, customMark) {
|
|
276
|
+
const numbers = type === 'footnote' ? this.footnotes : this.endnotes;
|
|
277
|
+
let n = numbers.get(id);
|
|
278
|
+
if (n === undefined) {
|
|
279
|
+
n = customMark ? 0 : type === 'footnote' ? ++this.footnoteCount : ++this.endnoteCount;
|
|
280
|
+
numbers.set(id, n);
|
|
281
|
+
}
|
|
282
|
+
return n;
|
|
283
|
+
}
|
|
284
|
+
/** The plan of Accept All (`accepted`) or Reject All, over every story, made once. */
|
|
285
|
+
plan(accepted) {
|
|
286
|
+
let plan = this.plans.get(accepted);
|
|
287
|
+
if (!plan) {
|
|
288
|
+
const stories = this.trees.stories();
|
|
289
|
+
plan = accepted ? ResolvedView.accepted(stories) : ResolvedView.original(stories);
|
|
290
|
+
this.plans.set(accepted, plan);
|
|
291
|
+
}
|
|
292
|
+
return plan;
|
|
293
|
+
}
|
|
294
|
+
/** A context over the same trees and plans, its own notes and states: for a reading whose blocks are not the result's. */
|
|
295
|
+
sibling() {
|
|
296
|
+
const c = new TextContext(this.trees);
|
|
297
|
+
for (const [k, v] of this.plans)
|
|
298
|
+
c.plans.set(k, v);
|
|
299
|
+
c.starts = this.starts;
|
|
300
|
+
return c;
|
|
301
|
+
}
|
|
302
|
+
/** Adopts the note numbers another context gave (`sibling`'s, for a notes part read before its story). */
|
|
303
|
+
adoptNotes(other) {
|
|
304
|
+
for (const [id, n] of other.footnotes)
|
|
305
|
+
if (!this.footnotes.has(id))
|
|
306
|
+
this.footnotes.set(id, n);
|
|
307
|
+
for (const [id, n] of other.endnotes)
|
|
308
|
+
if (!this.endnotes.has(id))
|
|
309
|
+
this.endnotes.set(id, n);
|
|
310
|
+
this.footnoteCount = Math.max(this.footnoteCount, other.footnoteCount);
|
|
311
|
+
this.endnoteCount = Math.max(this.endnoteCount, other.endnoteCount);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// --- the document properties (REQ-515; docx4j `Metadata`) --------------------------------------------
|
|
315
|
+
/** The properties under `core`, `app` and `custom`, each where the package has that part. */
|
|
316
|
+
async function properties(pkg) {
|
|
317
|
+
const out = {};
|
|
318
|
+
const c = await readQuietly(pkg.docPropsCorePart);
|
|
319
|
+
if (c)
|
|
320
|
+
out.core = coreProperties(c);
|
|
321
|
+
const a = await readQuietly(pkg.docPropsExtendedPart);
|
|
322
|
+
if (a)
|
|
323
|
+
out.app = appProperties(a);
|
|
324
|
+
const x = await readQuietly(pkg.docPropsCustomPart);
|
|
325
|
+
if (x)
|
|
326
|
+
out.custom = customProperties(x);
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
function put(m, name, value) {
|
|
330
|
+
if (value === undefined || value === null || value === '')
|
|
331
|
+
return;
|
|
332
|
+
m[name] = value;
|
|
333
|
+
}
|
|
334
|
+
function literal(o) {
|
|
335
|
+
const v = typeof o === 'object' && o !== null && 'value' in o && 'name' in o ? o.value : o;
|
|
336
|
+
const content = v === null || v === void 0 ? void 0 : v.content;
|
|
337
|
+
return content === undefined || content.length === 0 ? undefined : content.join('');
|
|
338
|
+
}
|
|
339
|
+
/** The core properties in the schema's order. */
|
|
340
|
+
function coreProperties(c) {
|
|
341
|
+
const m = {};
|
|
342
|
+
put(m, 'title', literal(c.title));
|
|
343
|
+
put(m, 'subject', literal(c.subject));
|
|
344
|
+
put(m, 'creator', literal(c.creator));
|
|
345
|
+
put(m, 'keywords', c.keywords);
|
|
346
|
+
put(m, 'description', literal(c.description));
|
|
347
|
+
put(m, 'category', c.category);
|
|
348
|
+
put(m, 'contentStatus', c.contentStatus);
|
|
349
|
+
put(m, 'language', literal(c.language));
|
|
350
|
+
put(m, 'identifier', literal(c.identifier));
|
|
351
|
+
put(m, 'version', c.version);
|
|
352
|
+
put(m, 'revision', c.revision);
|
|
353
|
+
put(m, 'lastModifiedBy', c.lastModifiedBy);
|
|
354
|
+
put(m, 'created', literal(c.created));
|
|
355
|
+
put(m, 'modified', literal(c.modified));
|
|
356
|
+
put(m, 'lastPrinted', calendarText(c.lastPrinted));
|
|
357
|
+
return m;
|
|
358
|
+
}
|
|
359
|
+
/** The application properties that describe the document; the statistics, which depend on layout, left out. */
|
|
360
|
+
function appProperties(p) {
|
|
361
|
+
const m = {};
|
|
362
|
+
put(m, 'Application', p.application);
|
|
363
|
+
put(m, 'AppVersion', p.appVersion);
|
|
364
|
+
put(m, 'Company', p.company);
|
|
365
|
+
put(m, 'Manager', p.manager);
|
|
366
|
+
put(m, 'Template', p.template);
|
|
367
|
+
put(m, 'HyperlinkBase', p.hyperlinkBase);
|
|
368
|
+
put(m, 'TotalTime', p.totalTime);
|
|
369
|
+
put(m, 'DocSecurity', p.docSecurity);
|
|
370
|
+
return m;
|
|
371
|
+
}
|
|
372
|
+
/** Each custom property's typed value, in the part's order; values of other types left out. */
|
|
373
|
+
function customProperties(p) {
|
|
374
|
+
var _a;
|
|
375
|
+
const m = {};
|
|
376
|
+
for (const property of (_a = p.property) !== null && _a !== void 0 ? _a : []) {
|
|
377
|
+
if (property.name === undefined)
|
|
378
|
+
continue;
|
|
379
|
+
put(m, property.name, customValue(property));
|
|
380
|
+
}
|
|
381
|
+
return m;
|
|
382
|
+
}
|
|
383
|
+
function customValue(p) {
|
|
384
|
+
for (const key of ['lpwstr', 'lpstr', 'bstr', 'bool', 'i1', 'i2', 'i4', 'i8', '_int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint', 'r4', 'r8', 'decimal']) {
|
|
385
|
+
const v = p[key];
|
|
386
|
+
if (v !== undefined && v !== null)
|
|
387
|
+
return v;
|
|
388
|
+
}
|
|
389
|
+
if (p.filetime !== undefined)
|
|
390
|
+
return calendarText(p.filetime);
|
|
391
|
+
if (p.date !== undefined)
|
|
392
|
+
return calendarText(p.date);
|
|
393
|
+
if (p.cy !== undefined)
|
|
394
|
+
return p.cy;
|
|
395
|
+
if (p.error !== undefined)
|
|
396
|
+
return p.error;
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
/** An XML calendar as its lexical form. */
|
|
400
|
+
export function calendarText(date) {
|
|
401
|
+
if (date === undefined || date === null)
|
|
402
|
+
return undefined;
|
|
403
|
+
if (typeof date === 'string')
|
|
404
|
+
return date;
|
|
405
|
+
const c = date;
|
|
406
|
+
if (typeof c.year !== 'number')
|
|
407
|
+
return String(date);
|
|
408
|
+
const p2 = (n) => String(n !== null && n !== void 0 ? n : 0).padStart(2, '0');
|
|
409
|
+
let out = `${String(c.year).padStart(4, '0')}-${p2(c.month)}-${p2(c.day)}`;
|
|
410
|
+
if (c.hour !== undefined) {
|
|
411
|
+
out += `T${p2(c.hour)}:${p2(c.minute)}:${p2(c.second)}`;
|
|
412
|
+
if (c.fractionalSecond)
|
|
413
|
+
out += String(c.fractionalSecond).replace(/^0/, '');
|
|
414
|
+
}
|
|
415
|
+
if (c.timezone !== undefined) {
|
|
416
|
+
if (c.timezone === 0)
|
|
417
|
+
out += 'Z';
|
|
418
|
+
else {
|
|
419
|
+
const sign = c.timezone < 0 ? '-' : '+';
|
|
420
|
+
const minutes = Math.abs(c.timezone);
|
|
421
|
+
out += `${sign}${p2(Math.floor(minutes / 60))}:${p2(minutes % 60)}`;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return out;
|
|
425
|
+
}
|