@stll/folio-core 0.33.1 → 0.34.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/dist/ai-edits/apply.d.ts +15 -0
- package/dist/ai-edits/apply.js +271 -48
- package/dist/ai-edits/headless.d.ts +47 -3
- package/dist/ai-edits/headless.js +53 -3
- package/dist/ai-edits/index.d.ts +1 -1
- package/dist/ai-edits/snapshot.d.ts +19 -1
- package/dist/ai-edits/snapshot.js +49 -5
- package/dist/ai-edits/table-geometry.d.ts +56 -0
- package/dist/ai-edits/table-geometry.js +217 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +34 -16
- package/dist/ai-edits/table-row-column-mutations.js +12 -4
- package/dist/ai-edits/table-template.d.ts +60 -0
- package/dist/ai-edits/table-template.js +176 -0
- package/dist/ai-edits/types.d.ts +13 -6
- package/dist/compare/__fixtures__/body-sequence.d.ts +61 -2
- package/dist/compare/__fixtures__/body-sequence.js +94 -6
- package/dist/compare/compare.d.ts +14 -7
- package/dist/compare/compare.js +136 -38
- package/dist/compare/formatting.d.ts +1 -1
- package/dist/compare/formatting.js +38 -9
- package/dist/compare/plan.d.ts +31 -1
- package/dist/compare/plan.js +233 -66
- package/dist/compare/types.d.ts +9 -7
- package/dist/compare/types.js +7 -5
- package/dist/compare/verification.d.ts +31 -12
- package/dist/compare/verification.js +106 -18
- package/dist/compat/eigenpal.d.ts +4 -4
- package/dist/compat/eigenpal.js +2 -2
- package/dist/controller/headerFooterEditorManager.js +11 -9
- package/dist/controller/layoutPipeline.js +24 -3
- package/dist/display-list/build/watermarkPrimitives.js +15 -3
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/document-operations.d.ts +10 -1
- package/dist/document-operations.js +33 -5
- package/dist/docx/appVersionNormalization.d.ts +49 -0
- package/dist/docx/appVersionNormalization.js +74 -0
- package/dist/docx/blockContentParser.js +3 -2
- package/dist/docx/drawingUtils.js +4 -3
- package/dist/docx/headerFooterParser.js +8 -14
- package/dist/docx/paragraphParser.js +48 -2
- package/dist/docx/rezip.d.ts +10 -4
- package/dist/docx/rezip.js +54 -18
- package/dist/docx/runParser.js +9 -8
- package/dist/docx/sdtProperties.js +4 -3
- package/dist/docx/selectiveSave.js +7 -6
- package/dist/docx/serializer/commentSerializer.d.ts +1 -1
- package/dist/docx/serializer/commentSerializer.js +43 -19
- package/dist/docx/serializer/documentSerializer.d.ts +3 -1
- package/dist/docx/serializer/documentSerializer.js +42 -78
- package/dist/docx/serializer/fontTableSerializer.js +8 -5
- package/dist/docx/serializer/headerFooterSerializer.d.ts +4 -1
- package/dist/docx/serializer/headerFooterSerializer.js +55 -31
- package/dist/docx/serializer/noteSerializer.js +34 -30
- package/dist/docx/serializer/numberingSerializer.js +8 -4
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +22 -12
- package/dist/docx/serializer/partNamespaces.d.ts +78 -0
- package/dist/docx/serializer/partNamespaces.js +324 -0
- package/dist/docx/serializer/runSerializer.js +1 -1
- package/dist/docx/serializer/settingsSerializer.js +8 -2
- package/dist/docx/serializer/stylesSerializer.js +8 -5
- package/dist/docx/serializer/tableSerializer.js +83 -18
- package/dist/docx/serializer/themeSerializer.js +10 -2
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/docx/settingsParser.js +3 -0
- package/dist/docx/strictValueEncodings.gen.d.ts +15 -0
- package/dist/docx/strictValueEncodings.gen.js +275 -0
- package/dist/docx/tableParser.d.ts +0 -6
- package/dist/docx/tableParser.js +52 -7
- package/dist/docx/transitionalSpelling.d.ts +23 -0
- package/dist/docx/transitionalSpelling.js +36 -0
- package/dist/docx/universalMeasure.d.ts +20 -0
- package/dist/docx/universalMeasure.js +32 -0
- package/dist/docx/verbatimCapture.d.ts +20 -0
- package/dist/docx/verbatimCapture.js +131 -0
- package/dist/docx/vmlImageParser.js +4 -3
- package/dist/docx/watermarkParser.d.ts +2 -4
- package/dist/docx/watermarkParser.js +8 -9
- package/dist/docx/xmlParser.d.ts +23 -2
- package/dist/docx/xmlParser.js +43 -11
- package/dist/headless-layout.js +14 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -2
- package/dist/layout-bridge/convert/footnoteLayout.js +23 -10
- package/dist/layout-bridge/convert/headerFooterLayout.js +13 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +96 -13
- package/dist/layout-engine/index.js +11 -4
- package/dist/layout-engine/justifiedLineFit.d.ts +4 -4
- package/dist/layout-engine/justifiedLineFit.js +4 -4
- package/dist/layout-engine/measure/lineBreakProvider.js +1 -0
- package/dist/layout-engine/measure/measureBlocks.js +1 -1
- package/dist/layout-engine/measure/measureParagraph.js +29 -29
- package/dist/layout-painter/renderPage.js +6 -1
- package/dist/layout-painter/renderParagraph.js +18 -8
- package/dist/layout-painter/renderWatermark.js +11 -4
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/prosemirror/attrs/index.js +11 -0
- package/dist/prosemirror/commands/comments.js +24 -3
- package/dist/prosemirror/containerFinalParagraph.d.ts +47 -0
- package/dist/prosemirror/containerFinalParagraph.js +92 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +47 -9
- package/dist/prosemirror/conversion/toProseDoc.js +61 -14
- package/dist/prosemirror/extensions/core/DocExtension.js +7 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +5 -0
- package/dist/prosemirror/schema/marks.d.ts +3 -9
- package/dist/prosemirror/schema/nodes.d.ts +22 -0
- package/dist/server.d.ts +1 -1
- package/dist/types/block-id.d.ts +12 -1
- package/dist/types/block-id.js +17 -1
- package/dist/utils/canonicalJson.d.ts +14 -0
- package/dist/utils/canonicalJson.js +19 -0
- package/dist/utils/fontResolver.js +51 -0
- package/dist/utils/formatToStyle.d.ts +1 -1
- package/dist/utils/formatToStyle.js +41 -1
- package/dist/watermark/index.js +7 -0
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { deterministicHexId } from "../../utils/hexId.js";
|
|
2
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
|
+
import { serializePartElement } from "./partNamespaces.js";
|
|
3
4
|
import { serializeTextFormatting } from "./runSerializer.js";
|
|
4
5
|
import { escapeXml } from "./xmlUtils.js";
|
|
5
6
|
//#region src/docx/serializer/commentSerializer.ts
|
|
@@ -36,12 +37,29 @@ function serializeComment(comment) {
|
|
|
36
37
|
xml += "</w:comment>";
|
|
37
38
|
return xml;
|
|
38
39
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
const COMMENTS_BASELINE_PREFIXES = [
|
|
41
|
+
"wpc",
|
|
42
|
+
"mc",
|
|
43
|
+
"o",
|
|
44
|
+
"r",
|
|
45
|
+
"m",
|
|
46
|
+
"v",
|
|
47
|
+
"wp",
|
|
48
|
+
"w10",
|
|
49
|
+
"w",
|
|
50
|
+
"w14",
|
|
51
|
+
"wp14",
|
|
52
|
+
"wpg",
|
|
53
|
+
"wpi",
|
|
54
|
+
"wne",
|
|
55
|
+
"wps"
|
|
56
|
+
];
|
|
57
|
+
const COMMENTS_EXTENDED_BASELINE_PREFIXES = [
|
|
58
|
+
"mc",
|
|
59
|
+
"w",
|
|
60
|
+
"w15"
|
|
61
|
+
];
|
|
62
|
+
const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
|
45
63
|
/**
|
|
46
64
|
* Serialize comments array to comments.xml content. Returns a valid empty
|
|
47
65
|
* `<w:comments/>` document for an empty array so callers can overwrite an
|
|
@@ -49,18 +67,21 @@ const COMMENTS_HEADER = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
|
49
67
|
* comment — leaving the previous file in place would otherwise re-emit
|
|
50
68
|
* the orphaned comment threads on every save.
|
|
51
69
|
*/
|
|
52
|
-
function serializeComments(comments) {
|
|
70
|
+
function serializeComments(comments, sourceBindings) {
|
|
53
71
|
const topLevel = [];
|
|
54
72
|
const replies = [];
|
|
55
73
|
for (const c of comments) {
|
|
56
74
|
const { parentId } = c;
|
|
57
75
|
(parentId === null || parentId === void 0 ? topLevel : replies).push(c);
|
|
58
76
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
const body = topLevel.map((comment) => serializeComment(comment)).join("") + replies.map((reply) => serializeComment(reply)).join("");
|
|
78
|
+
return XML_DECLARATION + serializePartElement({
|
|
79
|
+
partPath: "word/comments.xml",
|
|
80
|
+
rootName: "w:comments",
|
|
81
|
+
baselinePrefixes: COMMENTS_BASELINE_PREFIXES,
|
|
82
|
+
sourceBindings,
|
|
83
|
+
body
|
|
84
|
+
});
|
|
64
85
|
}
|
|
65
86
|
/** The `w14:paraId` Word threads a comment by: its LAST paragraph's paraId. */
|
|
66
87
|
function commentThreadParaId(comment) {
|
|
@@ -145,7 +166,6 @@ function buildCommentExtendedEntries(comments) {
|
|
|
145
166
|
}
|
|
146
167
|
return entries.length > 0 ? entries : null;
|
|
147
168
|
}
|
|
148
|
-
const COMMENTS_EXTENDED_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<w15:commentsEx xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" mc:Ignorable=\"w15\">";
|
|
149
169
|
/**
|
|
150
170
|
* Serialize `commentsExtended.xml` (`w15:commentsEx`) for reply threading and
|
|
151
171
|
* resolved state, or `null` when no comment needs an entry (see
|
|
@@ -155,13 +175,17 @@ const COMMENTS_EXTENDED_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" stand
|
|
|
155
175
|
function serializeCommentsExtended(comments) {
|
|
156
176
|
const entries = buildCommentExtendedEntries(comments);
|
|
157
177
|
if (!entries) return null;
|
|
158
|
-
|
|
159
|
-
for (const entry of entries) {
|
|
178
|
+
const body = entries.map((entry) => {
|
|
160
179
|
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${escapeXml(entry.paraIdParent)}"` : "";
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
return `<w15:commentEx w15:paraId="${escapeXml(entry.paraId)}"${parentAttr} w15:done="${entry.done ? "1" : "0"}"/>`;
|
|
181
|
+
}).join("");
|
|
182
|
+
return XML_DECLARATION + serializePartElement({
|
|
183
|
+
partPath: "word/commentsExtended.xml",
|
|
184
|
+
rootName: "w15:commentsEx",
|
|
185
|
+
baselinePrefixes: COMMENTS_EXTENDED_BASELINE_PREFIXES,
|
|
186
|
+
sourceBindings: void 0,
|
|
187
|
+
body
|
|
188
|
+
});
|
|
165
189
|
}
|
|
166
190
|
//#endregion
|
|
167
191
|
export { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended };
|
|
@@ -11,9 +11,11 @@ declare function serializeDocumentBody(body: document_d_exports.DocumentBody): s
|
|
|
11
11
|
* Serialize a complete Document to valid document.xml
|
|
12
12
|
*
|
|
13
13
|
* @param doc - The document to serialize
|
|
14
|
+
* @param sourceBindings - Root `xmlns:*` of the part being replaced, so a
|
|
15
|
+
* prefix only the source document bound keeps its URI
|
|
14
16
|
* @returns Complete XML string for document.xml
|
|
15
17
|
*/
|
|
16
|
-
declare function serializeDocument(doc: document_d_exports.Document): string;
|
|
18
|
+
declare function serializeDocument(doc: document_d_exports.Document, sourceBindings?: ReadonlyMap<string, string>): string;
|
|
17
19
|
/**
|
|
18
20
|
* Serialize just the document body (useful for partial updates)
|
|
19
21
|
*
|
|
@@ -1,78 +1,41 @@
|
|
|
1
1
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
2
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
|
+
import { serializePartElement } from "./partNamespaces.js";
|
|
3
4
|
import { resetAutoIdCounter } from "./runSerializer.js";
|
|
4
5
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
5
6
|
import { serializeTable } from "./tableSerializer.js";
|
|
6
7
|
//#region src/docx/serializer/documentSerializer.ts
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
|
|
39
|
-
w16: "http://schemas.microsoft.com/office/word/2018/wordml",
|
|
40
|
-
w16sdtdh: "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash",
|
|
41
|
-
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
|
|
42
|
-
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
|
|
43
|
-
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
|
44
|
-
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
|
|
45
|
-
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Build namespace declaration string for document element
|
|
49
|
-
*/
|
|
50
|
-
function buildNamespaceDeclarations() {
|
|
51
|
-
const declared = {
|
|
52
|
-
a: NAMESPACES.a,
|
|
53
|
-
wpc: NAMESPACES.wpc,
|
|
54
|
-
mc: NAMESPACES.mc,
|
|
55
|
-
o: NAMESPACES.o,
|
|
56
|
-
pic: NAMESPACES.pic,
|
|
57
|
-
r: NAMESPACES.r,
|
|
58
|
-
m: NAMESPACES.m,
|
|
59
|
-
v: NAMESPACES.v,
|
|
60
|
-
wp14: NAMESPACES.wp14,
|
|
61
|
-
wp: NAMESPACES.wp,
|
|
62
|
-
w10: NAMESPACES.w10,
|
|
63
|
-
w: NAMESPACES.w,
|
|
64
|
-
w14: NAMESPACES.w14,
|
|
65
|
-
w15: NAMESPACES.w15,
|
|
66
|
-
w16: NAMESPACES.w16,
|
|
67
|
-
w16cex: NAMESPACES.w16cex,
|
|
68
|
-
w16cid: NAMESPACES.w16cid,
|
|
69
|
-
w16sdtdh: NAMESPACES.w16sdtdh,
|
|
70
|
-
w16se: NAMESPACES.w16se,
|
|
71
|
-
wpg: NAMESPACES.wpg,
|
|
72
|
-
wps: NAMESPACES.wps
|
|
73
|
-
};
|
|
74
|
-
return Object.entries(declared).map(([prefix, uri]) => `xmlns:${prefix}="${uri}"`).join(" ");
|
|
75
|
-
}
|
|
9
|
+
* Prefixes document.xml declares whether or not the body uses them.
|
|
10
|
+
*
|
|
11
|
+
* A canonical `<w:sdtPr>` legitimately carries `<w16sdtdh:dataHash>` /
|
|
12
|
+
* `<w16cex:*>` / `<w16cid:*>` children the parser stores opaquely, and the
|
|
13
|
+
* drawing prefixes host raw-replayed shapes, so the part keeps the shape Word
|
|
14
|
+
* writes even when this particular save emits none of them.
|
|
15
|
+
*/
|
|
16
|
+
const DOCUMENT_BASELINE_PREFIXES = [
|
|
17
|
+
"a",
|
|
18
|
+
"wpc",
|
|
19
|
+
"mc",
|
|
20
|
+
"o",
|
|
21
|
+
"pic",
|
|
22
|
+
"r",
|
|
23
|
+
"m",
|
|
24
|
+
"v",
|
|
25
|
+
"wp14",
|
|
26
|
+
"wp",
|
|
27
|
+
"w10",
|
|
28
|
+
"w",
|
|
29
|
+
"w14",
|
|
30
|
+
"w15",
|
|
31
|
+
"w16",
|
|
32
|
+
"w16cex",
|
|
33
|
+
"w16cid",
|
|
34
|
+
"w16sdtdh",
|
|
35
|
+
"w16se",
|
|
36
|
+
"wpg",
|
|
37
|
+
"wps"
|
|
38
|
+
];
|
|
76
39
|
/**
|
|
77
40
|
* Serialize a single block content item (paragraph, table, or block-level SDT).
|
|
78
41
|
*/
|
|
@@ -103,19 +66,20 @@ function serializeDocumentBody(body) {
|
|
|
103
66
|
* Serialize a complete Document to valid document.xml
|
|
104
67
|
*
|
|
105
68
|
* @param doc - The document to serialize
|
|
69
|
+
* @param sourceBindings - Root `xmlns:*` of the part being replaced, so a
|
|
70
|
+
* prefix only the source document bound keeps its URI
|
|
106
71
|
* @returns Complete XML string for document.xml
|
|
107
72
|
*/
|
|
108
|
-
function serializeDocument(doc) {
|
|
73
|
+
function serializeDocument(doc, sourceBindings) {
|
|
109
74
|
resetAutoIdCounter();
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return parts.join("");
|
|
75
|
+
const body = `<w:body>${serializeDocumentBody(doc.package.document)}</w:body>`;
|
|
76
|
+
return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + serializePartElement({
|
|
77
|
+
partPath: "word/document.xml",
|
|
78
|
+
rootName: "w:document",
|
|
79
|
+
baselinePrefixes: DOCUMENT_BASELINE_PREFIXES,
|
|
80
|
+
sourceBindings,
|
|
81
|
+
body
|
|
82
|
+
});
|
|
119
83
|
}
|
|
120
84
|
/**
|
|
121
85
|
* Serialize just the document body (useful for partial updates)
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { serializePartElement } from "./partNamespaces.js";
|
|
1
2
|
import { escapeXml } from "./xmlUtils.js";
|
|
2
3
|
//#region src/docx/serializer/fontTableSerializer.ts
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const serializeFontTableXml = (fontTable) => "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + serializePartElement({
|
|
5
|
+
partPath: "word/fontTable.xml",
|
|
6
|
+
rootName: "w:fonts",
|
|
7
|
+
baselinePrefixes: ["w"],
|
|
8
|
+
sourceBindings: void 0,
|
|
9
|
+
body: fontTable.fonts.map(serializeFont).join("")
|
|
10
|
+
});
|
|
8
11
|
const serializeFont = (font) => {
|
|
9
12
|
const parts = [];
|
|
10
13
|
if (font.altName) parts.push(`<w:altName w:val="${escapeXml(font.altName)}"/>`);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { SourcePart } from "./partNamespaces.js";
|
|
2
3
|
//#region src/docx/serializer/headerFooterSerializer.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* Serialize a HeaderFooter object to valid OOXML XML
|
|
5
6
|
*
|
|
6
7
|
* @param hf - HeaderFooter object to serialize
|
|
8
|
+
* @param source - The part being replaced, so a prefix only the source
|
|
9
|
+
* document bound keeps its URI
|
|
7
10
|
* @returns Complete XML string for header*.xml or footer*.xml
|
|
8
11
|
*/
|
|
9
|
-
declare function serializeHeaderFooter(hf: document_d_exports.HeaderFooter): string;
|
|
12
|
+
declare function serializeHeaderFooter(hf: document_d_exports.HeaderFooter, source?: SourcePart): string;
|
|
10
13
|
//#endregion
|
|
11
14
|
export { serializeHeaderFooter };
|
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
import { canReplayHeaderFooterVerbatim, getHeaderFooterVerbatimXml } from "../headerFooterVerbatim.js";
|
|
2
|
+
import { isEmptyParagraph } from "../paragraphParser.js";
|
|
3
|
+
import { captureVerbatimXml } from "../verbatimCapture.js";
|
|
4
|
+
import { getLocalName, parseXmlDocument } from "../xmlParser.js";
|
|
2
5
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
3
6
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
7
|
+
import { serializePartElement } from "./partNamespaces.js";
|
|
4
8
|
import { serializeTable } from "./tableSerializer.js";
|
|
5
9
|
import { escapeXml } from "./xmlUtils.js";
|
|
6
10
|
//#region src/docx/serializer/headerFooterSerializer.ts
|
|
7
|
-
const
|
|
8
|
-
wpc
|
|
9
|
-
mc
|
|
10
|
-
o
|
|
11
|
-
r
|
|
12
|
-
m
|
|
13
|
-
v
|
|
14
|
-
a
|
|
15
|
-
pic
|
|
16
|
-
wp14
|
|
17
|
-
wp
|
|
18
|
-
w10
|
|
19
|
-
w
|
|
20
|
-
w14
|
|
21
|
-
w15
|
|
22
|
-
w16
|
|
23
|
-
w16cex
|
|
24
|
-
w16cid
|
|
25
|
-
w16sdtdh
|
|
26
|
-
w16se
|
|
27
|
-
wpg
|
|
28
|
-
wps
|
|
29
|
-
|
|
30
|
-
function buildNamespaceDeclarations() {
|
|
31
|
-
return Object.entries(NAMESPACES).map(([prefix, uri]) => `xmlns:${prefix}="${uri}"`).join(" ");
|
|
32
|
-
}
|
|
11
|
+
const HEADER_FOOTER_BASELINE_PREFIXES = [
|
|
12
|
+
"wpc",
|
|
13
|
+
"mc",
|
|
14
|
+
"o",
|
|
15
|
+
"r",
|
|
16
|
+
"m",
|
|
17
|
+
"v",
|
|
18
|
+
"a",
|
|
19
|
+
"pic",
|
|
20
|
+
"wp14",
|
|
21
|
+
"wp",
|
|
22
|
+
"w10",
|
|
23
|
+
"w",
|
|
24
|
+
"w14",
|
|
25
|
+
"w15",
|
|
26
|
+
"w16",
|
|
27
|
+
"w16cex",
|
|
28
|
+
"w16cid",
|
|
29
|
+
"w16sdtdh",
|
|
30
|
+
"w16se",
|
|
31
|
+
"wpg",
|
|
32
|
+
"wps"
|
|
33
|
+
];
|
|
33
34
|
/**
|
|
34
35
|
* Serialize a block content item (paragraph, table, or block-level SDT) for
|
|
35
36
|
* header/footer.
|
|
@@ -43,21 +44,44 @@ function serializeBlock(block) {
|
|
|
43
44
|
* Serialize a HeaderFooter object to valid OOXML XML
|
|
44
45
|
*
|
|
45
46
|
* @param hf - HeaderFooter object to serialize
|
|
47
|
+
* @param source - The part being replaced, so a prefix only the source
|
|
48
|
+
* document bound keeps its URI
|
|
46
49
|
* @returns Complete XML string for header*.xml or footer*.xml
|
|
47
50
|
*/
|
|
48
|
-
function serializeHeaderFooter(hf) {
|
|
51
|
+
function serializeHeaderFooter(hf, source) {
|
|
49
52
|
const verbatim = getHeaderFooterVerbatimXml(hf);
|
|
50
53
|
if (verbatim && canReplayHeaderFooterVerbatim(hf)) return verbatim;
|
|
51
54
|
const rootTag = hf.type === "header" ? "w:hdr" : "w:ftr";
|
|
52
|
-
const nsDecl = buildNamespaceDeclarations();
|
|
53
55
|
const watermarkXml = serializeWatermarkParagraph(hf);
|
|
54
56
|
const watermarkInsertIndex = hf.watermarkBlockIndex !== void 0 ? Math.max(0, Math.min(hf.watermarkBlockIndex, hf.content.length)) : 0;
|
|
55
57
|
const blocksXml = hf.content.map((block) => serializeBlock(block));
|
|
56
58
|
let contentXml;
|
|
57
|
-
if (watermarkXml)
|
|
58
|
-
|
|
59
|
+
if (watermarkXml) {
|
|
60
|
+
const watermarkHost = hf.content.at(watermarkInsertIndex);
|
|
61
|
+
const rawWatermarkXml = hf.rawWatermarkXml;
|
|
62
|
+
const mergesIntoRetainedHost = rawWatermarkXml !== void 0 && watermarkHost?.type === "paragraph" && isEmptyParagraph(watermarkHost);
|
|
63
|
+
if (mergesIntoRetainedHost) blocksXml[watermarkInsertIndex] = serializeRawWatermarkIntoHost({
|
|
64
|
+
hostXml: blocksXml[watermarkInsertIndex] ?? serializeParagraph(watermarkHost),
|
|
65
|
+
rawWatermarkXml
|
|
66
|
+
});
|
|
67
|
+
contentXml = blocksXml.slice(0, watermarkInsertIndex).join("") + (mergesIntoRetainedHost ? "" : watermarkXml) + blocksXml.slice(watermarkInsertIndex).join("");
|
|
68
|
+
} else contentXml = blocksXml.join("");
|
|
59
69
|
if (!contentXml) contentXml = "<w:p><w:pPr/></w:p>";
|
|
60
|
-
return
|
|
70
|
+
return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + serializePartElement({
|
|
71
|
+
partPath: source?.path ?? `word/${hf.type}.xml`,
|
|
72
|
+
rootName: rootTag,
|
|
73
|
+
baselinePrefixes: HEADER_FOOTER_BASELINE_PREFIXES,
|
|
74
|
+
sourceBindings: source?.bindings,
|
|
75
|
+
body: contentXml
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function serializeRawWatermarkIntoHost({ hostXml, rawWatermarkXml }) {
|
|
79
|
+
const rawHost = parseXmlDocument(rawWatermarkXml);
|
|
80
|
+
if (!rawHost || getLocalName(rawHost.name ?? "") !== "p") return rawWatermarkXml;
|
|
81
|
+
const watermarkContent = (rawHost.elements ?? []).filter((child) => child.type === "element" && getLocalName(child.name ?? "") !== "pPr").map((child) => captureVerbatimXml(child)).join("");
|
|
82
|
+
if (!watermarkContent) return rawWatermarkXml;
|
|
83
|
+
const namespaceAttributes = Object.entries(rawHost.attributes ?? {}).filter(([name, value]) => value !== void 0 && (name === "xmlns" || name.startsWith("xmlns:"))).map(([name, value]) => ` ${name}="${escapeXml(String(value))}"`).join("");
|
|
84
|
+
return hostXml.replace(/^<w:p(?=[\s>])/u, `<w:p${namespaceAttributes}`).replace("</w:p>", `${watermarkContent}</w:p>`);
|
|
61
85
|
}
|
|
62
86
|
function serializeWatermarkParagraph(hf) {
|
|
63
87
|
if (hf.rawWatermarkXml) return hf.rawWatermarkXml;
|
|
@@ -1,33 +1,38 @@
|
|
|
1
1
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
2
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
|
+
import { serializePartElement } from "./partNamespaces.js";
|
|
3
4
|
import { serializeTable } from "./tableSerializer.js";
|
|
4
5
|
//#region src/docx/serializer/noteSerializer.ts
|
|
5
|
-
const
|
|
6
|
-
wpc
|
|
7
|
-
mc
|
|
8
|
-
o
|
|
9
|
-
r
|
|
10
|
-
m
|
|
11
|
-
v
|
|
12
|
-
a
|
|
13
|
-
pic
|
|
14
|
-
wp14
|
|
15
|
-
wp
|
|
16
|
-
w10
|
|
17
|
-
w
|
|
18
|
-
w14
|
|
19
|
-
w15
|
|
20
|
-
w16
|
|
21
|
-
w16cex
|
|
22
|
-
w16cid
|
|
23
|
-
w16sdtdh
|
|
24
|
-
w16se
|
|
25
|
-
wpg
|
|
26
|
-
wps
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
6
|
+
const NOTE_BASELINE_PREFIXES = [
|
|
7
|
+
"wpc",
|
|
8
|
+
"mc",
|
|
9
|
+
"o",
|
|
10
|
+
"r",
|
|
11
|
+
"m",
|
|
12
|
+
"v",
|
|
13
|
+
"a",
|
|
14
|
+
"pic",
|
|
15
|
+
"wp14",
|
|
16
|
+
"wp",
|
|
17
|
+
"w10",
|
|
18
|
+
"w",
|
|
19
|
+
"w14",
|
|
20
|
+
"w15",
|
|
21
|
+
"w16",
|
|
22
|
+
"w16cex",
|
|
23
|
+
"w16cid",
|
|
24
|
+
"w16sdtdh",
|
|
25
|
+
"w16se",
|
|
26
|
+
"wpg",
|
|
27
|
+
"wps"
|
|
28
|
+
];
|
|
29
|
+
const serializeNotePart = (elementName, body) => "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + serializePartElement({
|
|
30
|
+
partPath: `word/${elementName}s.xml`,
|
|
31
|
+
rootName: `w:${elementName}s`,
|
|
32
|
+
baselinePrefixes: NOTE_BASELINE_PREFIXES,
|
|
33
|
+
sourceBindings: void 0,
|
|
34
|
+
body
|
|
35
|
+
});
|
|
31
36
|
/**
|
|
32
37
|
* Serialize a block content item (paragraph, table, or block-level SDT) for a
|
|
33
38
|
* note body.
|
|
@@ -63,9 +68,8 @@ function insertNoteReferenceMark(xml, elementName) {
|
|
|
63
68
|
return `${xml.slice(0, insertAt)}${referenceRun}${xml.slice(insertAt)}`;
|
|
64
69
|
}
|
|
65
70
|
function serializeNewNotePart(elementName, notes) {
|
|
66
|
-
const nsDecl = buildNamespaceDeclarations();
|
|
67
71
|
const serializedNotes = notes.map((note) => insertNoteReferenceMark(serializeNote(elementName, note), elementName)).join("");
|
|
68
|
-
return
|
|
72
|
+
return serializeNotePart(elementName, serializeRequiredNoteSeparators(elementName) + serializedNotes);
|
|
69
73
|
}
|
|
70
74
|
/**
|
|
71
75
|
* Serialize footnotes to a complete word/footnotes.xml string.
|
|
@@ -74,7 +78,7 @@ function serializeNewNotePart(elementName, notes) {
|
|
|
74
78
|
* @returns Complete footnotes.xml string.
|
|
75
79
|
*/
|
|
76
80
|
function serializeFootnotes(footnotes) {
|
|
77
|
-
return
|
|
81
|
+
return serializeNotePart("footnote", footnotes.map((fn) => serializeNote("footnote", fn)).join(""));
|
|
78
82
|
}
|
|
79
83
|
/**
|
|
80
84
|
* Serialize endnotes to a complete word/endnotes.xml string.
|
|
@@ -83,7 +87,7 @@ function serializeFootnotes(footnotes) {
|
|
|
83
87
|
* @returns Complete endnotes.xml string.
|
|
84
88
|
*/
|
|
85
89
|
function serializeEndnotes(endnotes) {
|
|
86
|
-
return
|
|
90
|
+
return serializeNotePart("endnote", endnotes.map((en) => serializeNote("endnote", en)).join(""));
|
|
87
91
|
}
|
|
88
92
|
/** Serialize a brand-new footnote part, including Word's required separators
|
|
89
93
|
* and the automatic reference mark at the start of every normal note. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { serializePartElement } from "./partNamespaces.js";
|
|
1
2
|
import { serializeTextFormatting } from "./runSerializer.js";
|
|
2
3
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
3
4
|
//#region src/docx/serializer/numberingSerializer.ts
|
|
4
|
-
const W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
5
5
|
/**
|
|
6
6
|
* Serialize a level's paragraph properties — the modeled subset is indentation
|
|
7
7
|
* plus tab stops (see `parseLevelParagraphProps`). Returns "" when neither is
|
|
@@ -87,9 +87,13 @@ function serializeNum(instance) {
|
|
|
87
87
|
* change detection and per-definition splicing, never to overwrite the part.
|
|
88
88
|
*/
|
|
89
89
|
function serializeNumberingXml(numbering) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + serializePartElement({
|
|
91
|
+
partPath: "word/numbering.xml",
|
|
92
|
+
rootName: "w:numbering",
|
|
93
|
+
baselinePrefixes: ["w"],
|
|
94
|
+
sourceBindings: void 0,
|
|
95
|
+
body: `${numbering.abstractNums.map(serializeAbstractNum).join("")}${numbering.nums.map(serializeNum).join("")}`
|
|
96
|
+
});
|
|
93
97
|
}
|
|
94
98
|
//#endregion
|
|
95
99
|
export { serializeNumberingXml };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
2
|
//#region src/docx/serializer/paragraphSerializer.d.ts
|
|
3
|
-
declare function serializeParagraphFormatting(formatting: document_d_exports.ParagraphFormatting | undefined, propertyChanges?: document_d_exports.ParagraphPropertyChange[],
|
|
3
|
+
declare function serializeParagraphFormatting(formatting: document_d_exports.ParagraphFormatting | undefined, propertyChanges?: document_d_exports.ParagraphPropertyChange[], paragraphMarkChange?: document_d_exports.ParagraphMarkChange): string;
|
|
4
4
|
/**
|
|
5
5
|
* Serialize a paragraph to OOXML XML (w:p)
|
|
6
6
|
*
|
|
@@ -140,7 +140,7 @@ function serializeParagraphMarkChange(mark) {
|
|
|
140
140
|
const attrs = serializeTrackedChangeAttrs(mark.info);
|
|
141
141
|
return `<w:${mark.kind} ${attrs}/>`;
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, sectionProperties } = {}) => {
|
|
144
144
|
const parts = [];
|
|
145
145
|
const pushToggle = (name, value) => {
|
|
146
146
|
if (value === true) parts.push(`<w:${name}/>`);
|
|
@@ -150,12 +150,10 @@ function serializeParagraphFormatting(formatting, propertyChanges, pPrMark) {
|
|
|
150
150
|
if (formatting.styleId) parts.push(`<w:pStyle w:val="${escapeXml(formatting.styleId)}"/>`);
|
|
151
151
|
pushToggle("keepNext", formatting.keepNext);
|
|
152
152
|
pushToggle("keepLines", formatting.keepLines);
|
|
153
|
-
pushToggle("contextualSpacing", formatting.contextualSpacing);
|
|
154
153
|
pushToggle("pageBreakBefore", formatting.pageBreakBefore);
|
|
155
154
|
const frameXml = serializeFrameProperties(formatting.frame);
|
|
156
155
|
if (frameXml) parts.push(frameXml);
|
|
157
156
|
pushToggle("widowControl", formatting.widowControl);
|
|
158
|
-
pushToggle("snapToGrid", formatting.snapToGrid);
|
|
159
157
|
const numPrXml = formatting.numPrFromStyle != null && numPrEqual(formatting.numPr, formatting.numPrFromStyle) ? "" : serializeNumbering(formatting.numPr);
|
|
160
158
|
if (numPrXml) parts.push(numPrXml);
|
|
161
159
|
const bordersXml = serializeParagraphBorders(formatting.borders);
|
|
@@ -168,21 +166,31 @@ function serializeParagraphFormatting(formatting, propertyChanges, pPrMark) {
|
|
|
168
166
|
pushToggle("suppressAutoHyphens", formatting.suppressAutoHyphens);
|
|
169
167
|
pushToggle("kinsoku", formatting.kinsoku);
|
|
170
168
|
pushToggle("overflowPunct", formatting.overflowPunctuation);
|
|
169
|
+
pushToggle("bidi", formatting.bidi);
|
|
170
|
+
pushToggle("snapToGrid", formatting.snapToGrid);
|
|
171
171
|
const spacingXml = serializeSpacing(formatting);
|
|
172
172
|
if (spacingXml) parts.push(spacingXml);
|
|
173
173
|
const indXml = serializeIndentation(formatting);
|
|
174
174
|
if (indXml) parts.push(indXml);
|
|
175
|
-
pushToggle("
|
|
175
|
+
pushToggle("contextualSpacing", formatting.contextualSpacing);
|
|
176
176
|
if (formatting.alignment) parts.push(`<w:jc w:val="${formatting.alignment}"/>`);
|
|
177
177
|
if (formatting.outlineLevel !== void 0) parts.push(`<w:outlineLvl w:val="${formatting.outlineLevel}"/>`);
|
|
178
|
-
if (
|
|
179
|
-
const fullInner = `${
|
|
178
|
+
if (paragraphMarkChange || formatting.runProperties || formatting.runInWithNext) {
|
|
179
|
+
const fullInner = `${paragraphMarkChange ? serializeParagraphMarkChange(paragraphMarkChange) : ""}${formatting.runProperties ? extractRPrInner(serializeTextFormatting(formatting.runProperties)) : ""}${formatting.runInWithNext ? "<w:specVanish/>" : ""}`;
|
|
180
180
|
if (fullInner.length > 0) parts.push(`<w:rPr>${fullInner}</w:rPr>`);
|
|
181
181
|
}
|
|
182
|
-
} else if (
|
|
182
|
+
} else if (paragraphMarkChange) parts.push(`<w:rPr>${serializeParagraphMarkChange(paragraphMarkChange)}</w:rPr>`);
|
|
183
|
+
parts.push(serializeSectionProperties(sectionProperties));
|
|
183
184
|
if (propertyChanges && propertyChanges.length > 0) parts.push(...propertyChanges.map((change) => serializeParagraphPropertyChange(change)));
|
|
184
|
-
|
|
185
|
-
return
|
|
185
|
+
const inner = parts.join("");
|
|
186
|
+
if (inner.length === 0) return "";
|
|
187
|
+
return `<w:pPr>${inner}</w:pPr>`;
|
|
188
|
+
};
|
|
189
|
+
function serializeParagraphFormatting(formatting, propertyChanges, paragraphMarkChange) {
|
|
190
|
+
return serializeParagraphFormattingWithOptions(formatting, {
|
|
191
|
+
propertyChanges,
|
|
192
|
+
paragraphMarkChange
|
|
193
|
+
});
|
|
186
194
|
}
|
|
187
195
|
function extractPPrInner(pPrXml) {
|
|
188
196
|
if (!pPrXml.startsWith("<w:pPr>") || !pPrXml.endsWith("</w:pPr>")) return "";
|
|
@@ -486,9 +494,11 @@ function serializeParagraph(paragraph) {
|
|
|
486
494
|
if (paragraph.paraId) attrs.push(`w14:paraId="${escapeXml(paragraph.paraId)}"`);
|
|
487
495
|
if (paragraph.textId) attrs.push(`w14:textId="${escapeXml(paragraph.textId)}"`);
|
|
488
496
|
const attrsStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
497
|
+
parts.push(serializeParagraphFormattingWithOptions(paragraph.formatting, {
|
|
498
|
+
propertyChanges: paragraph.propertyChanges,
|
|
499
|
+
paragraphMarkChange: paragraph.pPrMark,
|
|
500
|
+
sectionProperties: paragraph.sectionProperties
|
|
501
|
+
}));
|
|
492
502
|
const explicitCommentReferenceIds = /* @__PURE__ */ new Set();
|
|
493
503
|
for (const content of paragraph.content) if (content.type === "commentReference") explicitCommentReferenceIds.add(content.id);
|
|
494
504
|
let pendingRenderedPageBreak = paragraph.renderedPageBreakBefore === true;
|