@stll/folio-core 0.35.1 → 0.37.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/README.md +59 -1
- package/dist/ai-edits/apply.js +878 -377
- package/dist/ai-edits/block-identity.d.ts +4 -1
- package/dist/ai-edits/block-identity.js +4 -1
- package/dist/ai-edits/blockRange.js +14 -14
- package/dist/ai-edits/clean-text.d.ts +40 -1
- package/dist/ai-edits/clean-text.js +52 -2
- package/dist/ai-edits/headless.d.ts +3 -1
- package/dist/ai-edits/headless.js +141 -73
- package/dist/ai-edits/index.d.ts +3 -3
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.js +38 -20
- package/dist/ai-edits/snapshot.d.ts +14 -6
- package/dist/ai-edits/snapshot.js +105 -20
- package/dist/ai-edits/table-cell-mutations.js +1 -1
- package/dist/ai-edits/table-row-column-mutations.js +7 -0
- package/dist/ai-edits/table-template.d.ts +11 -1
- package/dist/ai-edits/table-template.js +49 -17
- package/dist/ai-edits/types.d.ts +62 -61
- package/dist/ai-edits/word-diff.d.ts +18 -3
- package/dist/ai-edits/word-diff.js +556 -67
- package/dist/ai-suggestions/conflict.js +1 -4
- package/dist/ai-suggestions/text-positions.d.ts +8 -0
- package/dist/ai-suggestions/text-positions.js +27 -5
- package/dist/compare/__fixtures__/body-sequence.js +3 -4
- package/dist/compare/column-alignment.d.ts +13 -13
- package/dist/compare/column-alignment.js +78 -39
- package/dist/compare/compare.d.ts +4 -3
- package/dist/compare/compare.js +48 -21
- package/dist/compare/content-alignment.d.ts +95 -0
- package/dist/compare/content-alignment.js +1450 -0
- package/dist/compare/content-types.d.ts +100 -0
- package/dist/compare/content-types.js +0 -0
- package/dist/compare/content.d.ts +209 -0
- package/dist/compare/content.js +885 -0
- package/dist/compare/formatting.d.ts +5 -5
- package/dist/compare/formatting.js +6 -4
- package/dist/compare/plan.d.ts +6 -1
- package/dist/compare/plan.js +171 -566
- package/dist/compare/scenario.d.ts +2 -2
- package/dist/compare/types.d.ts +3 -3
- package/dist/compare/verification.d.ts +8 -9
- package/dist/compare/verification.js +72 -50
- package/dist/compat/eigenpal.d.ts +5 -3
- package/dist/compat/eigenpal.js +3 -2
- package/dist/controller/headerFooterEditorManager.js +18 -10
- package/dist/controller/hiddenEditorApi.js +1 -1
- package/dist/controller/hiddenEditorManager.d.ts +7 -2
- package/dist/controller/hiddenEditorManager.js +15 -6
- package/dist/controller/layoutPipeline.js +5 -3
- package/dist/controller/noteEditorManager.js +12 -7
- package/dist/display-list/build/headerFooterPrimitives.js +1 -0
- package/dist/display-list/build/storyPrimitives.d.ts +5 -2
- package/dist/display-list/build/storyPrimitives.js +60 -3
- package/dist/display-list/build/tablePrimitives.js +30 -0
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/document-operations.d.ts +8 -4
- package/dist/document-operations.js +104 -12
- package/dist/docx/blockContentParser.js +6 -27
- package/dist/docx/commentParser.js +2 -4
- package/dist/docx/commentRangeIntegrity.js +2 -4
- package/dist/docx/documentClone.d.ts +2 -0
- package/dist/docx/documentClone.js +2 -0
- package/dist/docx/ensureParaIds.js +9 -4
- package/dist/docx/headerFooterParser.js +2 -4
- package/dist/docx/normalizeBaseDirection.js +5 -7
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +4 -1
- package/dist/docx/paragraphParser.js +34 -35
- package/dist/docx/paragraphPropertySource.d.ts +49 -0
- package/dist/docx/paragraphPropertySource.js +113 -0
- package/dist/docx/paragraphTraversal.js +30 -34
- package/dist/docx/rezip.d.ts +0 -8
- package/dist/docx/rezip.js +41 -16
- package/dist/docx/runConsolidator.js +2 -4
- package/dist/docx/runParser.js +6 -17
- package/dist/docx/sectionParser.js +1 -15
- package/dist/docx/serializer/paragraphSerializer.js +289 -30
- package/dist/docx/serializer/runSerializer.js +6 -12
- package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -10
- package/dist/docx/serializer/tableSerializer.js +4 -23
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +11 -0
- package/dist/docx/serializer/trackedChangeAttributes.js +31 -0
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/docx/server/createBilingualDocument.js +8 -10
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +22 -13
- package/dist/docx/server/validateDocxConformance.js +17 -13
- package/dist/docx/tableParser.js +1 -37
- package/dist/docx/trackedChangeInfo.d.ts +11 -0
- package/dist/docx/trackedChangeInfo.js +38 -0
- package/dist/docx/verbatimCapture.d.ts +20 -9
- package/dist/docx/verbatimCapture.js +208 -8
- package/dist/docx/xmlParser.d.ts +3 -1
- package/dist/docx/xmlParser.js +6 -1
- package/dist/docx/xmlSafety.d.ts +1 -1
- package/dist/docx/xmlSafety.js +157 -0
- package/dist/headless-layout.js +5 -4
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +23 -0
- package/dist/internal/headlessRevisionResolution.js +155 -0
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
- package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
- package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
- package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
- package/dist/internal/pageBreakRunPartition.d.ts +26 -0
- package/dist/internal/pageBreakRunPartition.js +35 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
- package/dist/internal/sectionEndpointResolution.d.ts +32 -0
- package/dist/internal/sectionEndpointResolution.js +38 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
- package/dist/layout-bridge/convert/headerFooterLayout.js +52 -9
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +391 -82
- package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
- package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
- package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
- package/dist/layout-bridge/dom/textStreamDom.js +75 -0
- package/dist/layout-bridge/headerFooterLayout.js +16 -30
- package/dist/layout-engine/index.js +12 -3
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +7 -0
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/renderTable.js +20 -0
- package/dist/markdown/renderBlock.js +7 -10
- package/dist/model.d.ts +1 -1
- package/dist/paged-layout/rangeProjection.js +6 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
- package/dist/paged-layout/transactionDirtyRange.js +23 -1
- package/dist/prosemirror/attrs/index.d.ts +7 -3
- package/dist/prosemirror/attrs/index.js +128 -7
- package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
- package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
- package/dist/prosemirror/commands/comments.d.ts +10 -1
- package/dist/prosemirror/commands/comments.js +551 -87
- package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
- package/dist/prosemirror/commands/formatPainter.js +319 -63
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
- package/dist/prosemirror/commands/pageBreak.js +18 -36
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +27 -3
- package/dist/prosemirror/commands/propertyChangeScope.js +85 -14
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -5
- package/dist/prosemirror/conversion/fromProseDoc.js +935 -223
- package/dist/prosemirror/conversion/runShadingMark.js +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
- package/dist/prosemirror/conversion/toProseDoc.js +439 -291
- package/dist/prosemirror/extensions/StarterKit.js +4 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +54 -6
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +19 -6
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
- package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
- package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
- package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
- package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
- package/dist/prosemirror/findReplaceSelection.js +8 -3
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/listMarker.d.ts +26 -1
- package/dist/prosemirror/listMarker.js +108 -14
- package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
- package/dist/prosemirror/pageBreakRunProjection.js +47 -0
- package/dist/prosemirror/paraText.js +6 -0
- package/dist/prosemirror/paragraphAlignment.d.ts +12 -0
- package/dist/prosemirror/paragraphAlignment.js +13 -0
- package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
- package/dist/prosemirror/paragraphSpacing.js +125 -0
- package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
- package/dist/prosemirror/plugins/documentNumbering.js +18 -0
- package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
- package/dist/prosemirror/plugins/pmTextScan.js +14 -4
- package/dist/prosemirror/plugins/suggestionMode.js +9 -11
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
- package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
- package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
- package/dist/prosemirror/runFormattingProvenance.js +48 -0
- package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
- package/dist/prosemirror/runFormattingReconciliation.js +54 -0
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
- package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
- package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
- package/dist/prosemirror/runStyleFormatting.js +105 -0
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +84 -9
- package/dist/prosemirror/schema/marks.js +73 -1
- package/dist/prosemirror/schema/nodes.d.ts +30 -6
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +45 -23
- package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
- package/dist/prosemirror/styles/styleResolver.js +3 -3
- package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
- package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
- package/dist/prosemirror/tableGridMutation.d.ts +20 -0
- package/dist/prosemirror/tableGridMutation.js +30 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
- package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
- package/dist/prosemirror/validation.js +23 -4
- package/dist/redline.js +4 -1
- package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
- package/dist/render-dom/RenderedDomContext.js +17 -34
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/style-engine/styleEngine.d.ts +1 -1
- package/dist/utils/clipboard.js +1 -1
- package/dist/utils/findReplace.js +38 -21
- package/dist/utils/mergeDocumentContent.js +3 -3
- package/dist/utils/replaceText.js +2 -1
- package/dist/version-comparison.d.ts +38 -44
- package/dist/version-comparison.js +270 -399
- package/dist/watermark/index.js +2 -4
- package/package.json +8 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { parseFooterReference, parseHeaderReference } from "./headerFooterRefParser.js";
|
|
2
2
|
import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
|
|
3
3
|
import { BorderStyleSchema, NumberFormatSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
4
|
+
import { parsePropertyChangeInfo } from "./trackedChangeInfo.js";
|
|
4
5
|
import { findChild, findChildren, getAttribute, getChildElements, getLocalName, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
5
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
6
6
|
//#region src/docx/sectionParser.ts
|
|
7
7
|
/**
|
|
8
8
|
* Sanity cap on `w:cols/@w:num`. Word's column picker tops out well below
|
|
@@ -61,20 +61,6 @@ function parseColorValue(colorStr, themeColor, themeTint, themeShade) {
|
|
|
61
61
|
if (themeShade) color.themeShade = themeShade;
|
|
62
62
|
return Object.keys(color).length > 0 ? color : void 0;
|
|
63
63
|
}
|
|
64
|
-
function parsePropertyChangeInfo(node) {
|
|
65
|
-
const rawId = getAttribute(node, "w", "id");
|
|
66
|
-
const parsedId = rawId ? Number.parseInt(rawId, 10) : 0;
|
|
67
|
-
const author = (getAttribute(node, "w", "author") ?? "").trim();
|
|
68
|
-
const date = (getAttribute(node, "w", "date") ?? "").trim();
|
|
69
|
-
const rsid = (getAttribute(node, "w", "rsid") ?? "").trim();
|
|
70
|
-
const info = {
|
|
71
|
-
id: normalizeRevisionId(parsedId),
|
|
72
|
-
author: author.length > 0 ? author : "Unknown"
|
|
73
|
-
};
|
|
74
|
-
if (date.length > 0) info.date = date;
|
|
75
|
-
if (rsid.length > 0) info.rsid = rsid;
|
|
76
|
-
return info;
|
|
77
|
-
}
|
|
78
64
|
/**
|
|
79
65
|
* Parse a border element for page borders
|
|
80
66
|
*/
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { canonicalJson } from "../../utils/canonicalJson.js";
|
|
1
2
|
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
2
3
|
import { numPrEqual } from "../numberingParser.js";
|
|
4
|
+
import { getParagraphPropertySource } from "../paragraphPropertySource.js";
|
|
3
5
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
6
|
+
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
7
|
+
import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
|
|
8
|
+
import { captureVerbatimXml, sanitizeCapturedXmlElement } from "../verbatimCapture.js";
|
|
9
|
+
import { NAMESPACES, OOXML_NAMESPACE_SCOPE, cloneElement, getChildElements, getLocalName, parseXml } from "../xmlParser.js";
|
|
4
10
|
import { serializeBorder } from "./borderSerializer.js";
|
|
5
11
|
import { serializeRun, serializeTextFormatting } from "./runSerializer.js";
|
|
6
12
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
13
|
+
import { serializeTrackedChangeAttributes, trackedChangeAttributeRecord } from "./trackedChangeAttributes.js";
|
|
7
14
|
import { escapeXml, intAttr, isSingleWellFormedElement } from "./xmlUtils.js";
|
|
8
|
-
import {
|
|
15
|
+
import { panic } from "better-result";
|
|
16
|
+
import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
|
|
9
17
|
//#region src/docx/serializer/paragraphSerializer.ts
|
|
10
18
|
/**
|
|
11
19
|
* Serialize paragraph borders (w:pBdr)
|
|
@@ -131,16 +139,280 @@ function serializeFrameProperties(frame) {
|
|
|
131
139
|
/**
|
|
132
140
|
* Serialize paragraph formatting properties to w:pPr XML
|
|
133
141
|
*/
|
|
134
|
-
function serializeTrackedChangeAttrs(info) {
|
|
135
|
-
const parts = [`w:id="${normalizeRevisionId(info.id)}"`, `w:author="${escapeXml(info.author)}"`];
|
|
136
|
-
if (info.date !== void 0) parts.push(`w:date="${escapeXml(info.date)}"`);
|
|
137
|
-
return parts.join(" ");
|
|
138
|
-
}
|
|
139
142
|
function serializeParagraphMarkChange(mark) {
|
|
140
|
-
const attrs =
|
|
143
|
+
const attrs = serializeTrackedChangeAttributes(mark.info);
|
|
141
144
|
return `<w:${mark.kind} ${attrs}/>`;
|
|
142
145
|
}
|
|
143
|
-
const
|
|
146
|
+
const RESERVED_PARAGRAPH_PROPERTY_CHILDREN = /* @__PURE__ */ new Set(["pPrChange", "sectPr"]);
|
|
147
|
+
const RESERVED_PARAGRAPH_CAPTURE_CHILDREN = /* @__PURE__ */ new Set([
|
|
148
|
+
...RESERVED_PARAGRAPH_PROPERTY_CHILDREN,
|
|
149
|
+
...PARAGRAPH_MARK_CHANGE_KINDS,
|
|
150
|
+
"cellDel",
|
|
151
|
+
"cellIns",
|
|
152
|
+
"cellMerge",
|
|
153
|
+
"numberingChange",
|
|
154
|
+
"rPrChange",
|
|
155
|
+
"tblGridChange",
|
|
156
|
+
"tblPrChange",
|
|
157
|
+
"tcPrChange",
|
|
158
|
+
"trPrChange"
|
|
159
|
+
]);
|
|
160
|
+
const PARAGRAPH_PROPERTY_ROOT_NAME = /* @__PURE__ */ new Set(["pPr"]);
|
|
161
|
+
const WORDPROCESSINGML_NAMESPACE = /* @__PURE__ */ new Set([NAMESPACES.w]);
|
|
162
|
+
const PARAGRAPH_APPEND_PREFIXES = /* @__PURE__ */ new Map([
|
|
163
|
+
["w", NAMESPACES.w],
|
|
164
|
+
["r", NAMESPACES.r],
|
|
165
|
+
["w15", NAMESPACES.w15]
|
|
166
|
+
]);
|
|
167
|
+
const PARAGRAPH_PROPERTY_CHILD_ORDER = new Map([
|
|
168
|
+
"pStyle",
|
|
169
|
+
"keepNext",
|
|
170
|
+
"keepLines",
|
|
171
|
+
"pageBreakBefore",
|
|
172
|
+
"framePr",
|
|
173
|
+
"widowControl",
|
|
174
|
+
"numPr",
|
|
175
|
+
"suppressLineNumbers",
|
|
176
|
+
"pBdr",
|
|
177
|
+
"shd",
|
|
178
|
+
"tabs",
|
|
179
|
+
"suppressAutoHyphens",
|
|
180
|
+
"kinsoku",
|
|
181
|
+
"wordWrap",
|
|
182
|
+
"overflowPunct",
|
|
183
|
+
"topLinePunct",
|
|
184
|
+
"autoSpaceDE",
|
|
185
|
+
"autoSpaceDN",
|
|
186
|
+
"bidi",
|
|
187
|
+
"adjustRightInd",
|
|
188
|
+
"snapToGrid",
|
|
189
|
+
"spacing",
|
|
190
|
+
"ind",
|
|
191
|
+
"contextualSpacing",
|
|
192
|
+
"mirrorIndents",
|
|
193
|
+
"suppressOverlap",
|
|
194
|
+
"jc",
|
|
195
|
+
"textDirection",
|
|
196
|
+
"textAlignment",
|
|
197
|
+
"textboxTightWrap",
|
|
198
|
+
"outlineLvl",
|
|
199
|
+
"divId",
|
|
200
|
+
"cnfStyle",
|
|
201
|
+
"rPr"
|
|
202
|
+
].map((name, index) => [name, index]));
|
|
203
|
+
const PARAGRAPH_MARK_BASE_CHILDREN = /* @__PURE__ */ new Set([
|
|
204
|
+
"rStyle",
|
|
205
|
+
"rFonts",
|
|
206
|
+
"b",
|
|
207
|
+
"bCs",
|
|
208
|
+
"i",
|
|
209
|
+
"iCs",
|
|
210
|
+
"caps",
|
|
211
|
+
"smallCaps",
|
|
212
|
+
"strike",
|
|
213
|
+
"dstrike",
|
|
214
|
+
"outline",
|
|
215
|
+
"shadow",
|
|
216
|
+
"emboss",
|
|
217
|
+
"imprint",
|
|
218
|
+
"snapToGrid",
|
|
219
|
+
"vanish",
|
|
220
|
+
"webHidden",
|
|
221
|
+
"color",
|
|
222
|
+
"spacing",
|
|
223
|
+
"w",
|
|
224
|
+
"kern",
|
|
225
|
+
"position",
|
|
226
|
+
"sz",
|
|
227
|
+
"szCs",
|
|
228
|
+
"noProof",
|
|
229
|
+
"highlight",
|
|
230
|
+
"u",
|
|
231
|
+
"effect",
|
|
232
|
+
"bdr",
|
|
233
|
+
"shd",
|
|
234
|
+
"fitText",
|
|
235
|
+
"vertAlign",
|
|
236
|
+
"rtl",
|
|
237
|
+
"cs",
|
|
238
|
+
"em",
|
|
239
|
+
"lang",
|
|
240
|
+
"eastAsianLayout",
|
|
241
|
+
"specVanish",
|
|
242
|
+
"oMath"
|
|
243
|
+
]);
|
|
244
|
+
const PARAGRAPH_NESTED_PROPERTY_CHILDREN = /* @__PURE__ */ new Map([
|
|
245
|
+
["numPr", /* @__PURE__ */ new Set(["ilvl", "numId"])],
|
|
246
|
+
["pBdr", /* @__PURE__ */ new Set([
|
|
247
|
+
"top",
|
|
248
|
+
"left",
|
|
249
|
+
"bottom",
|
|
250
|
+
"right",
|
|
251
|
+
"between",
|
|
252
|
+
"bar"
|
|
253
|
+
])],
|
|
254
|
+
["tabs", /* @__PURE__ */ new Set(["tab"])],
|
|
255
|
+
["rPr", PARAGRAPH_MARK_BASE_CHILDREN]
|
|
256
|
+
]);
|
|
257
|
+
const resolveNamespaceBinding = (scope, prefix) => {
|
|
258
|
+
for (let current = scope; current; current = current.parent) {
|
|
259
|
+
const value = current.bindings.get(prefix);
|
|
260
|
+
if (value !== void 0) return value;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const hasDescendantNamed = (element, namespaceUri, localName) => {
|
|
264
|
+
const pending = [...getChildElements(element)];
|
|
265
|
+
while (pending.length > 0) {
|
|
266
|
+
const child = pending.pop();
|
|
267
|
+
if (!child) continue;
|
|
268
|
+
if (getLocalName(child.name) === localName && toTransitionalNamespaceUri(child.namespaceUri ?? "") === namespaceUri) return true;
|
|
269
|
+
for (const descendant of getChildElements(child)) pending.push(descendant);
|
|
270
|
+
}
|
|
271
|
+
return false;
|
|
272
|
+
};
|
|
273
|
+
const hasInvalidParagraphPropertyRevision = (root) => {
|
|
274
|
+
const pending = [...getChildElements(root)];
|
|
275
|
+
while (pending.length > 0) {
|
|
276
|
+
const element = pending.pop();
|
|
277
|
+
if (!element) continue;
|
|
278
|
+
if (toTransitionalNamespaceUri(element.namespaceUri ?? "") === NAMESPACES.w) {
|
|
279
|
+
const localName = getLocalName(element.name);
|
|
280
|
+
if (RESERVED_PARAGRAPH_CAPTURE_CHILDREN.has(localName)) return true;
|
|
281
|
+
}
|
|
282
|
+
for (const child of getChildElements(element)) pending.push(child);
|
|
283
|
+
}
|
|
284
|
+
return false;
|
|
285
|
+
};
|
|
286
|
+
const hasInvalidParagraphPropertyShape = (root) => {
|
|
287
|
+
const pending = getChildElements(root).map((element) => ({
|
|
288
|
+
element,
|
|
289
|
+
parent: root
|
|
290
|
+
}));
|
|
291
|
+
if ((root.elements ?? []).some((child) => child.type === "text" && String(child.text ?? "").trim() !== "")) return true;
|
|
292
|
+
while (pending.length > 0) {
|
|
293
|
+
const entry = pending.pop();
|
|
294
|
+
if (!entry) continue;
|
|
295
|
+
const { element, parent } = entry;
|
|
296
|
+
if ((element.elements ?? []).some((child) => child.type === "text" && String(child.text ?? "").trim() !== "")) return true;
|
|
297
|
+
if (toTransitionalNamespaceUri(element.namespaceUri ?? "") === NAMESPACES.w && parent !== root) {
|
|
298
|
+
if (toTransitionalNamespaceUri(parent.namespaceUri ?? "") !== NAMESPACES.w) return true;
|
|
299
|
+
if (!PARAGRAPH_NESTED_PROPERTY_CHILDREN.get(getLocalName(parent.name))?.has(getLocalName(element.name))) return true;
|
|
300
|
+
}
|
|
301
|
+
for (const child of getChildElements(element)) pending.push({
|
|
302
|
+
element: child,
|
|
303
|
+
parent: element
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
};
|
|
308
|
+
const sourceShadowsDateUtcPrefix = (sourceXml) => {
|
|
309
|
+
const root = parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.at(0);
|
|
310
|
+
if (!root || root.type !== "element") return true;
|
|
311
|
+
const pending = [root];
|
|
312
|
+
while (pending.length > 0) {
|
|
313
|
+
const element = pending.pop();
|
|
314
|
+
if (!element) continue;
|
|
315
|
+
const resolved = resolveNamespaceBinding(element.namespaceScope, "w16du");
|
|
316
|
+
if (resolved !== void 0 && resolved !== "http://schemas.microsoft.com/office/word/2023/wordml/word16du") return true;
|
|
317
|
+
for (const child of getChildElements(element)) pending.push(child);
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
};
|
|
321
|
+
const hasInvalidParagraphMarkProperties = (root) => {
|
|
322
|
+
for (const child of getChildElements(root)) {
|
|
323
|
+
if (toTransitionalNamespaceUri(child.namespaceUri ?? "") !== NAMESPACES.w) continue;
|
|
324
|
+
const localName = getLocalName(child.name);
|
|
325
|
+
if (!PARAGRAPH_MARK_BASE_CHILDREN.has(localName)) return true;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
};
|
|
329
|
+
const replayableParagraphPropertySourceXml = (sourceXml) => {
|
|
330
|
+
return sanitizeCapturedXmlElement(sourceXml, {
|
|
331
|
+
allowedLocalNames: PARAGRAPH_PROPERTY_ROOT_NAME,
|
|
332
|
+
allowedNamespaceUris: WORDPROCESSINGML_NAMESPACE,
|
|
333
|
+
inheritedNamespaceScope: OOXML_NAMESPACE_SCOPE,
|
|
334
|
+
requiredNamespaceBindings: PARAGRAPH_APPEND_PREFIXES,
|
|
335
|
+
validate: (root) => {
|
|
336
|
+
let paragraphMarkProperties = null;
|
|
337
|
+
const seenChildren = /* @__PURE__ */ new Set();
|
|
338
|
+
let previousChildOrder = -1;
|
|
339
|
+
for (const child of getChildElements(root)) {
|
|
340
|
+
const localName = getLocalName(child.name);
|
|
341
|
+
const isWordprocessingChild = toTransitionalNamespaceUri(child.namespaceUri ?? "") === NAMESPACES.w;
|
|
342
|
+
if (isWordprocessingChild) {
|
|
343
|
+
if (RESERVED_PARAGRAPH_PROPERTY_CHILDREN.has(localName)) return false;
|
|
344
|
+
const childOrder = PARAGRAPH_PROPERTY_CHILD_ORDER.get(localName);
|
|
345
|
+
if (childOrder === void 0 || seenChildren.has(localName) || childOrder < previousChildOrder) return false;
|
|
346
|
+
seenChildren.add(localName);
|
|
347
|
+
previousChildOrder = childOrder;
|
|
348
|
+
}
|
|
349
|
+
if (localName !== "rPr" || !isWordprocessingChild) {
|
|
350
|
+
if (hasDescendantNamed(child, NAMESPACES.w, "rPr")) return false;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (paragraphMarkProperties !== null || toTransitionalNamespaceUri(resolveNamespaceBinding(child.namespaceScope, "w") ?? "") !== NAMESPACES.w) return false;
|
|
354
|
+
paragraphMarkProperties = child;
|
|
355
|
+
}
|
|
356
|
+
return !(paragraphMarkProperties && hasInvalidParagraphMarkProperties(paragraphMarkProperties) || hasInvalidParagraphPropertyShape(root) || hasInvalidParagraphPropertyRevision(root));
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
const verifiedParagraphPropertySource = (formatting, source) => {
|
|
361
|
+
if (!source) return null;
|
|
362
|
+
const replayableSource = replayableParagraphPropertySourceXml(source.xml);
|
|
363
|
+
if (replayableSource === null) return null;
|
|
364
|
+
return canonicalJson(formatting ?? {}) === source.formattingJson ? replayableSource : null;
|
|
365
|
+
};
|
|
366
|
+
const withTrailingParagraphPropertyChildren = (sourceXml, children) => {
|
|
367
|
+
const written = children.join("");
|
|
368
|
+
if (written.length === 0) return sourceXml;
|
|
369
|
+
const selfClosing = /^<((?:[A-Za-z_][\w.-]*:)?pPr)\b([^>]*)\/>$/u.exec(sourceXml);
|
|
370
|
+
if (selfClosing) {
|
|
371
|
+
const [, name, attrs] = selfClosing;
|
|
372
|
+
return `<${name}${attrs}>${written}</${name}>`;
|
|
373
|
+
}
|
|
374
|
+
const close = sourceXml.lastIndexOf("</");
|
|
375
|
+
return close === -1 ? sourceXml : `${sourceXml.slice(0, close)}${written}${sourceXml.slice(close)}`;
|
|
376
|
+
};
|
|
377
|
+
const withParagraphMarkChange = (sourceXml, mark) => {
|
|
378
|
+
const root = parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.at(0);
|
|
379
|
+
if (!root || root.type !== "element") panic("A validated paragraph-property capture could not be parsed for composition");
|
|
380
|
+
const attributes = trackedChangeAttributeRecord(mark.info);
|
|
381
|
+
const markElement = cloneElement(root, {
|
|
382
|
+
name: `w:${mark.kind}`,
|
|
383
|
+
attributes,
|
|
384
|
+
elements: []
|
|
385
|
+
});
|
|
386
|
+
const elements = [...root.elements ?? []];
|
|
387
|
+
const paragraphMarkIndex = elements.findIndex((child) => child.type === "element" && getLocalName(child.name) === "rPr" && toTransitionalNamespaceUri(child.namespaceUri ?? "") === NAMESPACES.w);
|
|
388
|
+
if (paragraphMarkIndex === -1) elements.push(cloneElement(root, {
|
|
389
|
+
name: "w:rPr",
|
|
390
|
+
attributes: {},
|
|
391
|
+
elements: [markElement]
|
|
392
|
+
}));
|
|
393
|
+
else {
|
|
394
|
+
const paragraphMarkProperties = elements[paragraphMarkIndex];
|
|
395
|
+
if (!paragraphMarkProperties || paragraphMarkProperties.type !== "element") panic("A validated paragraph-mark property node disappeared during composition");
|
|
396
|
+
elements[paragraphMarkIndex] = cloneElement(paragraphMarkProperties, { elements: [markElement, ...paragraphMarkProperties.elements ?? []] });
|
|
397
|
+
}
|
|
398
|
+
return captureVerbatimXml(cloneElement(root, { elements }));
|
|
399
|
+
};
|
|
400
|
+
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, propertySource, sectionProperties } = {}) => {
|
|
401
|
+
const serializablePropertyChangeCount = propertyChanges?.length ?? 0;
|
|
402
|
+
if (serializablePropertyChangeCount > 1) panic("A paragraph cannot serialize more than one w:pPrChange", { count: serializablePropertyChangeCount });
|
|
403
|
+
const paragraphMarkXml = paragraphMarkChange ? serializeParagraphMarkChange(paragraphMarkChange) : "";
|
|
404
|
+
const sectionPropertiesXml = serializeSectionProperties(sectionProperties);
|
|
405
|
+
const propertyChangesXml = (propertyChanges ?? []).map((change) => serializeParagraphPropertyChange(change));
|
|
406
|
+
const composedChildrenUseDateUtc = [
|
|
407
|
+
paragraphMarkXml,
|
|
408
|
+
sectionPropertiesXml,
|
|
409
|
+
...propertyChangesXml
|
|
410
|
+
].some((xml) => xml.includes(`${DATE_UTC_ATTRIBUTE}=`));
|
|
411
|
+
const verifiedSource = verifiedParagraphPropertySource(formatting, propertySource);
|
|
412
|
+
if (verifiedSource !== null && (!composedChildrenUseDateUtc || !sourceShadowsDateUtcPrefix(verifiedSource))) {
|
|
413
|
+
const sourceWithMark = paragraphMarkChange ? withParagraphMarkChange(verifiedSource, paragraphMarkChange) : verifiedSource;
|
|
414
|
+
return withTrailingParagraphPropertyChildren(sourceWithMark, [sectionPropertiesXml, ...propertyChangesXml]);
|
|
415
|
+
}
|
|
144
416
|
const parts = [];
|
|
145
417
|
const pushToggle = (name, value) => {
|
|
146
418
|
if (value === true) parts.push(`<w:${name}/>`);
|
|
@@ -156,13 +428,13 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
156
428
|
pushToggle("widowControl", formatting.widowControl);
|
|
157
429
|
const numPrXml = formatting.numPrFromStyle != null && numPrEqual(formatting.numPr, formatting.numPrFromStyle) ? "" : serializeNumbering(formatting.numPr);
|
|
158
430
|
if (numPrXml) parts.push(numPrXml);
|
|
431
|
+
pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
|
|
159
432
|
const bordersXml = serializeParagraphBorders(formatting.borders);
|
|
160
433
|
if (bordersXml) parts.push(bordersXml);
|
|
161
434
|
const shadingXml = serializeShading(formatting.shading);
|
|
162
435
|
if (shadingXml) parts.push(shadingXml);
|
|
163
436
|
const tabsXml = serializeTabStops(formatting.tabs);
|
|
164
437
|
if (tabsXml) parts.push(tabsXml);
|
|
165
|
-
pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
|
|
166
438
|
pushToggle("suppressAutoHyphens", formatting.suppressAutoHyphens);
|
|
167
439
|
pushToggle("kinsoku", formatting.kinsoku);
|
|
168
440
|
pushToggle("overflowPunct", formatting.overflowPunctuation);
|
|
@@ -176,12 +448,12 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
176
448
|
if (formatting.alignment) parts.push(`<w:jc w:val="${formatting.alignment}"/>`);
|
|
177
449
|
if (formatting.outlineLevel !== void 0) parts.push(`<w:outlineLvl w:val="${formatting.outlineLevel}"/>`);
|
|
178
450
|
if (paragraphMarkChange || formatting.runProperties || formatting.runInWithNext) {
|
|
179
|
-
const fullInner = `${paragraphMarkChange ?
|
|
451
|
+
const fullInner = `${paragraphMarkChange ? paragraphMarkXml : ""}${formatting.runProperties ? extractRPrInner(serializeTextFormatting(formatting.runProperties)) : ""}${formatting.runInWithNext ? "<w:specVanish/>" : ""}`;
|
|
180
452
|
if (fullInner.length > 0) parts.push(`<w:rPr>${fullInner}</w:rPr>`);
|
|
181
453
|
}
|
|
182
|
-
} else if (paragraphMarkChange) parts.push(`<w:rPr>${
|
|
183
|
-
parts.push(
|
|
184
|
-
if (
|
|
454
|
+
} else if (paragraphMarkChange) parts.push(`<w:rPr>${paragraphMarkXml}</w:rPr>`);
|
|
455
|
+
parts.push(sectionPropertiesXml);
|
|
456
|
+
if (propertyChangesXml.length > 0) parts.push(...propertyChangesXml);
|
|
185
457
|
const inner = parts.join("");
|
|
186
458
|
if (inner.length === 0) return "";
|
|
187
459
|
return `<w:pPr>${inner}</w:pPr>`;
|
|
@@ -206,17 +478,9 @@ function extractRPrInner(rPrXml) {
|
|
|
206
478
|
return rPrXml.slice(7, -8);
|
|
207
479
|
}
|
|
208
480
|
function serializeParagraphPropertyChange(change) {
|
|
209
|
-
const normalizedId = normalizeRevisionId(change.info.id);
|
|
210
|
-
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
211
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
212
|
-
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
213
|
-
const normalizedRsid = typeof change.info.rsid === "string" ? change.info.rsid.trim() : void 0;
|
|
214
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
215
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
216
|
-
if (normalizedRsid) attrs.push(`w:rsid="${escapeXml(normalizedRsid)}"`);
|
|
217
481
|
const previousPPrInner = extractPPrInner(serializeParagraphFormatting(change.previousFormatting) || "<w:pPr/>");
|
|
218
482
|
const normalizedPreviousPPr = previousPPrInner.length > 0 ? `<w:pPr>${previousPPrInner}</w:pPr>` : "<w:pPr/>";
|
|
219
|
-
return `<w:pPrChange ${
|
|
483
|
+
return `<w:pPrChange ${serializeTrackedChangeAttributes(change.info)}>${normalizedPreviousPPr}</w:pPrChange>`;
|
|
220
484
|
}
|
|
221
485
|
/** The attribute list of a `w:hyperlink`, without its children. */
|
|
222
486
|
function hyperlinkAttributes(hyperlink) {
|
|
@@ -390,13 +654,7 @@ function trackedChangeTag(change) {
|
|
|
390
654
|
}
|
|
391
655
|
}
|
|
392
656
|
function serializeTrackedChange(tag, change) {
|
|
393
|
-
const
|
|
394
|
-
const normalizedId = normalizeRevisionId(info.id);
|
|
395
|
-
const authorCandidate = typeof info.author === "string" ? info.author.trim() : "";
|
|
396
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
397
|
-
const normalizedDate = typeof info.date === "string" ? info.date.trim() : void 0;
|
|
398
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
399
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
657
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
400
658
|
const serializeDeletedRun = (run) => {
|
|
401
659
|
const xml = serializeRun(run);
|
|
402
660
|
if (!run.content.some((c) => c.type === "drawing" || c.type === "shape")) return rewriteRunTextAsDeleted(xml);
|
|
@@ -420,7 +678,7 @@ function serializeTrackedChange(tag, change) {
|
|
|
420
678
|
if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return serializeTrackedChange(trackedChangeTag(item), item);
|
|
421
679
|
return item.type === "bookmarkStart" ? serializeBookmarkStart(item) : serializeBookmarkEnd(item);
|
|
422
680
|
};
|
|
423
|
-
const open = `<w:${tag} ${attrs
|
|
681
|
+
const open = `<w:${tag} ${attrs}>`;
|
|
424
682
|
const close = `</w:${tag}>`;
|
|
425
683
|
const wrap = (inner) => inner.length === 0 ? "" : `${open}${inner}${close}`;
|
|
426
684
|
if (change.content.length === 0) return `${open}${close}`;
|
|
@@ -497,6 +755,7 @@ function serializeParagraph(paragraph) {
|
|
|
497
755
|
parts.push(serializeParagraphFormattingWithOptions(paragraph.formatting, {
|
|
498
756
|
propertyChanges: paragraph.propertyChanges,
|
|
499
757
|
paragraphMarkChange: paragraph.pPrMark,
|
|
758
|
+
propertySource: getParagraphPropertySource(paragraph),
|
|
500
759
|
sectionProperties: paragraph.sectionProperties
|
|
501
760
|
}));
|
|
502
761
|
const explicitCommentReferenceIds = /* @__PURE__ */ new Set();
|
|
@@ -5,9 +5,9 @@ import { THEME_COLOR_TO_DRAWING_SCHEME } from "../drawingUtils.js";
|
|
|
5
5
|
import { requiresXmlSpacePreserve } from "../textWhitespace.js";
|
|
6
6
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
7
7
|
import { serializeTable } from "./tableSerializer.js";
|
|
8
|
+
import { getSingularRunPropertyChange, serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
8
9
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
9
10
|
import { panic } from "better-result";
|
|
10
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
11
11
|
//#region src/docx/serializer/runSerializer.ts
|
|
12
12
|
/**
|
|
13
13
|
* Run Serializer - Serialize runs to OOXML XML
|
|
@@ -145,7 +145,7 @@ function serializeTextFormatting(formatting) {
|
|
|
145
145
|
}
|
|
146
146
|
parts.push(`<w:u ${uAttrs.join(" ")}/>`);
|
|
147
147
|
}
|
|
148
|
-
if (formatting.effect
|
|
148
|
+
if (formatting.effect) parts.push(`<w:effect w:val="${formatting.effect}"/>`);
|
|
149
149
|
const shadingXml = serializeShading(formatting.shading) || customHighlightShadingXml;
|
|
150
150
|
if (shadingXml) parts.push(shadingXml);
|
|
151
151
|
if (formatting.vertAlign) parts.push(`<w:vertAlign w:val="${formatting.vertAlign}"/>`);
|
|
@@ -169,20 +169,14 @@ function extractRPrInner(rPrXml) {
|
|
|
169
169
|
return rPrXml.slice(7, -8);
|
|
170
170
|
}
|
|
171
171
|
function serializeRunPropertyChange(change) {
|
|
172
|
-
const normalizedId = normalizeRevisionId(change.info.id);
|
|
173
|
-
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
174
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
175
|
-
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
176
|
-
const normalizedRsid = typeof change.info.rsid === "string" ? change.info.rsid.trim() : void 0;
|
|
177
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
178
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
179
|
-
if (normalizedRsid) attrs.push(`w:rsid="${escapeXml(normalizedRsid)}"`);
|
|
180
172
|
const previousRPrXml = serializeTextFormatting(change.previousFormatting) || "<w:rPr/>";
|
|
181
|
-
return `<w:rPrChange ${
|
|
173
|
+
return `<w:rPrChange ${serializeTrackedChangeAttributes(change.info)}>${previousRPrXml}</w:rPrChange>`;
|
|
182
174
|
}
|
|
183
175
|
function serializeRunProperties(formatting, propertyChanges) {
|
|
184
176
|
const currentRPrXml = serializeTextFormatting(formatting);
|
|
185
|
-
const
|
|
177
|
+
const currentInner = currentRPrXml ? extractRPrInner(currentRPrXml) : "";
|
|
178
|
+
const propertyChange = getSingularRunPropertyChange(propertyChanges);
|
|
179
|
+
const combined = `${currentInner}${propertyChange ? serializeRunPropertyChange(propertyChange) : ""}`;
|
|
186
180
|
if (!combined) return "";
|
|
187
181
|
return `<w:rPr>${combined}</w:rPr>`;
|
|
188
182
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getUnserializedSectionPropertyChildNames } from "../sectionParser.js";
|
|
2
2
|
import { serializeBorder } from "./borderSerializer.js";
|
|
3
|
+
import { serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
3
4
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
4
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
5
5
|
//#region src/docx/serializer/sectionPropertiesSerializer.ts
|
|
6
6
|
const serializeHeaderReference = (ref) => `<w:headerReference w:type="${ref.type}" r:id="${escapeXml(ref.rId)}"/>`;
|
|
7
7
|
const serializeFooterReference = (ref) => `<w:footerReference w:type="${ref.type}" r:id="${escapeXml(ref.rId)}"/>`;
|
|
@@ -133,16 +133,8 @@ function serializeOnOffElement(value, name) {
|
|
|
133
133
|
return value ? `<w:${name}/>` : `<w:${name} w:val="0"/>`;
|
|
134
134
|
}
|
|
135
135
|
function serializeSectionPropertyChange(change) {
|
|
136
|
-
const normalizedId = normalizeRevisionId(change.info.id);
|
|
137
|
-
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
138
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
139
|
-
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
140
|
-
const normalizedRsid = typeof change.info.rsid === "string" ? change.info.rsid.trim() : void 0;
|
|
141
|
-
const attrs = [`w:id="${normalizedId}"`, `w:author="${escapeXml(normalizedAuthor)}"`];
|
|
142
|
-
if (normalizedDate) attrs.push(`w:date="${escapeXml(normalizedDate)}"`);
|
|
143
|
-
if (normalizedRsid) attrs.push(`w:rsid="${escapeXml(normalizedRsid)}"`);
|
|
144
136
|
const previousSectPrXml = serializeSectionProperties(change.previousProperties) || "<w:sectPr/>";
|
|
145
|
-
return `<w:sectPrChange ${
|
|
137
|
+
return `<w:sectPrChange ${serializeTrackedChangeAttributes(change.info)}>${previousSectPrXml}</w:sectPrChange>`;
|
|
146
138
|
}
|
|
147
139
|
function serializeSectionProperties(props) {
|
|
148
140
|
if (!props) return "";
|
|
@@ -3,8 +3,8 @@ import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
|
3
3
|
import { parseTableCellProperties, parseTableGrid, parseTableProperties, parseTableRowProperties } from "../tableParser.js";
|
|
4
4
|
import { OOXML_NAMESPACE_SCOPE, parseXml } from "../xmlParser.js";
|
|
5
5
|
import { serializeBorder } from "./borderSerializer.js";
|
|
6
|
+
import { serializeTrackedChangeAttributes } from "./trackedChangeAttributes.js";
|
|
6
7
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
7
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
8
8
|
//#region src/docx/serializer/tableSerializer.ts
|
|
9
9
|
/**
|
|
10
10
|
* The captured element with the revision children written back into it.
|
|
@@ -69,25 +69,6 @@ const verifiedSourceXml = (formatting, parse) => {
|
|
|
69
69
|
const reparsed = parse(parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.[0] ?? null);
|
|
70
70
|
return canonicalJson(withoutCaptures(reparsed)) === canonicalJson(withoutCaptures(formatting)) ? sourceXml : null;
|
|
71
71
|
};
|
|
72
|
-
function normalizeTrackedChangeInfo(info) {
|
|
73
|
-
const normalizedId = normalizeRevisionId(info.id);
|
|
74
|
-
const authorCandidate = typeof info.author === "string" ? info.author.trim() : "";
|
|
75
|
-
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
76
|
-
const normalizedDate = typeof info.date === "string" ? info.date.trim() : void 0;
|
|
77
|
-
return {
|
|
78
|
-
id: normalizedId,
|
|
79
|
-
author: normalizedAuthor,
|
|
80
|
-
...normalizedDate !== void 0 ? { date: normalizedDate } : {}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function serializeTrackedChangeAttributes(info, rsid) {
|
|
84
|
-
const normalized = normalizeTrackedChangeInfo(info);
|
|
85
|
-
const attrs = [`w:id="${normalized.id}"`, `w:author="${escapeXml(normalized.author)}"`];
|
|
86
|
-
if (normalized.date) attrs.push(`w:date="${escapeXml(normalized.date)}"`);
|
|
87
|
-
if (info.utcDate) attrs.push(`${info.utcDate.attribute}="${escapeXml(info.utcDate.value)}"`);
|
|
88
|
-
if (rsid && rsid.trim().length > 0) attrs.push(`w:rsid="${escapeXml(rsid.trim())}"`);
|
|
89
|
-
return attrs.join(" ");
|
|
90
|
-
}
|
|
91
72
|
/**
|
|
92
73
|
* Serialize a table measurement (width, height)
|
|
93
74
|
*/
|
|
@@ -231,7 +212,7 @@ function extractTblPrInner(tblPrXml) {
|
|
|
231
212
|
return tblPrXml.slice(9, -10);
|
|
232
213
|
}
|
|
233
214
|
function serializeTablePropertyChange(change) {
|
|
234
|
-
const attrs = serializeTrackedChangeAttributes(change.info
|
|
215
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
235
216
|
const previousTblPrInner = extractTblPrInner(serializeTableFormatting(change.previousFormatting) || "<w:tblPr/>");
|
|
236
217
|
return `<w:tblPrChange ${attrs}>${previousTblPrInner.length > 0 ? `<w:tblPr>${previousTblPrInner}</w:tblPr>` : "<w:tblPr/>"}</w:tblPrChange>`;
|
|
237
218
|
}
|
|
@@ -269,7 +250,7 @@ function extractTrPrInner(trPrXml) {
|
|
|
269
250
|
return trPrXml.slice(8, -9);
|
|
270
251
|
}
|
|
271
252
|
function serializeTableRowPropertyChange(change) {
|
|
272
|
-
const attrs = serializeTrackedChangeAttributes(change.info
|
|
253
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
273
254
|
const previousTrPrInner = extractTrPrInner(serializeTableRowFormatting(change.previousFormatting) || "<w:trPr/>");
|
|
274
255
|
return `<w:trPrChange ${attrs}>${previousTrPrInner.length > 0 ? `<w:trPr>${previousTrPrInner}</w:trPr>` : "<w:trPr/>"}</w:trPrChange>`;
|
|
275
256
|
}
|
|
@@ -333,7 +314,7 @@ function extractTcPrInner(tcPrXml) {
|
|
|
333
314
|
return tcPrXml.slice(8, -9);
|
|
334
315
|
}
|
|
335
316
|
function serializeTableCellPropertyChange(change) {
|
|
336
|
-
const attrs = serializeTrackedChangeAttributes(change.info
|
|
317
|
+
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
337
318
|
const previousTcPrInner = extractTcPrInner(serializeTableCellFormatting(change.previousFormatting) || "<w:tcPr/>");
|
|
338
319
|
return `<w:tcPrChange ${attrs}>${previousTcPrInner.length > 0 ? `<w:tcPr>${previousTcPrInner}</w:tcPr>` : "<w:tcPr/>"}</w:tcPrChange>`;
|
|
339
320
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
//#region src/docx/serializer/trackedChangeAttributes.d.ts
|
|
3
|
+
type SerializableTrackedChangeInfo = document_d_exports.TrackedChangeInfo | document_d_exports.PropertyChangeInfo;
|
|
4
|
+
/** Enforces the singular `w:rPrChange` child in a run-property container. */
|
|
5
|
+
declare const getSingularRunPropertyChange: (propertyChanges: readonly document_d_exports.RunPropertyChange[] | undefined) => document_d_exports.RunPropertyChange | undefined;
|
|
6
|
+
/** Normalized, unescaped attributes in schema order for an XML element or string serializer. */
|
|
7
|
+
declare const trackedChangeAttributeEntries: (info: SerializableTrackedChangeInfo) => readonly (readonly [string, string])[];
|
|
8
|
+
declare const trackedChangeAttributeRecord: (info: SerializableTrackedChangeInfo) => Record<string, string>;
|
|
9
|
+
declare const serializeTrackedChangeAttributes: (info: SerializableTrackedChangeInfo) => string;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { getSingularRunPropertyChange, serializeTrackedChangeAttributes, trackedChangeAttributeEntries, trackedChangeAttributeRecord };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
2
|
+
import { escapeXml } from "./xmlUtils.js";
|
|
3
|
+
import { panic } from "better-result";
|
|
4
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
5
|
+
//#region src/docx/serializer/trackedChangeAttributes.ts
|
|
6
|
+
/** Enforces the singular `w:rPrChange` child in a run-property container. */
|
|
7
|
+
const getSingularRunPropertyChange = (propertyChanges) => {
|
|
8
|
+
const propertyChangeCount = propertyChanges?.length ?? 0;
|
|
9
|
+
if (propertyChangeCount > 1) panic("A run-property container cannot serialize more than one w:rPrChange", {
|
|
10
|
+
elementName: "w:rPrChange",
|
|
11
|
+
propertyChangeCount
|
|
12
|
+
});
|
|
13
|
+
return propertyChanges?.at(0);
|
|
14
|
+
};
|
|
15
|
+
/** Normalized, unescaped attributes in schema order for an XML element or string serializer. */
|
|
16
|
+
const trackedChangeAttributeEntries = (info) => {
|
|
17
|
+
const author = typeof info.author === "string" ? info.author.trim() : "";
|
|
18
|
+
const date = typeof info.date === "string" ? info.date.trim() : "";
|
|
19
|
+
const rawUtcDate = info.utcDate;
|
|
20
|
+
const utcDate = typeof rawUtcDate === "object" && rawUtcDate !== null && "value" in rawUtcDate && typeof rawUtcDate.value === "string" ? rawUtcDate.value.trim() : "";
|
|
21
|
+
const rsid = "rsid" in info && typeof info.rsid === "string" ? info.rsid.trim() : "";
|
|
22
|
+
const entries = [["w:id", String(normalizeRevisionId(info.id))], ["w:author", author.length > 0 ? author : "Unknown"]];
|
|
23
|
+
if (date.length > 0) entries.push(["w:date", date]);
|
|
24
|
+
if (utcDate.length > 0) entries.push([DATE_UTC_ATTRIBUTE, utcDate]);
|
|
25
|
+
if (rsid.length > 0) entries.push(["w:rsid", rsid]);
|
|
26
|
+
return entries;
|
|
27
|
+
};
|
|
28
|
+
const trackedChangeAttributeRecord = (info) => Object.fromEntries(trackedChangeAttributeEntries(info));
|
|
29
|
+
const serializeTrackedChangeAttributes = (info) => trackedChangeAttributeEntries(info).map(([name, value]) => `${name}="${escapeXml(value)}"`).join(" ");
|
|
30
|
+
//#endregion
|
|
31
|
+
export { getSingularRunPropertyChange, serializeTrackedChangeAttributes, trackedChangeAttributeEntries, trackedChangeAttributeRecord };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ShadingProperties } from "../../types/colors.js";
|
|
2
2
|
import { document_d_exports } from "../../types/document.js";
|
|
3
|
-
import { Hyperlink, Paragraph, ParagraphContent, Run, Table } from "../../types/content.js";
|
|
4
3
|
import { ParagraphFormatting, TextFormatting } from "../../types/formatting.js";
|
|
4
|
+
import { Hyperlink, Paragraph, ParagraphContent, Run, Table } from "../../types/content.js";
|
|
5
5
|
//#region src/docx/server/build.d.ts
|
|
6
6
|
declare const HEADING_LEVELS: readonly [1, 2, 3, 4, 5, 6];
|
|
7
7
|
type HeadingLevel = (typeof HEADING_LEVELS)[number];
|