@stll/folio-core 0.42.0 → 0.44.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/headless.js +6 -5
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/snapshot.js +13 -9
- package/dist/compare/content-alignment.js +16 -1
- package/dist/compare/inline-atoms.js +1 -1
- package/dist/compare/style-resources.js +6 -0
- package/dist/compat/eigenpal.d.ts +2 -2
- package/dist/controller/layoutPipeline.d.ts +2 -1
- package/dist/controller/layoutPipeline.js +5 -2
- package/dist/controller/layoutSession.d.ts +2 -1
- package/dist/controller/layoutSession.js +1 -0
- package/dist/docx/appVersionNormalization.d.ts +0 -18
- package/dist/docx/blockContentParser.js +10 -1
- package/dist/docx/blockRangeMarkers.d.ts +36 -0
- package/dist/docx/blockRangeMarkers.js +59 -0
- package/dist/docx/bookmarkParser.d.ts +2 -20
- package/dist/docx/bookmarkParser.js +6 -30
- package/dist/docx/borderParser.d.ts +13 -0
- package/dist/docx/borderParser.js +71 -0
- package/dist/docx/builtInStyles.d.ts +165 -0
- package/dist/docx/builtInStyles.js +239 -0
- package/dist/docx/commentIdNormalization.d.ts +10 -0
- package/dist/docx/commentIdNormalization.js +33 -0
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +34 -7
- package/dist/docx/commentReferenceNormalization.d.ts +4 -1
- package/dist/docx/commentReferenceNormalization.js +23 -14
- package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
- package/dist/docx/danglingRelationshipReferences.js +30 -0
- package/dist/docx/defaultParagraphStyle.d.ts +39 -0
- package/dist/docx/defaultParagraphStyle.js +54 -0
- package/dist/docx/documentParser.d.ts +2 -1
- package/dist/docx/documentParser.js +2 -2
- package/dist/docx/drawingUtils.d.ts +8 -1
- package/dist/docx/drawingUtils.js +12 -3
- package/dist/docx/fieldParser.js +3 -5
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +19 -2
- package/dist/docx/groupDrawingParser.js +1 -1
- package/dist/docx/headerFooterRefParser.d.ts +15 -3
- package/dist/docx/headerFooterRefParser.js +51 -14
- package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
- package/dist/docx/headerFooterReferenceNormalization.js +5 -1
- package/dist/docx/hyperlinkParser.js +11 -15
- package/dist/docx/imageParser.d.ts +1 -1
- package/dist/docx/imageParser.js +22 -18
- package/dist/docx/imageRawXml.js +5 -5
- package/dist/docx/markupRangeMarker.d.ts +15 -0
- package/dist/docx/markupRangeMarker.js +44 -0
- package/dist/docx/noteReferenceStyles.d.ts +29 -0
- package/dist/docx/noteReferenceStyles.js +70 -0
- package/dist/docx/numberingParser.js +2 -1
- package/dist/docx/numberingReference.d.ts +21 -0
- package/dist/docx/numberingReference.js +21 -0
- package/dist/docx/numberingReferenceNormalization.d.ts +14 -2
- package/dist/docx/numberingReferenceNormalization.js +51 -9
- package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
- package/dist/docx/paragraphParser.js +69 -101
- package/dist/docx/paragraphPropertySource.js +1 -0
- package/dist/docx/paragraphTraversal.d.ts +37 -1
- package/dist/docx/paragraphTraversal.js +84 -1
- package/dist/docx/parseContext.d.ts +37 -0
- package/dist/docx/parseContext.js +67 -0
- package/dist/docx/parseWarningMessage.d.ts +6 -0
- package/dist/docx/parseWarningMessage.js +44 -0
- package/dist/docx/parser.js +86 -24
- package/dist/docx/relsParser.d.ts +28 -11
- package/dist/docx/relsParser.js +26 -13
- package/dist/docx/revisionIdNormalization.js +81 -7
- package/dist/docx/rezip.js +85 -27
- package/dist/docx/runConsolidator.js +1 -2
- package/dist/docx/runParser.d.ts +8 -1
- package/dist/docx/runParser.js +30 -48
- package/dist/docx/sectionParser.d.ts +2 -1
- package/dist/docx/sectionParser.js +21 -65
- package/dist/docx/serializer/borderSerializer.d.ts +1 -2
- package/dist/docx/serializer/commentSerializer.js +22 -9
- package/dist/docx/serializer/documentSerializer.d.ts +1 -5
- package/dist/docx/serializer/documentSerializer.js +6 -16
- package/dist/docx/serializer/headerFooterSerializer.js +5 -0
- package/dist/docx/serializer/markupRangeAttributes.d.ts +8 -0
- package/dist/docx/serializer/markupRangeAttributes.js +24 -0
- package/dist/docx/serializer/noteSerializer.js +5 -0
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
- package/dist/docx/serializer/paragraphSerializer.js +29 -35
- package/dist/docx/serializer/runSerializer.js +13 -7
- package/dist/docx/serializer/tableSerializer.js +28 -13
- package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
- package/dist/docx/server/build.js +8 -1
- package/dist/docx/server/createBilingualDocument.js +15 -22
- package/dist/docx/server/extractDocxText.js +3 -4
- package/dist/docx/shadingParser.d.ts +6 -0
- package/dist/docx/shadingParser.js +32 -0
- package/dist/docx/shapeParser.js +3 -3
- package/dist/docx/styleParser.js +15 -89
- package/dist/docx/styleReferenceResolution.d.ts +36 -0
- package/dist/docx/styleReferenceResolution.js +51 -0
- package/dist/docx/tableLook.d.ts +57 -0
- package/dist/docx/tableLook.js +63 -0
- package/dist/docx/tableParser.d.ts +7 -9
- package/dist/docx/tableParser.js +64 -110
- package/dist/docx/textBoxParser.js +4 -4
- package/dist/docx/trackedMoveRangeNormalization.d.ts +3 -1
- package/dist/docx/trackedMoveRangeNormalization.js +11 -21
- package/dist/docx/transitionalSpelling.d.ts +13 -2
- package/dist/docx/transitionalSpelling.js +23 -1
- package/dist/docx/verbatimCapture.js +4 -11
- package/dist/docx/vmlImageParser.js +2 -2
- package/dist/docx/watermarkParser.js +2 -2
- package/dist/docx/xmlParser.d.ts +22 -32
- package/dist/docx/xmlParser.js +36 -21
- package/dist/index.d.ts +2 -2
- package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +2 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +9 -6
- package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
- package/dist/internal/paragraphFormattingSerialization.js +26 -6
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
- package/dist/layout-bridge/convert/templatePreviewFlow.d.ts +19 -11
- package/dist/layout-bridge/convert/templatePreviewFlow.js +103 -38
- package/dist/layout-bridge/convert/toFlowBlocks.js +12 -3
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/measure/measureBlocks.js +1 -6
- package/dist/layout-engine/types.d.ts +8 -2
- package/dist/layout-engine/types.js +35 -2
- package/dist/markdown/index.js +1 -1
- package/dist/markdown/internals.d.ts +6 -1
- package/dist/markdown/internals.js +14 -1
- package/dist/markdown/renderBlock.js +35 -21
- package/dist/markdown/renderParagraph.js +14 -5
- package/dist/markdown/renderRuns.js +4 -3
- package/dist/markdown/renderTable.js +4 -3
- package/dist/markdown/trailers.js +41 -7
- package/dist/markdown/types.d.ts +3 -7
- package/dist/prosemirror/attrs/index.js +2 -5
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
- package/dist/prosemirror/commands/index.d.ts +3 -3
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/pageBreak.js +12 -1
- package/dist/prosemirror/commands/paragraph.d.ts +3 -3
- package/dist/prosemirror/commands/paragraph.js +2 -2
- package/dist/prosemirror/commentIdAllocator.js +2 -7
- package/dist/prosemirror/conversion/fromProseDoc.js +131 -41
- package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
- package/dist/prosemirror/conversion/toProseDoc.js +402 -328
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +14 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +11 -6
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -3
- package/dist/prosemirror/extensions/features/ListExtension.js +42 -4
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.d.ts +7 -0
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +74 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +11 -3
- package/dist/prosemirror/extensions/marks/markUtils.js +98 -19
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +7 -3
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
- package/dist/prosemirror/extensions/types.d.ts +2 -2
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/index.js +3 -3
- package/dist/prosemirror/insertOperations.d.ts +9 -2
- package/dist/prosemirror/insertOperations.js +9 -4
- package/dist/prosemirror/listMarker.js +2 -1
- package/dist/prosemirror/numberedRefFields.js +2 -1
- package/dist/prosemirror/pageBreakRunProjection.d.ts +11 -3
- package/dist/prosemirror/pageBreakRunProjection.js +16 -8
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +159 -0
- package/dist/prosemirror/paragraphFormattingProvenance.js +106 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +9 -1
- package/dist/prosemirror/plugins/documentStyles.js +11 -1
- package/dist/prosemirror/plugins/index.d.ts +2 -2
- package/dist/prosemirror/plugins/index.js +2 -2
- package/dist/prosemirror/plugins/revisionIds.d.ts +11 -2
- package/dist/prosemirror/plugins/revisionIds.js +21 -6
- package/dist/prosemirror/plugins/templatePreviewValues.d.ts +42 -1
- package/dist/prosemirror/plugins/templatePreviewValues.js +217 -14
- package/dist/prosemirror/runFormattingReconciliation.js +3 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +31 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +4 -1
- package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
- package/dist/prosemirror/styles/styleResolver.js +15 -6
- package/dist/prosemirror/utils/visualLineNavigation.d.ts +22 -2
- package/dist/prosemirror/utils/visualLineNavigation.js +80 -63
- package/dist/style-engine/styleEngine.d.ts +4 -1
- package/dist/style-engine/styleEngine.js +3 -0
- package/dist/style-sets/extract.js +35 -11
- package/dist/style-sets/stellaStyle.js +46 -39
- package/dist/style-sets/styleSetNormalization.d.ts +19 -0
- package/dist/style-sets/styleSetNormalization.js +99 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/createDocument.js +145 -20
- package/dist/utils/headingCollector.d.ts +8 -5
- package/dist/utils/headingCollector.js +23 -25
- package/dist/utils/tableOfContentsStyle.js +9 -2
- package/package.json +3 -2
- package/dist/docx/textWhitespace.d.ts +0 -4
- package/dist/docx/textWhitespace.js +0 -4
- package/dist/layout-bridge/engine/tableWidthUtils.d.ts +0 -6
- package/dist/layout-bridge/engine/tableWidthUtils.js +0 -25
- package/dist/markdown/headings.d.ts +0 -13
- package/dist/markdown/headings.js +0 -20
package/dist/docx/parser.js
CHANGED
|
@@ -1,34 +1,39 @@
|
|
|
1
1
|
import { toArrayBuffer } from "../utils/docxInput.js";
|
|
2
2
|
import { loadFontsWithMapping } from "../utils/fontLoader.js";
|
|
3
3
|
import { MAX_PACKAGE_TIFF_PIXELS, convertTiffToPngDataUrl, isTiffMimeType } from "../utils/tiffConverter.js";
|
|
4
|
+
import { DUPLICATE_COMMENT_ID_WARNING, normalizeCommentIds } from "./commentIdNormalization.js";
|
|
4
5
|
import { parseComments } from "./commentParser.js";
|
|
5
|
-
import { normalizeCommentReferences } from "./commentReferenceNormalization.js";
|
|
6
|
+
import { DANGLING_COMMENT_REFERENCE_WARNING, UNBALANCED_COMMENT_RANGE_WARNING, normalizeCommentReferences } from "./commentReferenceNormalization.js";
|
|
6
7
|
import { detectDocxConformanceClass } from "./conformance.js";
|
|
7
8
|
import { parseCoreProperties } from "./corePropertiesParser.js";
|
|
9
|
+
import { countDanglingRelationshipReferences } from "./danglingRelationshipReferences.js";
|
|
8
10
|
import { extractAllTemplateVariables, parseDocumentBody } from "./documentParser.js";
|
|
9
11
|
import { normalizeDrawingIds } from "./drawingIdNormalization.js";
|
|
10
12
|
import { DocxEncryptionError } from "./encryption/errors.js";
|
|
11
13
|
import { parseFontTable } from "./fontTableParser.js";
|
|
12
14
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
13
15
|
import { parseFooter, parseHeader } from "./headerFooterParser.js";
|
|
14
|
-
import { normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
|
|
16
|
+
import { DANGLING_FOOTER_REFERENCE_WARNING, DANGLING_HEADER_REFERENCE_WARNING, normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
|
|
15
17
|
import { assignHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint } from "./headerFooterVerbatim.js";
|
|
16
18
|
import { extractMetafileRaster, isMetafileMimeType } from "./metafileRaster.js";
|
|
17
19
|
import { renderEmfSvg } from "./metafileSvg.js";
|
|
18
20
|
import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
|
|
19
21
|
import { parseNumbering } from "./numberingParser.js";
|
|
20
|
-
import { normalizeNumberingReferences } from "./numberingReferenceNormalization.js";
|
|
22
|
+
import { UNNUMBERED_PARAGRAPH_WARNING, UNNUMBERED_STYLE_WARNING, normalizeNumberingReferences, normalizeStyleNumberingReferences } from "./numberingReferenceNormalization.js";
|
|
21
23
|
import { assignDocumentParagraphPropertySourceContract } from "./paragraphPropertySource.js";
|
|
24
|
+
import { createParseWarningCollector } from "./parseContext.js";
|
|
25
|
+
import { formatParseWarnings } from "./parseWarningMessage.js";
|
|
22
26
|
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
23
27
|
import { normalizeRenderedPageBreakHints } from "./renderedPageBreakNormalization.js";
|
|
24
28
|
import { parseSettings } from "./settingsParser.js";
|
|
25
29
|
import { parseStylesPackage } from "./styleParser.js";
|
|
26
30
|
import { applyThemeFontLang, parseTheme } from "./themeParser.js";
|
|
27
|
-
import { normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
|
|
31
|
+
import { UNBALANCED_MOVE_RANGE_WARNING, normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
|
|
28
32
|
import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
|
|
29
33
|
import { enforcePackageVmlPreviewBudget } from "./vmlPreview.js";
|
|
30
34
|
import { FOLIO_XML_RESOURCE_LIMITS } from "./xmlResourceLimits.js";
|
|
31
35
|
import { TaggedError } from "better-result";
|
|
36
|
+
import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
|
|
32
37
|
//#region src/docx/parser.ts
|
|
33
38
|
/**
|
|
34
39
|
* Main Parser Orchestrator - Unified parseDocx function
|
|
@@ -69,7 +74,7 @@ const sha256Hex = async (buffer) => {
|
|
|
69
74
|
async function parseDocx(input, options = {}) {
|
|
70
75
|
const buffer = input instanceof ArrayBuffer ? input : await toArrayBuffer(input);
|
|
71
76
|
const { onProgress = () => {}, preloadFonts = true, parseHeadersFooters = true, parseNotes = true, detectVariables = true, password, unzipLimits, mediaResolver } = options;
|
|
72
|
-
const warnings =
|
|
77
|
+
const { context: parseContext, warnings: collectedWarnings } = createParseWarningCollector();
|
|
73
78
|
try {
|
|
74
79
|
const timeStage = (_name, fn) => fn();
|
|
75
80
|
const timeStageAsync = async (_name, fn) => await fn();
|
|
@@ -80,8 +85,11 @@ async function parseDocx(input, options = {}) {
|
|
|
80
85
|
password,
|
|
81
86
|
extractAllXml: false
|
|
82
87
|
}));
|
|
83
|
-
if (raw.wasEncrypted)
|
|
84
|
-
|
|
88
|
+
if (raw.wasEncrypted) parseContext.warn({ code: PARSE_WARNING_CODES.packageDecrypted });
|
|
89
|
+
for (const message of raw.warnings) parseContext.warn({
|
|
90
|
+
code: PARSE_WARNING_CODES.packageArchive,
|
|
91
|
+
detail: message
|
|
92
|
+
});
|
|
85
93
|
onProgress("Extracted DOCX", 10);
|
|
86
94
|
onProgress("Parsing relationships...", 10);
|
|
87
95
|
const rels = timeStage("relationships", () => raw.documentRels ? parseRelationships(raw.documentRels) : /* @__PURE__ */ new Map());
|
|
@@ -113,8 +121,8 @@ async function parseDocx(input, options = {}) {
|
|
|
113
121
|
onProgress("Parsing document body...", 40);
|
|
114
122
|
let documentBody = { content: [] };
|
|
115
123
|
timeStage("documentBody", () => {
|
|
116
|
-
if (raw.documentXml) documentBody = parseDocumentBody(raw.documentXml, styles, theme, numbering, rels, media);
|
|
117
|
-
else
|
|
124
|
+
if (raw.documentXml) documentBody = parseDocumentBody(raw.documentXml, styles, theme, numbering, rels, media, parseContext.scoped({ part: "word/document.xml" }));
|
|
125
|
+
else parseContext.warn({ code: PARSE_WARNING_CODES.documentPartMissing });
|
|
118
126
|
});
|
|
119
127
|
onProgress("Parsed document body", 55);
|
|
120
128
|
let headers;
|
|
@@ -130,13 +138,19 @@ async function parseDocx(input, options = {}) {
|
|
|
130
138
|
let endnotes;
|
|
131
139
|
if (parseNotes) {
|
|
132
140
|
onProgress("Parsing footnotes/endnotes...", 65);
|
|
133
|
-
const notes = timeStage("footnotesEndnotes", () => parseNotesContent(raw, styles, theme, numbering, rels, media));
|
|
141
|
+
const notes = timeStage("footnotesEndnotes", () => parseNotesContent(raw, styles, theme, numbering, rels, media, parseContext));
|
|
134
142
|
footnotes = notes.footnotes;
|
|
135
143
|
endnotes = notes.endnotes;
|
|
136
144
|
onProgress("Parsed footnotes/endnotes", 75);
|
|
137
145
|
} else onProgress("Skipping footnotes/endnotes", 75);
|
|
138
146
|
onProgress("Parsing comments...", 75);
|
|
139
|
-
const
|
|
147
|
+
const commentsContext = parseContext.scoped({ part: "word/comments.xml" });
|
|
148
|
+
const comments = timeStage("comments", () => parseComments(raw.commentsXml, styles, theme, rels, media, raw.commentsExtensibleXml, raw.commentsExtendedXml, commentsContext));
|
|
149
|
+
const commentIdNormalization = normalizeCommentIds(comments);
|
|
150
|
+
if (commentIdNormalization.droppedDuplicateComments > 0) commentsContext.warn({
|
|
151
|
+
code: DUPLICATE_COMMENT_ID_WARNING,
|
|
152
|
+
count: commentIdNormalization.droppedDuplicateComments
|
|
153
|
+
});
|
|
140
154
|
if (comments.length > 0) documentBody.comments = comments;
|
|
141
155
|
normalizeDrawingIds({
|
|
142
156
|
documentBody,
|
|
@@ -162,15 +176,27 @@ async function parseDocx(input, options = {}) {
|
|
|
162
176
|
...footnotes !== void 0 ? { footnotes } : {},
|
|
163
177
|
...endnotes !== void 0 ? { endnotes } : {}
|
|
164
178
|
});
|
|
165
|
-
if (commentReferenceNormalization.removedDanglingReferences > 0)
|
|
166
|
-
|
|
179
|
+
if (commentReferenceNormalization.removedDanglingReferences > 0) parseContext.warn({
|
|
180
|
+
code: DANGLING_COMMENT_REFERENCE_WARNING,
|
|
181
|
+
count: commentReferenceNormalization.removedDanglingReferences
|
|
182
|
+
});
|
|
183
|
+
if (commentReferenceNormalization.reanchoredUnbalancedRanges > 0) parseContext.warn({
|
|
184
|
+
code: UNBALANCED_COMMENT_RANGE_WARNING,
|
|
185
|
+
count: commentReferenceNormalization.reanchoredUnbalancedRanges
|
|
186
|
+
});
|
|
167
187
|
const headerFooterReferenceNormalization = normalizeHeaderFooterReferences({
|
|
168
188
|
documentBody,
|
|
169
189
|
...headers !== void 0 ? { headers } : {},
|
|
170
190
|
...footers !== void 0 ? { footers } : {}
|
|
171
191
|
});
|
|
172
|
-
if (headerFooterReferenceNormalization.removedDanglingHeaderReferences > 0)
|
|
173
|
-
|
|
192
|
+
if (headerFooterReferenceNormalization.removedDanglingHeaderReferences > 0) parseContext.warn({
|
|
193
|
+
code: DANGLING_HEADER_REFERENCE_WARNING,
|
|
194
|
+
count: headerFooterReferenceNormalization.removedDanglingHeaderReferences
|
|
195
|
+
});
|
|
196
|
+
if (headerFooterReferenceNormalization.removedDanglingFooterReferences > 0) parseContext.warn({
|
|
197
|
+
code: DANGLING_FOOTER_REFERENCE_WARNING,
|
|
198
|
+
count: headerFooterReferenceNormalization.removedDanglingFooterReferences
|
|
199
|
+
});
|
|
174
200
|
const numberingReferenceNormalization = normalizeNumberingReferences({
|
|
175
201
|
documentBody,
|
|
176
202
|
numbering,
|
|
@@ -179,7 +205,33 @@ async function parseDocx(input, options = {}) {
|
|
|
179
205
|
...footnotes !== void 0 ? { footnotes } : {},
|
|
180
206
|
...endnotes !== void 0 ? { endnotes } : {}
|
|
181
207
|
});
|
|
182
|
-
if (numberingReferenceNormalization.
|
|
208
|
+
if (numberingReferenceNormalization.unnumberedDanglingReferences > 0) parseContext.warn({
|
|
209
|
+
code: UNNUMBERED_PARAGRAPH_WARNING,
|
|
210
|
+
count: numberingReferenceNormalization.unnumberedDanglingReferences
|
|
211
|
+
});
|
|
212
|
+
const styleNumberingNormalization = normalizeStyleNumberingReferences({
|
|
213
|
+
styles: styleDefinitions?.styles ?? [],
|
|
214
|
+
numbering
|
|
215
|
+
});
|
|
216
|
+
for (const styleId of styleNumberingNormalization.unnumberedStyleIds) parseContext.warn({
|
|
217
|
+
code: UNNUMBERED_STYLE_WARNING,
|
|
218
|
+
value: styleId,
|
|
219
|
+
at: `style "${styleId}"`
|
|
220
|
+
});
|
|
221
|
+
const danglingReferences = countDanglingRelationshipReferences({
|
|
222
|
+
content: documentBody.content,
|
|
223
|
+
relationships: rels
|
|
224
|
+
});
|
|
225
|
+
if (danglingReferences.drawings > 0) parseContext.warn({
|
|
226
|
+
code: PARSE_WARNING_CODES.danglingRelationshipId,
|
|
227
|
+
element: "w:drawing",
|
|
228
|
+
count: danglingReferences.drawings
|
|
229
|
+
});
|
|
230
|
+
if (danglingReferences.hyperlinks > 0) parseContext.warn({
|
|
231
|
+
code: PARSE_WARNING_CODES.danglingRelationshipId,
|
|
232
|
+
element: "w:hyperlink",
|
|
233
|
+
count: danglingReferences.hyperlinks
|
|
234
|
+
});
|
|
183
235
|
const trackedMoveRangeNormalization = normalizeTrackedMoveRanges({
|
|
184
236
|
documentBody,
|
|
185
237
|
...headers !== void 0 ? { headers } : {},
|
|
@@ -187,7 +239,10 @@ async function parseDocx(input, options = {}) {
|
|
|
187
239
|
...footnotes !== void 0 ? { footnotes } : {},
|
|
188
240
|
...endnotes !== void 0 ? { endnotes } : {}
|
|
189
241
|
});
|
|
190
|
-
if (trackedMoveRangeNormalization.removedUnbalancedMoveRangeMarkers > 0)
|
|
242
|
+
if (trackedMoveRangeNormalization.removedUnbalancedMoveRangeMarkers > 0) parseContext.warn({
|
|
243
|
+
code: UNBALANCED_MOVE_RANGE_WARNING,
|
|
244
|
+
count: trackedMoveRangeNormalization.removedUnbalancedMoveRangeMarkers
|
|
245
|
+
});
|
|
191
246
|
let templateVariables;
|
|
192
247
|
if (detectVariables) {
|
|
193
248
|
onProgress("Detecting template variables...", 75);
|
|
@@ -230,8 +285,15 @@ async function parseDocx(input, options = {}) {
|
|
|
230
285
|
const validation = validateFolioDocumentModel(document);
|
|
231
286
|
const parsedCompleteModel = parseHeadersFooters && parseNotes;
|
|
232
287
|
if (!validation.valid && parsedCompleteModel) throw new DocxModelValidationError("Parsed DOCX produced an invalid document model", validation.issues);
|
|
233
|
-
|
|
234
|
-
|
|
288
|
+
for (const issue of formatDocumentModelIssues(validation.issues)) parseContext.warn({
|
|
289
|
+
code: PARSE_WARNING_CODES.documentModelIssue,
|
|
290
|
+
detail: issue
|
|
291
|
+
});
|
|
292
|
+
const parseWarnings = collectedWarnings();
|
|
293
|
+
if (parseWarnings.length > 0) {
|
|
294
|
+
document.parseWarnings = parseWarnings;
|
|
295
|
+
document.warnings = formatParseWarnings(parseWarnings);
|
|
296
|
+
}
|
|
235
297
|
onProgress("Complete", 100);
|
|
236
298
|
return document;
|
|
237
299
|
} catch (error) {
|
|
@@ -410,7 +472,7 @@ function parseHeadersAndFooters(raw, styles, theme, numbering, rels, media) {
|
|
|
410
472
|
if (headerXml) {
|
|
411
473
|
const headerRelsPath = getRelationshipsPathForPart(partPath);
|
|
412
474
|
const headerRelsXml = getMapCaseInsensitive(raw.allXml, headerRelsPath);
|
|
413
|
-
const headerRels = headerRelsXml ? parseRelationships(headerRelsXml) :
|
|
475
|
+
const headerRels = headerRelsXml ? parseRelationships(headerRelsXml) : /* @__PURE__ */ new Map();
|
|
414
476
|
const header = parseHeader(headerXml, "default", styles, theme, numbering, headerRels, media);
|
|
415
477
|
const watermark = header.watermark;
|
|
416
478
|
if (watermark?.kind === "picture") {
|
|
@@ -429,7 +491,7 @@ function parseHeadersAndFooters(raw, styles, theme, numbering, rels, media) {
|
|
|
429
491
|
if (footerXml) {
|
|
430
492
|
const footerRelsPath = getRelationshipsPathForPart(partPath);
|
|
431
493
|
const footerRelsXml = getMapCaseInsensitive(raw.allXml, footerRelsPath);
|
|
432
|
-
const footer = parseFooter(footerXml, "default", styles, theme, numbering, footerRelsXml ? parseRelationships(footerRelsXml) :
|
|
494
|
+
const footer = parseFooter(footerXml, "default", styles, theme, numbering, footerRelsXml ? parseRelationships(footerRelsXml) : /* @__PURE__ */ new Map(), media);
|
|
433
495
|
footers.set(rId, footer);
|
|
434
496
|
}
|
|
435
497
|
}
|
|
@@ -441,13 +503,13 @@ function parseHeadersAndFooters(raw, styles, theme, numbering, rels, media) {
|
|
|
441
503
|
/**
|
|
442
504
|
* Parse footnotes and endnotes from raw content
|
|
443
505
|
*/
|
|
444
|
-
function parseNotesContent(raw, styles, theme, numbering, rels, media) {
|
|
506
|
+
function parseNotesContent(raw, styles, theme, numbering, rels, media, context) {
|
|
445
507
|
const relsForNotePart = (partPath) => {
|
|
446
508
|
const xml = getMapCaseInsensitive(raw.allXml, getRelationshipsPathForPart(partPath));
|
|
447
509
|
return xml ? parseRelationships(xml) : rels;
|
|
448
510
|
};
|
|
449
|
-
const footnoteMap = parseFootnotes(raw.footnotesXml, styles, theme, numbering, relsForNotePart("word/footnotes.xml"), media);
|
|
450
|
-
const endnoteMap = parseEndnotes(raw.endnotesXml, styles, theme, numbering, relsForNotePart("word/endnotes.xml"), media);
|
|
511
|
+
const footnoteMap = parseFootnotes(raw.footnotesXml, styles, theme, numbering, relsForNotePart("word/footnotes.xml"), media, context?.scoped({ part: "word/footnotes.xml" }));
|
|
512
|
+
const endnoteMap = parseEndnotes(raw.endnotesXml, styles, theme, numbering, relsForNotePart("word/endnotes.xml"), media, context?.scoped({ part: "word/endnotes.xml" }));
|
|
451
513
|
return {
|
|
452
514
|
footnotes: footnoteMap.getNormalFootnotes(),
|
|
453
515
|
endnotes: endnoteMap.getNormalEndnotes()
|
|
@@ -107,21 +107,38 @@ declare function getHeaders(map: document_d_exports.RelationshipMap): document_d
|
|
|
107
107
|
*/
|
|
108
108
|
declare function getFooters(map: document_d_exports.RelationshipMap): document_d_exports.Relationship[];
|
|
109
109
|
/**
|
|
110
|
-
*
|
|
110
|
+
* What a relationship id names.
|
|
111
|
+
*
|
|
112
|
+
* The three cases are kept apart because collapsing any of them into a string
|
|
113
|
+
* turns absence into a lookup key: an id the author never wrote, an id whose
|
|
114
|
+
* target the package no longer holds, and an id that resolves are different
|
|
115
|
+
* facts, and only the last one may be read as a part.
|
|
116
|
+
*/
|
|
117
|
+
type RelationshipResolution = {
|
|
118
|
+
status: "resolved";
|
|
119
|
+
relationship: document_d_exports.Relationship;
|
|
120
|
+
} | {
|
|
121
|
+
status: "absent";
|
|
122
|
+
} | {
|
|
123
|
+
status: "dangling";
|
|
124
|
+
id: string;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Resolve a relationship id against a relationship map.
|
|
111
128
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
129
|
+
* The only sanctioned way to turn an `r:id`, `r:embed` or `r:link` into a part.
|
|
130
|
+
* An empty attribute is absence, not an id: `ST_RelationshipId` is an NCName,
|
|
131
|
+
* so `""` can never name a relationship, and no map can hold it as a key.
|
|
115
132
|
*/
|
|
116
|
-
declare function
|
|
133
|
+
declare function resolveRelationshipId(map: document_d_exports.RelationshipMap | null | undefined, rId: string | undefined): RelationshipResolution;
|
|
117
134
|
/**
|
|
118
|
-
* Resolve a relationship
|
|
135
|
+
* Resolve a relationship id and require it to name a relationship of one type.
|
|
119
136
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
137
|
+
* A reference of the wrong type is reported as dangling: the part it names
|
|
138
|
+
* exists, but not as the thing the reference asked for, and reading it anyway
|
|
139
|
+
* is how a missing image comes back as `styles.xml`.
|
|
123
140
|
*/
|
|
124
|
-
declare function
|
|
141
|
+
declare function resolveRelationshipIdOfType(map: document_d_exports.RelationshipMap | null | undefined, rId: string | undefined, type: document_d_exports.RelationshipType): RelationshipResolution;
|
|
125
142
|
/**
|
|
126
143
|
* Resolve a relative target path to an absolute path within the DOCX
|
|
127
144
|
*
|
|
@@ -158,4 +175,4 @@ declare function parsePackageRelationships(relsXml: string): document_d_exports.
|
|
|
158
175
|
*/
|
|
159
176
|
declare function formatRelationships(map: document_d_exports.RelationshipMap): string;
|
|
160
177
|
//#endregion
|
|
161
|
-
export { RELATIONSHIP_TYPES, filterByType, formatRelationships, getFooters, getHeaders, getHyperlinks, getImages, getRelationshipTypeName, isExternalHyperlink, isFooterRelationship, isHeaderRelationship, isImageRelationship, parseDocumentRelationships, parsePackageRelationships, parseRelationships,
|
|
178
|
+
export { RELATIONSHIP_TYPES, RelationshipResolution, filterByType, formatRelationships, getFooters, getHeaders, getHyperlinks, getImages, getRelationshipTypeName, isExternalHyperlink, isFooterRelationship, isHeaderRelationship, isImageRelationship, parseDocumentRelationships, parsePackageRelationships, parseRelationships, resolveRelationshipId, resolveRelationshipIdOfType, resolveRelativePath };
|
package/dist/docx/relsParser.js
CHANGED
|
@@ -155,24 +155,37 @@ function getFooters(map) {
|
|
|
155
155
|
return filterByType(map, RELATIONSHIP_TYPES.footer);
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
|
-
* Resolve a relationship
|
|
158
|
+
* Resolve a relationship id against a relationship map.
|
|
159
159
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* The only sanctioned way to turn an `r:id`, `r:embed` or `r:link` into a part.
|
|
161
|
+
* An empty attribute is absence, not an id: `ST_RelationshipId` is an NCName,
|
|
162
|
+
* so `""` can never name a relationship, and no map can hold it as a key.
|
|
163
163
|
*/
|
|
164
|
-
function
|
|
165
|
-
|
|
164
|
+
function resolveRelationshipId(map, rId) {
|
|
165
|
+
if (rId === void 0 || rId.length === 0) return { status: "absent" };
|
|
166
|
+
const relationship = map?.get(rId);
|
|
167
|
+
return relationship === void 0 ? {
|
|
168
|
+
status: "dangling",
|
|
169
|
+
id: rId
|
|
170
|
+
} : {
|
|
171
|
+
status: "resolved",
|
|
172
|
+
relationship
|
|
173
|
+
};
|
|
166
174
|
}
|
|
167
175
|
/**
|
|
168
|
-
* Resolve a relationship
|
|
176
|
+
* Resolve a relationship id and require it to name a relationship of one type.
|
|
169
177
|
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
178
|
+
* A reference of the wrong type is reported as dangling: the part it names
|
|
179
|
+
* exists, but not as the thing the reference asked for, and reading it anyway
|
|
180
|
+
* is how a missing image comes back as `styles.xml`.
|
|
173
181
|
*/
|
|
174
|
-
function
|
|
175
|
-
|
|
182
|
+
function resolveRelationshipIdOfType(map, rId, type) {
|
|
183
|
+
const resolved = resolveRelationshipId(map, rId);
|
|
184
|
+
if (resolved.status !== "resolved" || resolved.relationship.type === type) return resolved;
|
|
185
|
+
return {
|
|
186
|
+
status: "dangling",
|
|
187
|
+
id: resolved.relationship.id
|
|
188
|
+
};
|
|
176
189
|
}
|
|
177
190
|
/**
|
|
178
191
|
* Resolve a relative target path to an absolute path within the DOCX
|
|
@@ -232,4 +245,4 @@ function formatRelationships(map) {
|
|
|
232
245
|
return lines.join("\n");
|
|
233
246
|
}
|
|
234
247
|
//#endregion
|
|
235
|
-
export { RELATIONSHIP_TYPES, filterByType, formatRelationships, getFooters, getHeaders, getHyperlinks, getImages, getRelationshipTypeName, isExternalHyperlink, isFooterRelationship, isHeaderRelationship, isImageRelationship, parseDocumentRelationships, parsePackageRelationships, parseRelationships,
|
|
248
|
+
export { RELATIONSHIP_TYPES, filterByType, formatRelationships, getFooters, getHeaders, getHyperlinks, getImages, getRelationshipTypeName, isExternalHyperlink, isFooterRelationship, isHeaderRelationship, isImageRelationship, parseDocumentRelationships, parsePackageRelationships, parseRelationships, resolveRelationshipId, resolveRelationshipIdOfType, resolveRelativePath };
|
|
@@ -31,16 +31,79 @@ const REVISION_ELEMENT_NAMES = /* @__PURE__ */ new Set([
|
|
|
31
31
|
"trPrChange"
|
|
32
32
|
]);
|
|
33
33
|
const REVISION_ELEMENT_CANDIDATE = new RegExp(`<(?:[^\\s<>/:]+:)?(?:${[...REVISION_ELEMENT_NAMES].join("|")})(?:[\\s/>])`, "u");
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The rest of the annotation id space.
|
|
36
|
+
*
|
|
37
|
+
* A comment, a bookmark, a protected range and a tracked change all draw their
|
|
38
|
+
* `w:id` from one space: Word allocates from a single counter, which is why a
|
|
39
|
+
* package carrying several kinds almost never repeats a value across them. So
|
|
40
|
+
* an id this pass mints must avoid these as well, or a renumbered `w:ins`
|
|
41
|
+
* lands on a live comment.
|
|
42
|
+
*
|
|
43
|
+
* They are only ever reserved, never claimed. A comment id legitimately
|
|
44
|
+
* appears four times (`w:comment`, both range markers and the reference) and a
|
|
45
|
+
* bookmark id twice, so feeding them to the uniqueness machinery would reject
|
|
46
|
+
* a package Word wrote. Their pairing is also why they are not revision
|
|
47
|
+
* elements: renumbering one end of a range would unpair it.
|
|
48
|
+
*/
|
|
49
|
+
const ANNOTATION_ELEMENT_NAMES = /* @__PURE__ */ new Set([
|
|
50
|
+
"bookmarkEnd",
|
|
51
|
+
"bookmarkStart",
|
|
52
|
+
"comment",
|
|
53
|
+
"commentRangeEnd",
|
|
54
|
+
"commentRangeStart",
|
|
55
|
+
"commentReference",
|
|
56
|
+
"customXmlDelRangeEnd",
|
|
57
|
+
"customXmlDelRangeStart",
|
|
58
|
+
"customXmlInsRangeEnd",
|
|
59
|
+
"customXmlInsRangeStart",
|
|
60
|
+
"customXmlMoveFromRangeEnd",
|
|
61
|
+
"customXmlMoveFromRangeStart",
|
|
62
|
+
"customXmlMoveToRangeEnd",
|
|
63
|
+
"customXmlMoveToRangeStart",
|
|
64
|
+
"moveFromRangeEnd",
|
|
65
|
+
"moveFromRangeStart",
|
|
66
|
+
"moveToRangeEnd",
|
|
67
|
+
"moveToRangeStart",
|
|
68
|
+
"permEnd",
|
|
69
|
+
"permStart"
|
|
70
|
+
]);
|
|
71
|
+
const ANNOTATION_ELEMENT_CANDIDATE = new RegExp(`<(?:[^\\s<>/:]+:)?(?:${[...ANNOTATION_ELEMENT_NAMES].join("|")})(?:[\\s/>])`, "u");
|
|
72
|
+
const ID_KINDS = {
|
|
73
|
+
revision: "revision",
|
|
74
|
+
annotation: "annotation"
|
|
75
|
+
};
|
|
76
|
+
/** One lookup for both halves of the space, so an element is classified once. */
|
|
77
|
+
const ID_KIND_BY_ELEMENT_NAME = new Map([...[...REVISION_ELEMENT_NAMES].map((name) => [name, ID_KINDS.revision]), ...[...ANNOTATION_ELEMENT_NAMES].map((name) => [name, ID_KINDS.annotation])]);
|
|
78
|
+
/**
|
|
79
|
+
* An element's `w:id` and which half of the annotation space it belongs to.
|
|
80
|
+
*
|
|
81
|
+
* One classifier rather than two, because it runs on every element of every
|
|
82
|
+
* scanned part: resolving the namespace and the local name twice to ask two
|
|
83
|
+
* questions measured 18% on a 17.6 MiB package.
|
|
84
|
+
*
|
|
85
|
+
* `w:permStart` types its id as a string, so a protected range named
|
|
86
|
+
* `everyone` yields nothing. That is correct: a value the allocator can never
|
|
87
|
+
* mint is not one it has to avoid.
|
|
88
|
+
*/
|
|
89
|
+
const identifiedElement = (element) => {
|
|
90
|
+
if (!element.name || !WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(element) ?? "")) return null;
|
|
91
|
+
const localName = getLocalName(element.name);
|
|
92
|
+
const kind = ID_KIND_BY_ELEMENT_NAME.get(localName);
|
|
93
|
+
if (kind === void 0) return null;
|
|
36
94
|
const attribute = findAttributeByNamespaceUri(element, WORDPROCESSINGML_NAMESPACE_URIS, "id");
|
|
37
95
|
if (!attribute) return null;
|
|
38
96
|
const id = Number(attribute.value);
|
|
39
97
|
return Number.isSafeInteger(id) && id >= 0 ? {
|
|
98
|
+
kind,
|
|
40
99
|
name: attribute.name,
|
|
41
100
|
id
|
|
42
101
|
} : null;
|
|
43
102
|
};
|
|
103
|
+
const revisionAttribute = (element) => {
|
|
104
|
+
const identified = identifiedElement(element);
|
|
105
|
+
return identified?.kind === ID_KINDS.revision ? identified : null;
|
|
106
|
+
};
|
|
44
107
|
/**
|
|
45
108
|
* Keep physical tracked-change element ids unique across a package.
|
|
46
109
|
*
|
|
@@ -57,11 +120,10 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
|
|
|
57
120
|
assertXmlResourceLimits(xml);
|
|
58
121
|
const ids = [];
|
|
59
122
|
if (rewriteStreamingXmlDecimalAttributes(xml, (element) => {
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
123
|
+
const identified = identifiedElement(element);
|
|
124
|
+
if (identified === null) return null;
|
|
125
|
+
if (identified.kind === ID_KINDS.revision) ids.push(identified.id);
|
|
126
|
+
reserved.add(identified.id);
|
|
65
127
|
return null;
|
|
66
128
|
}).status === "unsupported") throw new XmlResourceLimitError({
|
|
67
129
|
message: `Revision-id normalization could not safely scan ${path}`,
|
|
@@ -73,6 +135,18 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
|
|
|
73
135
|
const firstSeen = /* @__PURE__ */ new Set();
|
|
74
136
|
for (const [path, ids] of occurrencesByPath) for (const id of ids) if (firstSeen.has(id)) repeatedPaths.add(path);
|
|
75
137
|
else firstSeen.add(id);
|
|
138
|
+
if (repeatedPaths.size > 0) for (const [path, xml] of parts) {
|
|
139
|
+
if (occurrencesByPath.has(path) || !ANNOTATION_ELEMENT_CANDIDATE.test(xml)) continue;
|
|
140
|
+
assertXmlResourceLimits(xml);
|
|
141
|
+
if (rewriteStreamingXmlDecimalAttributes(xml, (element) => {
|
|
142
|
+
const identified = identifiedElement(element);
|
|
143
|
+
if (identified !== null) reserved.add(identified.id);
|
|
144
|
+
return null;
|
|
145
|
+
}).status === "unsupported") throw new XmlResourceLimitError({
|
|
146
|
+
message: `Revision-id normalization could not safely scan ${path}`,
|
|
147
|
+
limit: "syntax"
|
|
148
|
+
});
|
|
149
|
+
}
|
|
76
150
|
let nextId = 0;
|
|
77
151
|
const allocate = () => {
|
|
78
152
|
while (reserved.has(nextId)) nextId += 1;
|
package/dist/docx/rezip.js
CHANGED
|
@@ -7,9 +7,12 @@ import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
|
|
|
7
7
|
import { normalizeDrawingIds } from "./drawingIdNormalization.js";
|
|
8
8
|
import { rebindDrawingImageRelationship } from "./drawingRelationships.js";
|
|
9
9
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
10
|
+
import { parseHeaderFooterType } from "./headerFooterRefParser.js";
|
|
10
11
|
import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
11
12
|
import { isNewDataUrlDrawing } from "./newImage.js";
|
|
13
|
+
import { missingNoteReferenceStyles, noteReferenceNeeds } from "./noteReferenceStyles.js";
|
|
12
14
|
import { parseNumbering } from "./numberingParser.js";
|
|
15
|
+
import { isNumberingReference } from "./numberingReference.js";
|
|
13
16
|
import { isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries } from "./packageParts.js";
|
|
14
17
|
import { normalizeParaIdRangeInXmlParts } from "./paraIdRangeNormalization.js";
|
|
15
18
|
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
@@ -113,7 +116,7 @@ const extractHeaderFooterReferences = (xml) => {
|
|
|
113
116
|
const rId = getAttributeByNamespaceUri(node, OFFICE_RELATIONSHIP_NAMESPACE_URIS, "id");
|
|
114
117
|
if (rId) references.push({
|
|
115
118
|
element,
|
|
116
|
-
type: getAttributeByNamespaceUri(node, WORDPROCESSINGML_NAMESPACE_URIS, "type")
|
|
119
|
+
type: parseHeaderFooterType(getAttributeByNamespaceUri(node, WORDPROCESSINGML_NAMESPACE_URIS, "type")),
|
|
117
120
|
rId
|
|
118
121
|
});
|
|
119
122
|
}
|
|
@@ -1387,6 +1390,42 @@ async function serializeNumberingIntoZip(doc, originalZip, newZip, compressionLe
|
|
|
1387
1390
|
}
|
|
1388
1391
|
const STYLES_PART_PATH = "word/styles.xml";
|
|
1389
1392
|
const STYLES_CLOSE_ROOT = "</w:styles>";
|
|
1393
|
+
/**
|
|
1394
|
+
* The style table a package folio creates starts from: `docDefaults` and
|
|
1395
|
+
* `Normal`, and nothing else. A document that carries its own style table
|
|
1396
|
+
* replaces this part wholesale.
|
|
1397
|
+
*/
|
|
1398
|
+
const SEED_STYLES_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1399
|
+
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
1400
|
+
<w:docDefaults>
|
|
1401
|
+
<w:rPrDefault>
|
|
1402
|
+
<w:rPr>
|
|
1403
|
+
<w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/>
|
|
1404
|
+
<w:sz w:val="22"/>
|
|
1405
|
+
</w:rPr>
|
|
1406
|
+
</w:rPrDefault>
|
|
1407
|
+
<w:pPrDefault>
|
|
1408
|
+
<w:pPr>
|
|
1409
|
+
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
|
|
1410
|
+
</w:pPr>
|
|
1411
|
+
</w:pPrDefault>
|
|
1412
|
+
</w:docDefaults>
|
|
1413
|
+
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
|
|
1414
|
+
<w:name w:val="Normal"/>
|
|
1415
|
+
</w:style>
|
|
1416
|
+
</w:styles>`;
|
|
1417
|
+
/**
|
|
1418
|
+
* The seed part plus the reference styles this package's comments and notes
|
|
1419
|
+
* need. A document with no style table of its own never reaches
|
|
1420
|
+
* {@link styleDefinitionsToSerialize}, so without this its reference marks
|
|
1421
|
+
* would carry a `w:rStyle` naming nothing — the defect
|
|
1422
|
+
* `noteReferenceStyles.ts` exists to remove, on the one path that skips it.
|
|
1423
|
+
*/
|
|
1424
|
+
const seedStylesXmlWith = (missing) => {
|
|
1425
|
+
if (missing.length === 0) return SEED_STYLES_XML;
|
|
1426
|
+
const rootClose = SEED_STYLES_XML.lastIndexOf(STYLES_CLOSE_ROOT);
|
|
1427
|
+
return SEED_STYLES_XML.slice(0, rootClose) + missing.map(serializeStyle).join("") + SEED_STYLES_XML.slice(rootClose);
|
|
1428
|
+
};
|
|
1390
1429
|
const STYLE_ID_PATTERN = /<w:style\b[^>]*?\bw:styleId="(?<id>[^"]+)"/gu;
|
|
1391
1430
|
/**
|
|
1392
1431
|
* Append styles the model defines but the original `word/styles.xml` lacks.
|
|
@@ -1395,6 +1434,27 @@ const STYLE_ID_PATTERN = /<w:style\b[^>]*?\bw:styleId="(?<id>[^"]+)"/gu;
|
|
|
1395
1434
|
* per-language clones a bilingual transform adds, are emitted before the root
|
|
1396
1435
|
* close so paragraphs referencing them resolve on reopen.
|
|
1397
1436
|
*/
|
|
1437
|
+
/**
|
|
1438
|
+
* The styles to write into a package folio is authoring: the model's, plus any
|
|
1439
|
+
* reference character style the serializers are about to emit for this
|
|
1440
|
+
* package's comments and notes but the style table does not define. See
|
|
1441
|
+
* `noteReferenceStyles.ts` — the reference mark would otherwise carry a
|
|
1442
|
+
* `w:rStyle` pointing at nothing.
|
|
1443
|
+
*
|
|
1444
|
+
* Only for a package folio writes from scratch. Repacking a document someone
|
|
1445
|
+
* else authored preserves `word/styles.xml` byte for byte, and adding a
|
|
1446
|
+
* definition there would rewrite a part the user never edited: their document,
|
|
1447
|
+
* their style table, missing reference style included.
|
|
1448
|
+
*/
|
|
1449
|
+
const styleDefinitionsToSerialize = (doc) => {
|
|
1450
|
+
const styles = doc.package.styles;
|
|
1451
|
+
if (!styles) return;
|
|
1452
|
+
const missing = missingNoteReferenceStyles(styles, noteReferenceNeeds(doc.package));
|
|
1453
|
+
return missing.length === 0 ? styles : {
|
|
1454
|
+
...styles,
|
|
1455
|
+
styles: [...styles.styles, ...missing]
|
|
1456
|
+
};
|
|
1457
|
+
};
|
|
1398
1458
|
async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compressionLevel) {
|
|
1399
1459
|
const styles = doc.package.styles;
|
|
1400
1460
|
if (!styles || styles.styles.length === 0) return;
|
|
@@ -1576,25 +1636,7 @@ const createEmptyDocxZip = ({ creator, application }) => {
|
|
|
1576
1636
|
</w:sectPr>
|
|
1577
1637
|
</w:body>
|
|
1578
1638
|
</w:document>`);
|
|
1579
|
-
zip.file(
|
|
1580
|
-
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
1581
|
-
<w:docDefaults>
|
|
1582
|
-
<w:rPrDefault>
|
|
1583
|
-
<w:rPr>
|
|
1584
|
-
<w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/>
|
|
1585
|
-
<w:sz w:val="22"/>
|
|
1586
|
-
</w:rPr>
|
|
1587
|
-
</w:rPrDefault>
|
|
1588
|
-
<w:pPrDefault>
|
|
1589
|
-
<w:pPr>
|
|
1590
|
-
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
|
|
1591
|
-
</w:pPr>
|
|
1592
|
-
</w:pPrDefault>
|
|
1593
|
-
</w:docDefaults>
|
|
1594
|
-
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
|
|
1595
|
-
<w:name w:val="Normal"/>
|
|
1596
|
-
</w:style>
|
|
1597
|
-
</w:styles>`);
|
|
1639
|
+
zip.file(STYLES_PART_PATH, SEED_STYLES_XML);
|
|
1598
1640
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1599
1641
|
const creatorElement = creator === void 0 ? "" : `\n <dc:creator>${escapeXml(creator)}</dc:creator>`;
|
|
1600
1642
|
zip.file("docProps/core.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
@@ -1645,10 +1687,11 @@ const createDocumentSeedZip = async (doc, properties) => {
|
|
|
1645
1687
|
const relationships = ["<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>"];
|
|
1646
1688
|
const overrides = [];
|
|
1647
1689
|
let nextRelationshipId = 2;
|
|
1648
|
-
|
|
1690
|
+
const styleDefinitions = styleDefinitionsToSerialize(doc);
|
|
1691
|
+
if (styleDefinitions) {
|
|
1649
1692
|
assertStyleNumberingReferences(doc);
|
|
1650
|
-
zip.file(
|
|
1651
|
-
}
|
|
1693
|
+
zip.file(STYLES_PART_PATH, serializeStylesXml(styleDefinitions));
|
|
1694
|
+
} else zip.file(STYLES_PART_PATH, seedStylesXmlWith(missingNoteReferenceStyles(void 0, noteReferenceNeeds(doc.package))));
|
|
1652
1695
|
const numbering = doc.package.numbering;
|
|
1653
1696
|
if (numbering && (numbering.abstractNums.length > 0 || numbering.nums.length > 0)) {
|
|
1654
1697
|
zip.file("word/numbering.xml", serializeNumberingXml(numbering));
|
|
@@ -1684,17 +1727,32 @@ const createDocumentSeedZip = async (doc, properties) => {
|
|
|
1684
1727
|
};
|
|
1685
1728
|
const relationshipXml = (id, type, target) => `<Relationship Id="rId${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${target}"/>`;
|
|
1686
1729
|
const overrideXml = (partName, contentType) => `<Override PartName="${partName}" ContentType="${contentType}"/>`;
|
|
1730
|
+
/**
|
|
1731
|
+
* A package this build assembles from a Document must define the numbering its
|
|
1732
|
+
* styles name: Word reads a styles.xml reference nothing resolves as no
|
|
1733
|
+
* numbering at all, silently dropping the style's list.
|
|
1734
|
+
*
|
|
1735
|
+
* The panic is an invariant over Folio's own output, not input validation. A
|
|
1736
|
+
* source file can carry a dangling style reference, and it never arrives here:
|
|
1737
|
+
* `normalizeStyleNumberingReferences` rewrites one to the "no numbering"
|
|
1738
|
+
* sentinel at every boundary that mints a Document from user styles (`parseDocx`
|
|
1739
|
+
* and the style-set extraction entry points). What reaches this point is what
|
|
1740
|
+
* Folio itself put in the model, so a miss is a defect in Folio.
|
|
1741
|
+
*/
|
|
1687
1742
|
const assertStyleNumberingReferences = (doc) => {
|
|
1688
1743
|
const referenced = /* @__PURE__ */ new Set();
|
|
1689
1744
|
for (const style of doc.package.styles?.styles ?? []) {
|
|
1690
1745
|
const numId = style.pPr?.numPr?.numId;
|
|
1691
|
-
if (numId
|
|
1746
|
+
if (isNumberingReference(numId)) referenced.add(numId);
|
|
1692
1747
|
}
|
|
1693
1748
|
if (referenced.size === 0) return;
|
|
1694
|
-
const available = new
|
|
1695
|
-
for (const numId of referenced) if (!available.has(numId)) panic(`Style references missing numbering definition ${numId}`);
|
|
1749
|
+
const available = new Map(doc.package.numbering?.nums.map((numbering) => [numbering.numId, numbering]) ?? []);
|
|
1696
1750
|
const availableAbstract = new Set(doc.package.numbering?.abstractNums.map((numbering) => numbering.abstractNumId) ?? []);
|
|
1697
|
-
for (const
|
|
1751
|
+
for (const numId of referenced) {
|
|
1752
|
+
const numbering = available.get(numId);
|
|
1753
|
+
if (!numbering) panic(`Style references missing numbering definition ${numId}`);
|
|
1754
|
+
if (!availableAbstract.has(numbering.abstractNumId)) panic(`Numbering definition ${numbering.numId} references missing abstract numbering`);
|
|
1755
|
+
}
|
|
1698
1756
|
};
|
|
1699
1757
|
//#endregion
|
|
1700
1758
|
export { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_PART, COMMENTS_EXTENDED_PART_LOWER, DocxPackageFidelityError, addCommentsExtendedOverride, addCommentsExtendedRelationship, addMedia, addRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, collectHyperlinksWithoutRId, createDocx, createEmptyDocx, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedInlineResources, isDocxBuffer, notePartRelsPath, removeCommentsExtendedOverride, removeCommentsExtendedRelationship, repackDocx, repackDocxFromRaw, updateCoreProperties, updateDocumentXml, updateMultipleFiles, updateXmlFile, validateDocx, withoutAttachedTemplate };
|
|
@@ -114,8 +114,7 @@ function mergeRunContent(content1, content2) {
|
|
|
114
114
|
if (lastText?.type === "text" && firstText?.type === "text") {
|
|
115
115
|
result[result.length - 1] = {
|
|
116
116
|
type: "text",
|
|
117
|
-
text: lastText.text + firstText.text
|
|
118
|
-
...lastText.preserveSpace || firstText.preserveSpace ? { preserveSpace: true } : {}
|
|
117
|
+
text: lastText.text + firstText.text
|
|
119
118
|
};
|
|
120
119
|
for (let i = 1; i < content2.length; i++) result.push(content2[i]);
|
|
121
120
|
} else for (const c of content2) result.push(c);
|