@stll/folio-core 0.43.0 → 0.45.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/__fixtures__/paragraphs.js +2 -2
- package/dist/ai-edits/headless.js +7 -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 +94 -54
- package/dist/compare/inline-atoms.js +34 -20
- package/dist/compare/style-resources.js +6 -0
- package/dist/content-controls/mutateContentControls.js +4 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -8
- package/dist/document-operations.js +14 -3
- package/dist/docx/appVersionNormalization.d.ts +0 -18
- package/dist/docx/blockContentParser.js +8 -0
- 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 +3 -1
- package/dist/docx/commentIdNormalization.js +18 -1
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +80 -42
- package/dist/docx/commentReferenceNormalization.d.ts +4 -1
- package/dist/docx/commentReferenceNormalization.js +23 -14
- package/dist/docx/commentThreadKey.d.ts +18 -0
- package/dist/docx/commentThreadKey.js +22 -0
- package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
- package/dist/docx/danglingRelationshipReferences.js +30 -0
- package/dist/docx/defaultParagraphStyle.d.ts +18 -1
- package/dist/docx/defaultParagraphStyle.js +23 -1
- package/dist/docx/diagramPreview.js +87 -27
- 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 -4
- package/dist/docx/groupDrawingParser.js +4 -4
- package/dist/docx/headerFooterRefParser.d.ts +4 -3
- package/dist/docx/headerFooterRefParser.js +42 -12
- package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
- package/dist/docx/headerFooterReferenceNormalization.js +5 -1
- package/dist/docx/hyperlinkParser.js +13 -17
- package/dist/docx/imageParser.d.ts +10 -2
- package/dist/docx/imageParser.js +80 -30
- package/dist/docx/imageRawXml.d.ts +14 -1
- package/dist/docx/imageRawXml.js +35 -11
- package/dist/docx/markupRangeMarker.d.ts +15 -0
- package/dist/docx/markupRangeMarker.js +44 -0
- package/dist/docx/mathToMathml.js +12 -14
- package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
- package/dist/docx/nonVisualDrawingProps.js +46 -0
- package/dist/docx/noteReferenceStyles.d.ts +29 -0
- package/dist/docx/noteReferenceStyles.js +70 -0
- package/dist/docx/numberingReferenceNormalization.d.ts +4 -1
- package/dist/docx/numberingReferenceNormalization.js +20 -1
- package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
- package/dist/docx/paragraphParser.js +66 -99
- package/dist/docx/paragraphPropertySource.js +1 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +3 -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 +83 -29
- package/dist/docx/previewBudget.d.ts +64 -0
- package/dist/docx/previewBudget.js +88 -0
- package/dist/docx/relsParser.d.ts +28 -11
- package/dist/docx/relsParser.js +26 -13
- package/dist/docx/revisionIdNormalization.js +96 -10
- package/dist/docx/rezip.js +80 -40
- 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/sdtPropertiesPatch.js +24 -18
- package/dist/docx/sectionParser.d.ts +2 -1
- package/dist/docx/sectionParser.js +21 -65
- package/dist/docx/sectionReferenceHistory.js +2 -2
- package/dist/docx/selectiveSave.js +6 -6
- package/dist/docx/serializer/blockSdtSerializer.js +38 -26
- package/dist/docx/serializer/borderSerializer.d.ts +2 -3
- package/dist/docx/serializer/borderSerializer.js +13 -12
- package/dist/docx/serializer/commentSerializer.d.ts +41 -16
- package/dist/docx/serializer/commentSerializer.js +82 -72
- package/dist/docx/serializer/documentSerializer.d.ts +1 -5
- package/dist/docx/serializer/documentSerializer.js +6 -16
- package/dist/docx/serializer/fontTableSerializer.js +6 -6
- package/dist/docx/serializer/headerFooterSerializer.js +10 -5
- 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/numberingSerializer.js +7 -6
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
- package/dist/docx/serializer/paragraphSerializer.js +47 -52
- package/dist/docx/serializer/partNamespaces.js +2 -2
- package/dist/docx/serializer/runSerializer.js +57 -31
- package/dist/docx/serializer/sectionPropertiesSerializer.js +11 -10
- package/dist/docx/serializer/settingsSerializer.js +4 -3
- package/dist/docx/serializer/stylesSerializer.js +6 -6
- package/dist/docx/serializer/tableSerializer.js +37 -21
- package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
- package/dist/docx/serializer/textFormattingSerializer.js +29 -28
- package/dist/docx/serializer/themeSerializer.js +6 -6
- package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
- package/dist/docx/serializer/xmlUtils.d.ts +1 -2
- package/dist/docx/serializer/xmlUtils.js +1 -13
- package/dist/docx/server/boundedArchive.d.ts +12 -0
- package/dist/docx/server/boundedArchive.js +20 -1
- package/dist/docx/server/build.js +8 -1
- package/dist/docx/server/createBilingualDocument.js +10 -18
- package/dist/docx/server/extractDocxText.js +3 -4
- package/dist/docx/server/validateDocxConformance.js +22 -1
- package/dist/docx/shadingParser.d.ts +6 -0
- package/dist/docx/shadingParser.js +32 -0
- package/dist/docx/shapeParser.js +10 -8
- package/dist/docx/styleParser.js +13 -87
- 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 +11 -6
- 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/unzip.d.ts +23 -0
- package/dist/docx/unzip.js +32 -22
- package/dist/docx/verbatimCapture.js +5 -12
- package/dist/docx/vmlImageParser.js +5 -4
- package/dist/docx/vmlPreview.d.ts +1 -3
- package/dist/docx/vmlPreview.js +2 -30
- package/dist/docx/watermarkParser.js +2 -2
- package/dist/docx/xmlParser.d.ts +38 -33
- package/dist/docx/xmlParser.js +92 -47
- package/dist/docx/xmlResourceLimits.d.ts +89 -9
- package/dist/docx/xmlResourceLimits.js +105 -24
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
- package/dist/internal/paragraphFormattingSerialization.js +29 -8
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
- 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/layout-painter/renderImage.js +4 -3
- package/dist/layout-painter/renderParagraph.js +4 -3
- package/dist/managers/autoSaveCodec.js +2 -8
- package/dist/markdown/images.js +1 -4
- 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 +71 -5
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
- package/dist/prosemirror/commands/image.js +1 -0
- package/dist/prosemirror/commands/index.d.ts +3 -3
- package/dist/prosemirror/commands/index.js +2 -2
- 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 +197 -68
- package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
- package/dist/prosemirror/conversion/toProseDoc.js +458 -335
- 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/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/HyperlinkExtension.js +2 -3
- 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 +6 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +8 -2
- package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +8 -4
- 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/paragraphFormattingProvenance.d.ts +162 -0
- package/dist/prosemirror/paragraphFormattingProvenance.js +115 -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/runFormattingReconciliation.js +3 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +81 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
- package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
- package/dist/prosemirror/styles/styleResolver.js +12 -0
- package/dist/style-engine/styleEngine.d.ts +3 -0
- package/dist/style-engine/styleEngine.js +3 -0
- package/dist/style-sets/extract.js +1 -23
- 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/base64.d.ts +36 -0
- package/dist/utils/base64.js +40 -0
- package/dist/utils/clipboard.js +2 -1
- 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/dist/utils/units.d.ts +10 -1
- package/dist/utils/units.js +12 -1
- package/dist/utils/urlSecurity.d.ts +8 -2
- package/dist/utils/urlSecurity.js +21 -3
- package/package.json +2 -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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { ParseContext } from "./parseContext.js";
|
|
2
3
|
import { XmlElement } from "./xmlParser.js";
|
|
3
4
|
//#region src/docx/sectionParser.d.ts
|
|
4
5
|
declare function getUnserializedSectionPropertyChildNames(props: document_d_exports.SectionProperties): readonly string[] | undefined;
|
|
@@ -8,7 +9,7 @@ declare function getUnserializedSectionPropertyChildNames(props: document_d_expo
|
|
|
8
9
|
* @param sectPr - The w:sectPr element
|
|
9
10
|
* @returns SectionProperties object
|
|
10
11
|
*/
|
|
11
|
-
declare function parseSectionProperties(sectPr: XmlElement | null): document_d_exports.SectionProperties;
|
|
12
|
+
declare function parseSectionProperties(sectPr: XmlElement | null, context?: ParseContext): document_d_exports.SectionProperties;
|
|
12
13
|
/**
|
|
13
14
|
* Get page width in pixels (96 DPI)
|
|
14
15
|
*
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { parseBorderSpec } from "./borderParser.js";
|
|
1
2
|
import { parseFooterReference, parseHeaderReference } from "./headerFooterRefParser.js";
|
|
2
3
|
import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
|
|
3
|
-
import {
|
|
4
|
+
import { NumberFormatSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
4
5
|
import { parseSectionReferenceHistory } from "./sectionReferenceHistory.js";
|
|
5
6
|
import { parsePropertyChangeInfo } from "./trackedChangeInfo.js";
|
|
6
|
-
import { findChild, findChildren, getAttribute, getChildElements, getLocalName, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
7
|
+
import { findChild, findChildren, getAttribute, getChildElements, getLocalName, parseBooleanElement, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
|
|
7
8
|
//#region src/docx/sectionParser.ts
|
|
8
9
|
/**
|
|
9
10
|
* Sanity cap on `w:cols/@w:num`. Word's column picker tops out well below
|
|
@@ -49,49 +50,6 @@ function getUnserializedSectionPropertyChildNames(props) {
|
|
|
49
50
|
return Array.isArray(descriptor?.value) ? descriptor.value : void 0;
|
|
50
51
|
}
|
|
51
52
|
/**
|
|
52
|
-
* Parse a color element/attribute for page borders/background
|
|
53
|
-
*/
|
|
54
|
-
function parseColorValue(colorStr, themeColor, themeTint, themeShade) {
|
|
55
|
-
if (!colorStr && !themeColor) return;
|
|
56
|
-
const color = {};
|
|
57
|
-
if (colorStr && colorStr !== "auto") color.rgb = colorStr;
|
|
58
|
-
else if (colorStr === "auto") color.auto = true;
|
|
59
|
-
const validatedThemeColor = narrowEnum(themeColor, ThemeColorSlotSchema);
|
|
60
|
-
if (validatedThemeColor) color.themeColor = validatedThemeColor;
|
|
61
|
-
if (themeTint) color.themeTint = themeTint;
|
|
62
|
-
if (themeShade) color.themeShade = themeShade;
|
|
63
|
-
return Object.keys(color).length > 0 ? color : void 0;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Parse a border element for page borders
|
|
67
|
-
*/
|
|
68
|
-
function parseBorderSpec(element) {
|
|
69
|
-
if (!element) return;
|
|
70
|
-
const rawStyle = getAttribute(element, "w", "val") ?? "none";
|
|
71
|
-
const border = { style: narrowEnum(rawStyle, BorderStyleSchema) ?? rawStyle };
|
|
72
|
-
const sz = parseNumericAttribute(element, "w", "sz");
|
|
73
|
-
if (sz !== void 0) border.size = sz;
|
|
74
|
-
const space = parseNumericAttribute(element, "w", "space");
|
|
75
|
-
if (space !== void 0) border.space = space;
|
|
76
|
-
const color = parseColorValue(getAttribute(element, "w", "color"), getAttribute(element, "w", "themeColor"), getAttribute(element, "w", "themeTint"), getAttribute(element, "w", "themeShade"));
|
|
77
|
-
if (color) border.color = color;
|
|
78
|
-
const shadow = getAttribute(element, "w", "shadow");
|
|
79
|
-
if (shadow === "1" || shadow === "true") border.shadow = true;
|
|
80
|
-
const frame = getAttribute(element, "w", "frame");
|
|
81
|
-
if (frame === "1" || frame === "true") border.frame = true;
|
|
82
|
-
const artRelationshipId = getAttribute(element, "w", "id")?.trim();
|
|
83
|
-
if (artRelationshipId) border.artRelationshipId = artRelationshipId;
|
|
84
|
-
const topLeftArtRelationshipId = getAttribute(element, "w", "topLeft")?.trim();
|
|
85
|
-
if (topLeftArtRelationshipId) border.topLeftArtRelationshipId = topLeftArtRelationshipId;
|
|
86
|
-
const topRightArtRelationshipId = getAttribute(element, "w", "topRight")?.trim();
|
|
87
|
-
if (topRightArtRelationshipId) border.topRightArtRelationshipId = topRightArtRelationshipId;
|
|
88
|
-
const bottomLeftArtRelationshipId = getAttribute(element, "w", "bottomLeft")?.trim();
|
|
89
|
-
if (bottomLeftArtRelationshipId) border.bottomLeftArtRelationshipId = bottomLeftArtRelationshipId;
|
|
90
|
-
const bottomRightArtRelationshipId = getAttribute(element, "w", "bottomRight")?.trim();
|
|
91
|
-
if (bottomRightArtRelationshipId) border.bottomRightArtRelationshipId = bottomRightArtRelationshipId;
|
|
92
|
-
return border;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
53
|
* Parse page orientation
|
|
96
54
|
*/
|
|
97
55
|
function parseOrientation(orient) {
|
|
@@ -160,7 +118,7 @@ function parseLineNumberRestart(restart) {
|
|
|
160
118
|
* @param sectPr - The w:sectPr element
|
|
161
119
|
* @returns SectionProperties object
|
|
162
120
|
*/
|
|
163
|
-
function parseSectionProperties(sectPr) {
|
|
121
|
+
function parseSectionProperties(sectPr, context) {
|
|
164
122
|
const props = {};
|
|
165
123
|
if (!sectPr) return props;
|
|
166
124
|
const unhandledChildNames = getChildElements(sectPr).map((child) => getLocalName(child.name ?? "")).filter((name) => !serializedSectionPropertyChildNames.has(name));
|
|
@@ -199,11 +157,9 @@ function parseSectionProperties(sectPr) {
|
|
|
199
157
|
if (num !== void 0) props.columnCount = Math.min(num, MAX_SECTION_COLUMNS);
|
|
200
158
|
const space = parseNumericAttribute(cols, "w", "space");
|
|
201
159
|
if (space !== void 0) props.columnSpace = space;
|
|
202
|
-
const equalWidth =
|
|
203
|
-
if (equalWidth
|
|
204
|
-
|
|
205
|
-
const sep = getAttribute(cols, "w", "sep");
|
|
206
|
-
if (sep === "1" || sep === "true") props.separator = true;
|
|
160
|
+
const equalWidth = parseOnOffAttribute(cols, "w", "equalWidth");
|
|
161
|
+
if (equalWidth !== void 0) props.equalWidth = equalWidth;
|
|
162
|
+
if (parseOnOffAttribute(cols, "w", "sep") === true) props.separator = true;
|
|
207
163
|
const colElements = findChildren(cols, "w", "col");
|
|
208
164
|
if (colElements.length > 0) {
|
|
209
165
|
props.columns = [];
|
|
@@ -235,15 +191,15 @@ function parseSectionProperties(sectPr) {
|
|
|
235
191
|
else addUnhandledChildName("textDirection");
|
|
236
192
|
}
|
|
237
193
|
const bidi = findChild(sectPr, "w", "bidi");
|
|
238
|
-
if (bidi) props.bidi = parseBooleanElement(bidi);
|
|
239
|
-
const headerRefs = findChildren(sectPr, "w", "headerReference");
|
|
240
|
-
if (headerRefs.length > 0) props.headerReferences = headerRefs
|
|
241
|
-
const footerRefs = findChildren(sectPr, "w", "footerReference");
|
|
242
|
-
if (footerRefs.length > 0) props.footerReferences = footerRefs
|
|
194
|
+
if (bidi) props.bidi = parseBooleanElement(bidi, "w", context);
|
|
195
|
+
const headerRefs = findChildren(sectPr, "w", "headerReference").flatMap((el) => parseHeaderReference(el, context) ?? []);
|
|
196
|
+
if (headerRefs.length > 0) props.headerReferences = headerRefs;
|
|
197
|
+
const footerRefs = findChildren(sectPr, "w", "footerReference").flatMap((el) => parseFooterReference(el, context) ?? []);
|
|
198
|
+
if (footerRefs.length > 0) props.footerReferences = footerRefs;
|
|
243
199
|
const titlePg = findChild(sectPr, "w", "titlePg");
|
|
244
|
-
if (titlePg) props.titlePg = parseBooleanElement(titlePg);
|
|
200
|
+
if (titlePg) props.titlePg = parseBooleanElement(titlePg, "w", context);
|
|
245
201
|
const evenAndOddHeaders = findChild(sectPr, "w", "evenAndOddHeaders");
|
|
246
|
-
if (evenAndOddHeaders) props.evenAndOddHeaders = parseBooleanElement(evenAndOddHeaders);
|
|
202
|
+
if (evenAndOddHeaders) props.evenAndOddHeaders = parseBooleanElement(evenAndOddHeaders, "w", context);
|
|
247
203
|
const lnNumType = findChild(sectPr, "w", "lnNumType");
|
|
248
204
|
if (lnNumType) {
|
|
249
205
|
props.lineNumbers = {};
|
|
@@ -272,13 +228,13 @@ function parseSectionProperties(sectPr) {
|
|
|
272
228
|
const pgBorders = findChild(sectPr, "w", "pgBorders");
|
|
273
229
|
if (pgBorders) {
|
|
274
230
|
props.pageBorders = {};
|
|
275
|
-
const topBorder = parseBorderSpec(findChild(pgBorders, "w", "top"));
|
|
231
|
+
const topBorder = parseBorderSpec(findChild(pgBorders, "w", "top"), context);
|
|
276
232
|
if (topBorder) props.pageBorders.top = topBorder;
|
|
277
|
-
const bottomBorder = parseBorderSpec(findChild(pgBorders, "w", "bottom"));
|
|
233
|
+
const bottomBorder = parseBorderSpec(findChild(pgBorders, "w", "bottom"), context);
|
|
278
234
|
if (bottomBorder) props.pageBorders.bottom = bottomBorder;
|
|
279
|
-
const leftBorder = parseBorderSpec(findChild(pgBorders, "w", "left"));
|
|
235
|
+
const leftBorder = parseBorderSpec(findChild(pgBorders, "w", "left"), context);
|
|
280
236
|
if (leftBorder) props.pageBorders.left = leftBorder;
|
|
281
|
-
const rightBorder = parseBorderSpec(findChild(pgBorders, "w", "right"));
|
|
237
|
+
const rightBorder = parseBorderSpec(findChild(pgBorders, "w", "right"), context);
|
|
282
238
|
if (rightBorder) props.pageBorders.right = rightBorder;
|
|
283
239
|
const display = getAttribute(pgBorders, "w", "display");
|
|
284
240
|
if (display === "allPages" || display === "firstPage" || display === "notFirstPage") props.pageBorders.display = display;
|
|
@@ -315,11 +271,11 @@ function parseSectionProperties(sectPr) {
|
|
|
315
271
|
if (Object.keys(enProps).length > 0) props.endnotePr = enProps;
|
|
316
272
|
}
|
|
317
273
|
const formProt = findChild(sectPr, "w", "formProt");
|
|
318
|
-
if (formProt) props.formProtection = parseBooleanElement(formProt);
|
|
274
|
+
if (formProt) props.formProtection = parseBooleanElement(formProt, "w", context);
|
|
319
275
|
const noEndnote = findChild(sectPr, "w", "noEndnote");
|
|
320
|
-
if (noEndnote) props.noEndnote = parseBooleanElement(noEndnote);
|
|
276
|
+
if (noEndnote) props.noEndnote = parseBooleanElement(noEndnote, "w", context);
|
|
321
277
|
const rtlGutter = findChild(sectPr, "w", "rtlGutter");
|
|
322
|
-
if (rtlGutter) props.rtlGutter = parseBooleanElement(rtlGutter);
|
|
278
|
+
if (rtlGutter) props.rtlGutter = parseBooleanElement(rtlGutter, "w", context);
|
|
323
279
|
const docGrid = findChild(sectPr, "w", "docGrid");
|
|
324
280
|
if (docGrid) {
|
|
325
281
|
props.docGrid = {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
2
|
-
import { escapeXml } from "./serializer/xmlUtils.js";
|
|
3
2
|
import { OFFICE_RELATIONSHIP_NAMESPACE_URIS, WORDPROCESSINGML_NAMESPACE_URIS, findChildrenByNamespaceUri, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespaceUri } from "./xmlParser.js";
|
|
4
3
|
import { TaggedError } from "better-result";
|
|
4
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
5
5
|
//#region src/docx/sectionReferenceHistory.ts
|
|
6
6
|
const SECTION_REFERENCE_HISTORY_NAMESPACE = "urn:stella:folio:section-reference-history:1";
|
|
7
7
|
const HISTORY_NAMESPACES = /* @__PURE__ */ new Set([SECTION_REFERENCE_HISTORY_NAMESPACE]);
|
|
@@ -41,7 +41,7 @@ const serializeSectionReferenceHistory = (references) => {
|
|
|
41
41
|
if (new Set(values.map(({ type }) => type)).size !== values.length) return invalidHistory();
|
|
42
42
|
return values.map(({ type, rId }) => {
|
|
43
43
|
if (!rId || rId.trim() !== rId) return invalidHistory();
|
|
44
|
-
return `<w:${kind}Reference w:type="${type}" r:id="${
|
|
44
|
+
return `<w:${kind}Reference w:type="${type}" r:id="${escapeXmlAttribute(rId)}"/>`;
|
|
45
45
|
}).join("");
|
|
46
46
|
};
|
|
47
47
|
const content = serializeReferences("header", references.headerReferences ?? []) + serializeReferences("footer", references.footerReferences ?? []);
|
|
@@ -8,7 +8,7 @@ import { RELATIONSHIP_TYPES } from "./relsParser.js";
|
|
|
8
8
|
import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedInlineResources, updateCoreProperties, withoutAttachedTemplate } from "./rezip.js";
|
|
9
9
|
import "./selectiveSaveFlags.js";
|
|
10
10
|
import { buildPatchedDocumentXml, buildPatchedNoteXml, collectParaIds, patchNumberingDefinitions } from "./selectiveXmlPatch.js";
|
|
11
|
-
import {
|
|
11
|
+
import { planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
12
12
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
13
13
|
import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
|
|
14
14
|
import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
@@ -84,8 +84,8 @@ const commentsExtendedInfoEqual = (a, b) => {
|
|
|
84
84
|
* - Threading changed: write the part and ensure its override + relationship,
|
|
85
85
|
* bailing if the packaging files needed to wire it are absent.
|
|
86
86
|
*/
|
|
87
|
-
async function patchCommentsExtended(zip,
|
|
88
|
-
const desiredXml = serializeCommentsExtended(
|
|
87
|
+
async function patchCommentsExtended(zip, plan, updates) {
|
|
88
|
+
const desiredXml = serializeCommentsExtended(plan);
|
|
89
89
|
const existing = findZipEntryCaseInsensitive(zip, COMMENTS_EXTENDED_PART_LOWER);
|
|
90
90
|
if (!desiredXml) return existing === null;
|
|
91
91
|
const baselineInfo = existing ? parseCommentsExtended(await existing.async("text")) : /* @__PURE__ */ new Map();
|
|
@@ -190,6 +190,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
190
190
|
if (!validateFolioDocumentModel(doc).valid) return null;
|
|
191
191
|
const comments = doc.package.document.comments ?? [];
|
|
192
192
|
const hasComments = comments.length > 0;
|
|
193
|
+
const commentPlan = planCommentParts(comments);
|
|
193
194
|
try {
|
|
194
195
|
const zip = await (await import("jszip")).default.loadAsync(originalBuffer);
|
|
195
196
|
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && isUnsafePackagePath(path)) return null;
|
|
@@ -215,9 +216,8 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
215
216
|
}
|
|
216
217
|
const sourceCommentsFile = zip.file("word/comments.xml");
|
|
217
218
|
if (hasComments || sourceCommentsFile) {
|
|
218
|
-
ensureThreadedCommentParaIds(comments);
|
|
219
219
|
const sourceBindings = sourceCommentsFile ? readRootNamespaceBindings(await sourceCommentsFile.async("text")) : void 0;
|
|
220
|
-
updates.set("word/comments.xml", serializeComments(
|
|
220
|
+
updates.set("word/comments.xml", serializeComments(commentPlan, sourceBindings));
|
|
221
221
|
}
|
|
222
222
|
if (hasComments) {
|
|
223
223
|
const ctFile = zip.file("[Content_Types].xml");
|
|
@@ -235,7 +235,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
-
if (!await patchCommentsExtended(zip,
|
|
238
|
+
if (!await patchCommentsExtended(zip, commentPlan, updates)) return null;
|
|
239
239
|
await patchNumberingPart(zip, doc, updates);
|
|
240
240
|
for (const [path, xml] of await collectHeaderFooterUpdates(doc, zip)) updates.set(path, xml);
|
|
241
241
|
await queueSettingsUpdates(zip, updates);
|
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
2
2
|
import { isSingleWellFormedElement } from "./xmlUtils.js";
|
|
3
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
3
4
|
//#region src/docx/serializer/blockSdtSerializer.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Block-level SDT serializer.
|
|
7
|
+
*
|
|
8
|
+
* Replays `<w:sdtPr>` (and `<w:sdtEndPr>` when present) verbatim from the
|
|
9
|
+
* `rawPropertiesXml` / `rawEndPropertiesXml` strings captured by the parser.
|
|
10
|
+
* That keeps OOXML element order intact (`CT_SdtPr` is an `xsd:sequence`,
|
|
11
|
+
* ECMA-376 §17.5.2) and round-trips unmodeled features — `w:dataBinding`,
|
|
12
|
+
* `w15:repeatingSection`, `@lastValue`, custom XML mappings — without us
|
|
13
|
+
* having to enumerate them.
|
|
14
|
+
*
|
|
15
|
+
* If a `BlockSdt` was constructed programmatically (no parsed snapshot to
|
|
16
|
+
* replay), fall back to a minimal projection from the modeled fields so the
|
|
17
|
+
* result is still a valid `<w:sdt>`.
|
|
18
|
+
*
|
|
19
|
+
* Sharing the helper between the document body and the header/footer
|
|
20
|
+
* serializers keeps body↔HF parity in one place.
|
|
21
|
+
*/
|
|
7
22
|
function serializeFallbackSdtPr(props) {
|
|
8
23
|
const parts = [];
|
|
9
24
|
if (props.id !== void 0) parts.push(`<w:id w:val="${props.id}"/>`);
|
|
10
|
-
if (props.alias) parts.push(`<w:alias w:val="${
|
|
11
|
-
if (props.tag) parts.push(`<w:tag w:val="${
|
|
25
|
+
if (props.alias) parts.push(`<w:alias w:val="${escapeXmlAttribute(props.alias)}"/>`);
|
|
26
|
+
if (props.tag) parts.push(`<w:tag w:val="${escapeXmlAttribute(props.tag)}"/>`);
|
|
12
27
|
if (props.lock) parts.push(`<w:lock w:val="${props.lock}"/>`);
|
|
13
|
-
if (props.placeholder) parts.push(`<w:placeholder><w:docPart w:val="${
|
|
28
|
+
if (props.placeholder) parts.push(`<w:placeholder><w:docPart w:val="${escapeXmlAttribute(props.placeholder)}"/></w:placeholder>`);
|
|
14
29
|
if (props.showingPlaceholder) parts.push("<w:showingPlcHdr/>");
|
|
15
30
|
switch (props.sdtType) {
|
|
16
31
|
case "plainText":
|
|
17
32
|
parts.push("<w:text/>");
|
|
18
33
|
break;
|
|
19
34
|
case "date": {
|
|
20
|
-
const fullDateAttr = props.dateValueISO ? ` w:fullDate="${
|
|
21
|
-
const formatChild = props.dateFormat ? `<w:dateFormat w:val="${
|
|
35
|
+
const fullDateAttr = props.dateValueISO ? ` w:fullDate="${escapeXmlAttribute(props.dateValueISO)}"` : "";
|
|
36
|
+
const formatChild = props.dateFormat ? `<w:dateFormat w:val="${escapeXmlAttribute(props.dateFormat)}"/>` : "";
|
|
22
37
|
if (fullDateAttr || formatChild) parts.push(`<w:date${fullDateAttr}>${formatChild}</w:date>`);
|
|
23
38
|
else parts.push("<w:date/>");
|
|
24
39
|
break;
|
|
@@ -26,7 +41,7 @@ function serializeFallbackSdtPr(props) {
|
|
|
26
41
|
case "dropdown":
|
|
27
42
|
case "comboBox": {
|
|
28
43
|
const tag = props.sdtType === "dropdown" ? "w:dropDownList" : "w:comboBox";
|
|
29
|
-
const items = (props.listItems ?? []).map((item) => `<w:listItem w:displayText="${
|
|
44
|
+
const items = (props.listItems ?? []).map((item) => `<w:listItem w:displayText="${escapeXmlAttribute(item.displayText)}" w:value="${escapeXmlAttribute(item.value)}"/>`).join("");
|
|
30
45
|
parts.push(`<${tag}>${items}</${tag}>`);
|
|
31
46
|
break;
|
|
32
47
|
}
|
|
@@ -48,25 +63,22 @@ function serializeFallbackSdtPr(props) {
|
|
|
48
63
|
}
|
|
49
64
|
return `<w:sdtPr>${parts.join("")}</w:sdtPr>`;
|
|
50
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* `properties.dropdownLastValue` is the only record of what was selected.
|
|
68
|
+
*
|
|
69
|
+
* The XSD default of `@w:lastValue` is the empty string, so "never selected",
|
|
70
|
+
* "cleared" and "selected" are three distinguishable states, and the body's
|
|
71
|
+
* display text is evidence for none of them: it is equally the placeholder of
|
|
72
|
+
* a dropdown nobody has touched, and a displayText shared by two list items
|
|
73
|
+
* picks the wrong sibling. The parser records the authored `@w:lastValue` and
|
|
74
|
+
* `setContentControlValue` records a pick; what neither wrote is no selection.
|
|
75
|
+
*
|
|
76
|
+
* `""` is a value a producer can author (`<w:listItem w:value=""/>`), so
|
|
77
|
+
* presence is the test, not truthiness.
|
|
78
|
+
*/
|
|
51
79
|
function extractDropdownLastValue(blockSdt) {
|
|
52
80
|
if (blockSdt.properties.sdtType !== "dropdown" && blockSdt.properties.sdtType !== "comboBox") return;
|
|
53
|
-
|
|
54
|
-
if (modeled !== void 0) return modeled;
|
|
55
|
-
if (blockSdt.properties.rawPropertiesXml !== void 0) return;
|
|
56
|
-
const firstBlock = blockSdt.content[0];
|
|
57
|
-
if (!firstBlock || firstBlock.type !== "paragraph") return;
|
|
58
|
-
const parts = [];
|
|
59
|
-
for (const child of firstBlock.content) if (child.type === "run") {
|
|
60
|
-
for (const item of child.content) if (item.type === "text") parts.push(item.text);
|
|
61
|
-
}
|
|
62
|
-
const text = parts.join("");
|
|
63
|
-
if (text.length === 0) return;
|
|
64
|
-
const items = blockSdt.properties.listItems;
|
|
65
|
-
if (items) {
|
|
66
|
-
const match = items.find((item) => item.displayText === text);
|
|
67
|
-
if (match) return match.value;
|
|
68
|
-
}
|
|
69
|
-
return text;
|
|
81
|
+
return blockSdt.properties.dropdownLastValue;
|
|
70
82
|
}
|
|
71
83
|
function extractDateFullDate(blockSdt) {
|
|
72
84
|
if (blockSdt.properties.sdtType !== "date") return;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
2
|
//#region src/docx/serializer/borderSerializer.d.ts
|
|
3
|
-
type ExhaustiveFields<Source, Classified extends keyof Source> = Exclude<keyof Source, Classified> extends never ? Source : never;
|
|
4
3
|
type ClassifiedBorderField = "style" | "color" | "size" | "space" | "shadow" | "frame" | "artRelationshipId" | "topLeftArtRelationshipId" | "topRightArtRelationshipId" | "bottomLeftArtRelationshipId" | "bottomRightArtRelationshipId";
|
|
5
|
-
type ExhaustiveBorder = ExhaustiveFields<document_d_exports.BorderSpec, ClassifiedBorderField>;
|
|
4
|
+
type ExhaustiveBorder = document_d_exports.ExhaustiveFields<document_d_exports.BorderSpec, ClassifiedBorderField>;
|
|
6
5
|
/**
|
|
7
6
|
* Serialize a single border element (`<w:top .../>`, `<w:left .../>`, ...).
|
|
8
7
|
*
|
|
@@ -19,7 +18,7 @@ type ExhaustiveBorder = ExhaustiveFields<document_d_exports.BorderSpec, Classifi
|
|
|
19
18
|
*
|
|
20
19
|
* `style` and the color values come straight from the parsed DOCX (the parser
|
|
21
20
|
* casts `w:val`/`w:color` without validating the enum), so they are
|
|
22
|
-
* untrusted and are `
|
|
21
|
+
* untrusted and are `escapeXmlAttribute`'d before re-entering XML attributes; for valid
|
|
23
22
|
* documents these are enum/hex values, so escaping is a no-op.
|
|
24
23
|
*/
|
|
25
24
|
declare function serializeBorder(input: ExhaustiveBorder | undefined, elementName: string): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { intAttr } from "./xmlUtils.js";
|
|
2
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
2
3
|
//#region src/docx/serializer/borderSerializer.ts
|
|
3
4
|
/**
|
|
4
5
|
* Serialize a single border element (`<w:top .../>`, `<w:left .../>`, ...).
|
|
@@ -16,30 +17,30 @@ import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
|
16
17
|
*
|
|
17
18
|
* `style` and the color values come straight from the parsed DOCX (the parser
|
|
18
19
|
* casts `w:val`/`w:color` without validating the enum), so they are
|
|
19
|
-
* untrusted and are `
|
|
20
|
+
* untrusted and are `escapeXmlAttribute`'d before re-entering XML attributes; for valid
|
|
20
21
|
* documents these are enum/hex values, so escaping is a no-op.
|
|
21
22
|
*/
|
|
22
23
|
function serializeBorder(input, elementName) {
|
|
23
24
|
if (!input) return "";
|
|
24
25
|
const { style, color, size, space, shadow, frame, artRelationshipId, topLeftArtRelationshipId, topRightArtRelationshipId, bottomLeftArtRelationshipId, bottomRightArtRelationshipId } = input;
|
|
25
|
-
const attrs = [`w:val="${
|
|
26
|
+
const attrs = [`w:val="${escapeXmlAttribute(style)}"`];
|
|
26
27
|
if (size !== void 0) attrs.push(`w:sz="${intAttr(size)}"`);
|
|
27
28
|
if (space !== void 0) attrs.push(`w:space="${intAttr(space)}"`);
|
|
28
29
|
if (color) {
|
|
29
30
|
const { auto, rgb, themeColor, themeTint, themeShade } = color;
|
|
30
31
|
if (auto) attrs.push("w:color=\"auto\"");
|
|
31
|
-
else if (rgb) attrs.push(`w:color="${
|
|
32
|
-
if (themeColor) attrs.push(`w:themeColor="${
|
|
33
|
-
if (themeTint) attrs.push(`w:themeTint="${
|
|
34
|
-
if (themeShade) attrs.push(`w:themeShade="${
|
|
32
|
+
else if (rgb) attrs.push(`w:color="${escapeXmlAttribute(rgb)}"`);
|
|
33
|
+
if (themeColor) attrs.push(`w:themeColor="${escapeXmlAttribute(themeColor)}"`);
|
|
34
|
+
if (themeTint) attrs.push(`w:themeTint="${escapeXmlAttribute(themeTint)}"`);
|
|
35
|
+
if (themeShade) attrs.push(`w:themeShade="${escapeXmlAttribute(themeShade)}"`);
|
|
35
36
|
}
|
|
36
37
|
if (shadow) attrs.push("w:shadow=\"true\"");
|
|
37
38
|
if (frame) attrs.push("w:frame=\"true\"");
|
|
38
|
-
if (artRelationshipId) attrs.push(`
|
|
39
|
-
if (topLeftArtRelationshipId) attrs.push(`
|
|
40
|
-
if (topRightArtRelationshipId) attrs.push(`
|
|
41
|
-
if (bottomLeftArtRelationshipId) attrs.push(`
|
|
42
|
-
if (bottomRightArtRelationshipId) attrs.push(`
|
|
39
|
+
if (artRelationshipId) attrs.push(`r:id="${escapeXmlAttribute(artRelationshipId)}"`);
|
|
40
|
+
if (topLeftArtRelationshipId) attrs.push(`r:topLeft="${escapeXmlAttribute(topLeftArtRelationshipId)}"`);
|
|
41
|
+
if (topRightArtRelationshipId) attrs.push(`r:topRight="${escapeXmlAttribute(topRightArtRelationshipId)}"`);
|
|
42
|
+
if (bottomLeftArtRelationshipId) attrs.push(`r:bottomLeft="${escapeXmlAttribute(bottomLeftArtRelationshipId)}"`);
|
|
43
|
+
if (bottomRightArtRelationshipId) attrs.push(`r:bottomRight="${escapeXmlAttribute(bottomRightArtRelationshipId)}"`);
|
|
43
44
|
return `<w:${elementName} ${attrs.join(" ")}/>`;
|
|
44
45
|
}
|
|
45
46
|
//#endregion
|
|
@@ -1,30 +1,55 @@
|
|
|
1
1
|
import { Comment } from "../../types/content.js";
|
|
2
2
|
//#region src/docx/serializer/commentSerializer.d.ts
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* What every comment part is written from: one ordered list of comment ids, and
|
|
5
|
+
* the facts each id carries.
|
|
6
|
+
*
|
|
7
|
+
* `word/comments.xml` and `word/commentsExtended.xml` describe the same
|
|
8
|
+
* comments and have to agree about which is which. They agreed by each walking
|
|
9
|
+
* the `Comment[]` they were handed and pairing entries up by position, so any
|
|
10
|
+
* disagreement about order — one part reordered, the other not — silently moved
|
|
11
|
+
* a comment's thread link, resolved state and paraId onto a different comment.
|
|
12
|
+
* Positions cannot disagree if neither part has one: both walk `order` and look
|
|
13
|
+
* every fact up by `w:id`, the only identity the package itself has.
|
|
14
|
+
*/
|
|
15
|
+
type CommentPartPlan = {
|
|
16
|
+
/** The `w:id`s to write, in order, each exactly once. */
|
|
17
|
+
readonly order: readonly number[];
|
|
18
|
+
readonly byId: ReadonlyMap<number, Comment>;
|
|
19
|
+
/** The `w14:paraId` each comment is threaded by, minted where the model had none. */
|
|
20
|
+
readonly threadParaIdById: ReadonlyMap<number, string>;
|
|
21
|
+
/** The comments needing a `commentsExtended.xml` entry: replies, their parents, resolved comments. */
|
|
22
|
+
readonly threadedIds: ReadonlySet<number>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Plan both comment parts from the model, in the model's own order.
|
|
26
|
+
*
|
|
27
|
+
* The order is the document's: the order `word/comments.xml` listed the
|
|
28
|
+
* comments in is the order it is written back in, so a save neither reshuffles
|
|
29
|
+
* a reviewer's threads nor hands the next parse a different `comments[]` than
|
|
30
|
+
* the one it read.
|
|
31
|
+
*
|
|
32
|
+
* Planning also mints the `w14:paraId` a thread needs when the model has none —
|
|
33
|
+
* a comment written in the editor has no Word-authored id, and without one the
|
|
34
|
+
* `commentsExtended.xml` link would be dropped. Minting is deterministic
|
|
35
|
+
* (comment id and text derived) so repeated saves mint the same id, and it
|
|
36
|
+
* happens here rather than at each call site because both parts must see it.
|
|
37
|
+
*/
|
|
38
|
+
declare const planCommentParts: (comments: readonly Comment[]) => CommentPartPlan;
|
|
39
|
+
/**
|
|
40
|
+
* Serialize a comment plan to comments.xml content. Returns a valid empty
|
|
41
|
+
* `<w:comments/>` document for an empty plan so callers can overwrite an
|
|
6
42
|
* existing `word/comments.xml` part when the editor has removed the last
|
|
7
43
|
* comment — leaving the previous file in place would otherwise re-emit
|
|
8
44
|
* the orphaned comment threads on every save.
|
|
9
45
|
*/
|
|
10
|
-
declare function serializeComments(
|
|
11
|
-
/**
|
|
12
|
-
* Assign a deterministic `w14:paraId` to the LAST paragraph of every comment
|
|
13
|
-
* that needs a commentsExtended entry (a reply, a reply's parent, or a resolved
|
|
14
|
-
* comment) but has none. A document authored or loaded without comment paraIds
|
|
15
|
-
* would otherwise have no stable key to thread through commentsExtended.xml, and
|
|
16
|
-
* the thread link would be silently dropped. Word-authored ids are preserved;
|
|
17
|
-
* only threaded, id-less paragraphs are filled. Deterministic (content- and
|
|
18
|
-
* id-derived) so repeated saves mint the SAME id. MUST run before serializing
|
|
19
|
-
* BOTH comments.xml and commentsExtended.xml so the two reference the same id.
|
|
20
|
-
*/
|
|
21
|
-
declare function ensureThreadedCommentParaIds(comments: readonly Comment[]): void;
|
|
46
|
+
declare function serializeComments({ order, byId }: CommentPartPlan, sourceBindings?: ReadonlyMap<string, string>): string;
|
|
22
47
|
/**
|
|
23
48
|
* Serialize `commentsExtended.xml` (`w15:commentsEx`) for reply threading and
|
|
24
49
|
* resolved state, or `null` when no comment needs an entry (see
|
|
25
50
|
* {@link buildCommentExtendedEntries}). This is the part that makes Word render
|
|
26
51
|
* a comment as a REPLY rather than a separate top-level thread.
|
|
27
52
|
*/
|
|
28
|
-
declare function serializeCommentsExtended(
|
|
53
|
+
declare function serializeCommentsExtended(plan: CommentPartPlan): string | null;
|
|
29
54
|
//#endregion
|
|
30
|
-
export {
|
|
55
|
+
export { CommentPartPlan, planCommentParts, serializeComments, serializeCommentsExtended };
|