@stll/folio-core 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/apply.d.ts +2 -1
- package/dist/ai-edits/apply.js +693 -63
- package/dist/ai-edits/block-identity.d.ts +4 -0
- package/dist/ai-edits/block-identity.js +9 -0
- package/dist/ai-edits/blockRange.d.ts +28 -1
- package/dist/ai-edits/blockRange.js +68 -2
- package/dist/ai-edits/clean-text.js +2 -1
- package/dist/ai-edits/headless.d.ts +4 -4
- package/dist/ai-edits/headless.js +9 -9
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.d.ts +7 -7
- package/dist/ai-edits/read.js +110 -3
- package/dist/ai-edits/snapshot.js +21 -3
- package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
- package/dist/ai-edits/table-cell-mutations.js +238 -0
- package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
- package/dist/ai-edits/table-mutation-plan.js +90 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +108 -0
- package/dist/ai-edits/table-row-column-mutations.js +300 -0
- package/dist/ai-edits/table-targets.d.ts +32 -0
- package/dist/ai-edits/table-targets.js +70 -0
- package/dist/ai-edits/types.d.ts +62 -1
- package/dist/ai-edits/word-diff.js +21 -0
- package/dist/compat/eigenpal.d.ts +3 -3
- package/dist/compat/eigenpal.js +3 -3
- package/dist/content-controls/mutateContentControls.js +1 -1
- package/dist/controller/activeEditorStory.d.ts +36 -0
- package/dist/controller/activeEditorStory.js +30 -0
- package/dist/controller/contentControlWidgetController.d.ts +55 -0
- package/dist/controller/contentControlWidgetController.js +141 -0
- package/dist/controller/fontReadiness.js +2 -0
- package/dist/controller/headerFooterEditorManager.js +2 -2
- package/dist/controller/hiddenEditorApi.js +2 -2
- package/dist/controller/hiddenEditorManager.d.ts +12 -1
- package/dist/controller/hiddenEditorManager.js +44 -12
- package/dist/controller/layoutPipeline.d.ts +2 -0
- package/dist/controller/layoutPipeline.js +17 -2
- package/dist/controller/noteEditorManager.d.ts +36 -0
- package/dist/controller/noteEditorManager.js +210 -0
- package/dist/document-operations.d.ts +43 -11
- package/dist/document-operations.js +186 -18
- package/dist/docx/blockContentParser.js +21 -7
- package/dist/docx/commentParser.js +6 -1
- package/dist/docx/commentRangeIntegrity.d.ts +6 -0
- package/dist/docx/commentRangeIntegrity.js +186 -0
- package/dist/docx/conformance.js +62 -1
- package/dist/docx/documentGrid.d.ts +8 -0
- package/dist/docx/documentGrid.js +8 -0
- package/dist/docx/drawingUtils.js +1 -1
- package/dist/docx/encryption/agileDecryption.js +12 -2
- package/dist/docx/encryption/compoundFile.js +6 -1
- package/dist/docx/encryption/encryptionInfo.d.ts +9 -1
- package/dist/docx/encryption/encryptionInfo.js +18 -2
- package/dist/docx/encryption/openEncryptedDocx.js +1 -1
- package/dist/docx/ensureParaIds.js +8 -7
- package/dist/docx/fieldParser.js +1 -1
- package/dist/docx/groupDrawingParser.js +10 -5
- package/dist/docx/hyperlinkParser.js +1 -1
- package/dist/docx/imageParser.js +10 -6
- package/dist/docx/metadataPrivacy.js +17 -3
- package/dist/docx/notePropertiesParser.js +1 -1
- package/dist/docx/numberingParser.js +1 -1
- package/dist/docx/paragraphParser.js +70 -61
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/parser.js +3 -3
- package/dist/docx/rezip.js +20 -9
- package/dist/docx/runParser.js +17 -6
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sectionParser.js +18 -5
- package/dist/docx/selectiveSave.js +5 -1
- package/dist/docx/selectiveXmlPatch.d.ts +22 -1
- package/dist/docx/selectiveXmlPatch.js +61 -1
- package/dist/docx/serializer/blockSdtSerializer.js +3 -2
- package/dist/docx/serializer/commentSerializer.js +5 -6
- package/dist/docx/serializer/documentSerializer.js +2 -2
- package/dist/docx/serializer/headerFooterSerializer.js +2 -2
- package/dist/docx/serializer/noteSerializer.js +2 -2
- package/dist/docx/serializer/paragraphSerializer.js +23 -15
- package/dist/docx/serializer/runSerializer.js +25 -21
- package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -1
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/tableSerializer.d.ts +5 -4
- package/dist/docx/serializer/tableSerializer.js +26 -20
- package/dist/docx/serializer/xmlUtils.d.ts +13 -1
- package/dist/docx/serializer/xmlUtils.js +27 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
- package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
- package/dist/docx/server/boundedArchive.d.ts +14 -3
- package/dist/docx/server/boundedArchive.js +56 -11
- package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
- package/dist/docx/server/extractDocxText.js +55 -8
- package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
- package/dist/docx/server/inspectDocxPackage.js +217 -0
- package/dist/docx/server/validateDocxConformance.d.ts +41 -0
- package/dist/docx/server/validateDocxConformance.js +336 -0
- package/dist/docx/settingsParser.js +26 -3
- package/dist/docx/shapeParser.js +1 -1
- package/dist/docx/styleParser.js +4 -2
- package/dist/docx/tableParser.d.ts +8 -1
- package/dist/docx/tableParser.js +31 -10
- package/dist/docx/textBoxParser.d.ts +3 -3
- package/dist/docx/textBoxParser.js +16 -12
- package/dist/docx/unzip.js +1 -0
- package/dist/docx/vmlImageParser.js +11 -3
- package/dist/docx/xmlParser.js +11 -1
- package/dist/docx/xmlSafety.d.ts +5 -0
- package/dist/docx/xmlSafety.js +9 -0
- package/dist/fields/resolveFieldValues.js +1 -3
- package/dist/fonts/embeddedFonts.d.ts +33 -5
- package/dist/fonts/embeddedFonts.js +37 -8
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
- package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +151 -20
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
- package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
- package/dist/layout-bridge/engine/clickToPosition.js +2 -2
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +58 -30
- package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
- package/dist/layout-engine/justificationCompatibility.js +8 -0
- package/dist/layout-engine/keep-together.js +11 -1
- package/dist/layout-engine/measure/cache.js +23 -5
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +8 -2
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +2 -2
- package/dist/layout-engine/measure/lineBreakProvider.js +56 -37
- package/dist/layout-engine/measure/measureBlocks.js +15 -4
- package/dist/layout-engine/measure/measureContainer.js +1 -1
- package/dist/layout-engine/measure/measureHelpers.d.ts +11 -2
- package/dist/layout-engine/measure/measureHelpers.js +15 -4
- package/dist/layout-engine/measure/measureParagraph.js +85 -25
- package/dist/layout-engine/measure/measureProvider.js +4 -3
- package/dist/layout-engine/measure/tableCellFlow.js +5 -2
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
- package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
- package/dist/layout-engine/paginator.js +5 -1
- package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
- package/dist/layout-engine/paragraphSpacing.js +107 -13
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +48 -15
- package/dist/layout-painter/registry/modules/textBox.js +5 -1
- package/dist/layout-painter/renderImage.d.ts +12 -1
- package/dist/layout-painter/renderImage.js +21 -4
- package/dist/layout-painter/renderPage.d.ts +5 -2
- package/dist/layout-painter/renderPage.js +59 -14
- package/dist/layout-painter/renderParagraph.js +55 -15
- package/dist/layout-painter/renderTable.d.ts +5 -1
- package/dist/layout-painter/renderTable.js +7 -3
- package/dist/layout-painter/renderTextBox.d.ts +2 -1
- package/dist/layout-painter/renderTextBox.js +25 -14
- package/dist/layout-painter/renderWatermark.d.ts +1 -1
- package/dist/layout-painter/renderWatermark.js +2 -1
- package/dist/managers/DocumentLoaderManager.js +1 -1
- package/dist/markdown/fromMarkdown.js +1 -1
- package/dist/model.js +1 -1
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +175 -18
- package/dist/prosemirror/commands/comments.d.ts +79 -4
- package/dist/prosemirror/commands/comments.js +622 -13
- package/dist/prosemirror/commands/contentControls.js +1 -1
- package/dist/prosemirror/commands/hyperlink.js +15 -1
- package/dist/prosemirror/commands/image.js +7 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
- package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
- package/dist/prosemirror/commentIdAllocator.js +13 -3
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +404 -62
- package/dist/prosemirror/conversion/index.js +1 -1
- package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
- package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/toProseDoc.js +364 -103
- package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
- package/dist/prosemirror/extensions/StarterKit.js +6 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +6 -2
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +10 -2
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +15 -2
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +30 -4
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +70 -11
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +14 -6
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
- package/dist/prosemirror/index.d.ts +1 -1
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +36 -10
- package/dist/prosemirror/plugins/contentControlWidgets.js +128 -94
- package/dist/prosemirror/plugins/revisionIds.d.ts +23 -0
- package/dist/prosemirror/plugins/revisionIds.js +57 -0
- package/dist/prosemirror/plugins/selectionTracker.js +1 -0
- package/dist/prosemirror/plugins/suggestionMode.js +5 -4
- package/dist/prosemirror/runFormattingMarkNames.d.ts +14 -0
- package/dist/prosemirror/runFormattingMarkNames.js +40 -0
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +30 -3
- package/dist/prosemirror/schema/marks.js +15 -0
- package/dist/prosemirror/schema/nodes.d.ts +111 -6
- package/dist/prosemirror/selectionState.js +1 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
- package/dist/prosemirror/tableCellMergeRevision.js +22 -0
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
- package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
- package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
- package/dist/prosemirror/validation.js +9 -1
- package/dist/render-dom/RemoteSelectionOverlay.js +2 -2
- package/dist/server.d.ts +7 -3
- package/dist/server.js +7 -3
- package/dist/utils/clipboard.d.ts +10 -1
- package/dist/utils/clipboard.js +33 -6
- package/dist/utils/colorResolver.d.ts +8 -1
- package/dist/utils/colorResolver.js +35 -5
- package/dist/utils/fontFamilyMerge.js +9 -11
- package/dist/utils/fontLoader.js +3 -2
- package/dist/utils/fontResolver.d.ts +2 -1
- package/dist/utils/fontResolver.js +31 -7
- package/dist/utils/fontWeights.d.ts +1 -1
- package/dist/utils/fontWeights.js +1 -1
- package/dist/utils/hexId.d.ts +11 -1
- package/dist/utils/hexId.js +11 -1
- package/dist/utils/paragraphFormattingMerge.js +1 -0
- package/dist/utils/sanitizeImageSrc.d.ts +21 -0
- package/dist/utils/sanitizeImageSrc.js +30 -0
- package/dist/utils/stripXmlDeclarations.d.ts +11 -0
- package/dist/utils/stripXmlDeclarations.js +35 -0
- package/dist/version-comparison.d.ts +22 -2
- package/dist/version-comparison.js +41 -12
- package/dist/watermark/index.d.ts +11 -1
- package/dist/watermark/index.js +22 -1
- package/package.json +3 -2
|
@@ -74,6 +74,66 @@ function extractParagraphXml(serializedXml, paraId) {
|
|
|
74
74
|
return serializedXml.slice(offsets.start, offsets.end);
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
|
+
* Single linear-scan index of every `<w:p>` element's start/end offsets,
|
|
78
|
+
* keyed by `w14:paraId`. Generalizes {@link findParagraphOffsets} (one
|
|
79
|
+
* regex-scan-plus-depth-walk per lookup) to build every paragraph's offsets
|
|
80
|
+
* in a single pass, so a caller that needs many paragraphs from the same XML
|
|
81
|
+
* (e.g. `collectChangedNoteParaIds` in rezip.ts, walking every note paraId)
|
|
82
|
+
* does O(1) map lookups afterward instead of re-scanning the whole XML once
|
|
83
|
+
* per id — O(ids * XML length) collapses to O(XML length).
|
|
84
|
+
*
|
|
85
|
+
* A `<w:p>` nested inside another (e.g. inside `mc:AlternateContent`) is
|
|
86
|
+
* indexed too via a depth stack, matching every element `findParagraphOffsets`
|
|
87
|
+
* can resolve. A paraId that appears on more than one element is ambiguous —
|
|
88
|
+
* mirroring {@link findParagraphOffsets}'s single-match requirement — and is
|
|
89
|
+
* omitted from the index, so a lookup misses exactly where the per-id
|
|
90
|
+
* function would return null.
|
|
91
|
+
*/
|
|
92
|
+
function buildParagraphOffsetIndex(xml) {
|
|
93
|
+
const seenCount = /* @__PURE__ */ new Map();
|
|
94
|
+
const ranges = /* @__PURE__ */ new Map();
|
|
95
|
+
const stack = [];
|
|
96
|
+
let pos = 0;
|
|
97
|
+
const noteOpen = (paraId) => {
|
|
98
|
+
if (paraId) seenCount.set(paraId, (seenCount.get(paraId) ?? 0) + 1);
|
|
99
|
+
};
|
|
100
|
+
const noteRange = (paraId, start, end) => {
|
|
101
|
+
if (paraId) ranges.set(paraId, {
|
|
102
|
+
start,
|
|
103
|
+
end
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
while (pos < xml.length) {
|
|
107
|
+
const tagStart = xml.indexOf("<", pos);
|
|
108
|
+
if (tagStart === -1) break;
|
|
109
|
+
if (xml.startsWith("</w:p>", tagStart)) {
|
|
110
|
+
const frame = stack.pop();
|
|
111
|
+
const end = tagStart + 6;
|
|
112
|
+
if (frame) noteRange(frame.paraId, frame.start, end);
|
|
113
|
+
pos = end;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!xml.startsWith("<w:p", tagStart) || !isXmlNameBoundary(xml[tagStart + 4])) {
|
|
117
|
+
pos = tagStart + 1;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const tagEnd = xml.indexOf(">", tagStart);
|
|
121
|
+
if (tagEnd === -1) break;
|
|
122
|
+
const openTag = xml.slice(tagStart, tagEnd + 1);
|
|
123
|
+
const paraId = /\bw14:paraId="(?<id>[^"]*)"/u.exec(openTag)?.groups?.["id"];
|
|
124
|
+
noteOpen(paraId);
|
|
125
|
+
if (xml[tagEnd - 1] === "/") noteRange(paraId, tagStart, tagEnd + 1);
|
|
126
|
+
else stack.push({
|
|
127
|
+
start: tagStart,
|
|
128
|
+
paraId
|
|
129
|
+
});
|
|
130
|
+
pos = tagEnd + 1;
|
|
131
|
+
}
|
|
132
|
+
const index = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const [id, range] of ranges) if (seenCount.get(id) === 1) index.set(id, range);
|
|
134
|
+
return index;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
77
137
|
* Count <w:p> elements in an XML string (top-level paragraph count).
|
|
78
138
|
* Counts opening <w:p tags that are NOT self-closing.
|
|
79
139
|
*/
|
|
@@ -484,4 +544,4 @@ function escapeRegExp(str) {
|
|
|
484
544
|
return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
485
545
|
}
|
|
486
546
|
//#endregion
|
|
487
|
-
export { buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
|
|
547
|
+
export { buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSingleWellFormedElement } from "./xmlUtils.js";
|
|
1
2
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
2
3
|
//#region src/docx/serializer/blockSdtSerializer.ts
|
|
3
4
|
function escapeXmlAttr(value) {
|
|
@@ -73,14 +74,14 @@ function extractDateFullDate(blockSdt) {
|
|
|
73
74
|
}
|
|
74
75
|
function serializeBlockSdt(blockSdt, serializeChild) {
|
|
75
76
|
const props = blockSdt.properties;
|
|
76
|
-
const baseSdtPr = props.rawPropertiesXml
|
|
77
|
+
const baseSdtPr = props.rawPropertiesXml && isSingleWellFormedElement(props.rawPropertiesXml, "sdtPr") ? props.rawPropertiesXml : serializeFallbackSdtPr(props);
|
|
77
78
|
const dateFullDate = extractDateFullDate(blockSdt);
|
|
78
79
|
const dropdownLastValue = extractDropdownLastValue(blockSdt);
|
|
79
80
|
const sdtPrXml = reconcileRawSdtPr(baseSdtPr, props, {
|
|
80
81
|
...dateFullDate !== void 0 ? { dateFullDate } : {},
|
|
81
82
|
...dropdownLastValue !== void 0 ? { dropdownLastValue } : {}
|
|
82
83
|
});
|
|
83
|
-
const sdtEndPrXml = props.rawEndPropertiesXml
|
|
84
|
+
const sdtEndPrXml = props.rawEndPropertiesXml && isSingleWellFormedElement(props.rawEndPropertiesXml, "sdtEndPr") ? props.rawEndPropertiesXml : "";
|
|
84
85
|
const contentXml = blockSdt.content.map(serializeChild).join("");
|
|
85
86
|
return `<w:sdt>${sdtPrXml}${sdtEndPrXml}${props.rawSdtChildrenBeforeContent ?? ""}<w:sdtContent>${contentXml}</w:sdtContent>${props.rawSdtChildrenAfterContent ?? ""}</w:sdt>`;
|
|
86
87
|
}
|
|
@@ -27,8 +27,8 @@ function serializeRunContent(run) {
|
|
|
27
27
|
*/
|
|
28
28
|
function commentParagraphOpenTag(p) {
|
|
29
29
|
const attrs = [];
|
|
30
|
-
if (p.paraId) attrs.push(`w14:paraId="${p.paraId}"`);
|
|
31
|
-
if (p.textId) attrs.push(`w14:textId="${p.textId}"`);
|
|
30
|
+
if (p.paraId) attrs.push(`w14:paraId="${escapeXml(p.paraId)}"`);
|
|
31
|
+
if (p.textId) attrs.push(`w14:textId="${escapeXml(p.textId)}"`);
|
|
32
32
|
return attrs.length > 0 ? `<w:p ${attrs.join(" ")}>` : "<w:p>";
|
|
33
33
|
}
|
|
34
34
|
function serializeParagraph(p) {
|
|
@@ -46,8 +46,7 @@ function serializeParagraphWithAnnotationRef(p) {
|
|
|
46
46
|
return xml;
|
|
47
47
|
}
|
|
48
48
|
function serializeComment(comment) {
|
|
49
|
-
const attrs = [`w:id="${comment.id}"`];
|
|
50
|
-
if (comment.author) attrs.push(`w:author="${escapeXml(comment.author)}"`);
|
|
49
|
+
const attrs = [`w:id="${comment.id}"`, `w:author="${escapeXml(comment.author)}"`];
|
|
51
50
|
if (comment.initials) attrs.push(`w:initials="${escapeXml(comment.initials)}"`);
|
|
52
51
|
if (comment.date) attrs.push(`w:date="${escapeXml(comment.date)}"`);
|
|
53
52
|
let xml = `<w:comment ${attrs.join(" ")}>`;
|
|
@@ -174,8 +173,8 @@ function serializeCommentsExtended(comments) {
|
|
|
174
173
|
if (!entries) return null;
|
|
175
174
|
let xml = COMMENTS_EXTENDED_HEADER;
|
|
176
175
|
for (const entry of entries) {
|
|
177
|
-
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${entry.paraIdParent}"` : "";
|
|
178
|
-
xml += `<w15:commentEx w15:paraId="${entry.paraId}"${parentAttr} w15:done="${entry.done ? "1" : "0"}"/>`;
|
|
176
|
+
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${escapeXml(entry.paraIdParent)}"` : "";
|
|
177
|
+
xml += `<w15:commentEx w15:paraId="${escapeXml(entry.paraId)}"${parentAttr} w15:done="${entry.done ? "1" : "0"}"/>`;
|
|
179
178
|
}
|
|
180
179
|
xml += "</w15:commentsEx>";
|
|
181
180
|
return xml;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
2
|
+
import { serializeTable } from "./tableSerializer.js";
|
|
2
3
|
import { resetAutoIdCounter } from "./runSerializer.js";
|
|
3
4
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
4
5
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
5
|
-
import { serializeTable } from "./tableSerializer.js";
|
|
6
6
|
//#region src/docx/serializer/documentSerializer.ts
|
|
7
7
|
/**
|
|
8
8
|
* Standard OOXML namespaces for document.xml
|
|
@@ -74,7 +74,7 @@ function buildNamespaceDeclarations() {
|
|
|
74
74
|
*/
|
|
75
75
|
function serializeBlockContent(block) {
|
|
76
76
|
if (block.type === "paragraph") return serializeParagraph(block);
|
|
77
|
-
if (block.type === "table") return serializeTable(block);
|
|
77
|
+
if (block.type === "table") return serializeTable(block, serializeParagraph);
|
|
78
78
|
return serializeBlockSdt(block, serializeBlockContent);
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { canReplayHeaderFooterVerbatim, getHeaderFooterVerbatimXml } from "../headerFooterVerbatim.js";
|
|
2
2
|
import { escapeXml } from "./xmlUtils.js";
|
|
3
3
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
4
|
-
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
5
4
|
import { serializeTable } from "./tableSerializer.js";
|
|
5
|
+
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
6
6
|
//#region src/docx/serializer/headerFooterSerializer.ts
|
|
7
7
|
const NAMESPACES = {
|
|
8
8
|
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
|
|
@@ -36,7 +36,7 @@ function buildNamespaceDeclarations() {
|
|
|
36
36
|
*/
|
|
37
37
|
function serializeBlock(block) {
|
|
38
38
|
if (block.type === "paragraph") return serializeParagraph(block);
|
|
39
|
-
if (block.type === "table") return serializeTable(block);
|
|
39
|
+
if (block.type === "table") return serializeTable(block, serializeParagraph);
|
|
40
40
|
return serializeBlockSdt(block, serializeBlock);
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
2
|
-
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
2
|
import { serializeTable } from "./tableSerializer.js";
|
|
3
|
+
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
4
4
|
//#region src/docx/serializer/noteSerializer.ts
|
|
5
5
|
const NAMESPACES = {
|
|
6
6
|
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
|
|
@@ -34,7 +34,7 @@ function buildNamespaceDeclarations() {
|
|
|
34
34
|
*/
|
|
35
35
|
function serializeBlock(block) {
|
|
36
36
|
if (block.type === "paragraph") return serializeParagraph(block);
|
|
37
|
-
if (block.type === "table") return serializeTable(block);
|
|
37
|
+
if (block.type === "table") return serializeTable(block, serializeParagraph);
|
|
38
38
|
return serializeBlockSdt(block, serializeBlock);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { numPrEqual } from "../numberingParser.js";
|
|
2
|
-
import {
|
|
2
|
+
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
3
|
+
import { escapeXml, intAttr, isSingleWellFormedElement } from "./xmlUtils.js";
|
|
3
4
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
4
5
|
import { serializeBorder } from "./borderSerializer.js";
|
|
5
6
|
import { serializeRun, serializeTextFormatting } from "./runSerializer.js";
|
|
6
7
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
8
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
7
9
|
//#region src/docx/serializer/paragraphSerializer.ts
|
|
8
10
|
/**
|
|
9
11
|
* Serialize paragraph borders (w:pBdr)
|
|
@@ -44,15 +46,15 @@ function serializeParagraphBorders(borders) {
|
|
|
44
46
|
function serializeShading(shading) {
|
|
45
47
|
if (!shading) return "";
|
|
46
48
|
const attrs = [];
|
|
47
|
-
if (shading.pattern) attrs.push(`w:val="${shading.pattern}"`);
|
|
49
|
+
if (shading.pattern) attrs.push(`w:val="${escapeXml(shading.pattern)}"`);
|
|
48
50
|
else attrs.push("w:val=\"clear\"");
|
|
49
|
-
if (shading.color?.rgb) attrs.push(`w:color="${shading.color.rgb}"`);
|
|
51
|
+
if (shading.color?.rgb && isValidHexColor(shading.color.rgb)) attrs.push(`w:color="${escapeXml(shading.color.rgb)}"`);
|
|
50
52
|
else if (shading.color?.auto) attrs.push("w:color=\"auto\"");
|
|
51
|
-
if (shading.fill?.rgb) attrs.push(`w:fill="${shading.fill.rgb}"`);
|
|
53
|
+
if (shading.fill?.rgb && isValidHexColor(shading.fill.rgb)) attrs.push(`w:fill="${escapeXml(shading.fill.rgb)}"`);
|
|
52
54
|
else if (shading.fill?.auto) attrs.push("w:fill=\"auto\"");
|
|
53
|
-
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${shading.fill.themeColor}"`);
|
|
54
|
-
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${shading.fill.themeTint}"`);
|
|
55
|
-
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${shading.fill.themeShade}"`);
|
|
55
|
+
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${escapeXml(shading.fill.themeColor)}"`);
|
|
56
|
+
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${escapeXml(shading.fill.themeTint)}"`);
|
|
57
|
+
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${escapeXml(shading.fill.themeShade)}"`);
|
|
56
58
|
if (attrs.length === 0) return "";
|
|
57
59
|
return `<w:shd ${attrs.join(" ")}/>`;
|
|
58
60
|
}
|
|
@@ -132,7 +134,7 @@ function serializeFrameProperties(frame) {
|
|
|
132
134
|
* Serialize paragraph formatting properties to w:pPr XML
|
|
133
135
|
*/
|
|
134
136
|
function serializeTrackedChangeAttrs(info) {
|
|
135
|
-
const parts = [`w:id="${info.id}"`, `w:author="${escapeXml(info.author)}"`];
|
|
137
|
+
const parts = [`w:id="${normalizeRevisionId(info.id)}"`, `w:author="${escapeXml(info.author)}"`];
|
|
136
138
|
if (info.date !== void 0) parts.push(`w:date="${escapeXml(info.date)}"`);
|
|
137
139
|
return parts.join(" ");
|
|
138
140
|
}
|
|
@@ -155,6 +157,7 @@ function serializeParagraphFormatting(formatting, propertyChanges, pPrMark) {
|
|
|
155
157
|
const frameXml = serializeFrameProperties(formatting.frame);
|
|
156
158
|
if (frameXml) parts.push(frameXml);
|
|
157
159
|
pushToggle("widowControl", formatting.widowControl);
|
|
160
|
+
pushToggle("snapToGrid", formatting.snapToGrid);
|
|
158
161
|
const numPrXml = formatting.numPrFromStyle != null && numPrEqual(formatting.numPr, formatting.numPrFromStyle) ? "" : serializeNumbering(formatting.numPr);
|
|
159
162
|
if (numPrXml) parts.push(numPrXml);
|
|
160
163
|
const bordersXml = serializeParagraphBorders(formatting.borders);
|
|
@@ -197,7 +200,7 @@ function extractRPrInner(rPrXml) {
|
|
|
197
200
|
return rPrXml.slice(7, -8);
|
|
198
201
|
}
|
|
199
202
|
function serializeParagraphPropertyChange(change) {
|
|
200
|
-
const normalizedId =
|
|
203
|
+
const normalizedId = normalizeRevisionId(change.info.id);
|
|
201
204
|
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
202
205
|
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
203
206
|
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
@@ -354,17 +357,19 @@ function serializeInlineSdt(sdt) {
|
|
|
354
357
|
case "inlineSdt": return serializeInlineSdt(item);
|
|
355
358
|
case "insertion": return serializeTrackedChange("ins", item);
|
|
356
359
|
case "deletion": return serializeTrackedChange("del", item);
|
|
360
|
+
case "moveFrom": return serializeTrackedChange("moveFrom", item);
|
|
361
|
+
case "moveTo": return serializeTrackedChange("moveTo", item);
|
|
357
362
|
case "mathEquation": return item.ommlXml || "";
|
|
358
363
|
default: return item;
|
|
359
364
|
}
|
|
360
365
|
}).join("");
|
|
361
|
-
const baseSdtPr = props.rawPropertiesXml
|
|
366
|
+
const baseSdtPr = props.rawPropertiesXml && isSingleWellFormedElement(props.rawPropertiesXml, "sdtPr") ? props.rawPropertiesXml : synthesizeInlineSdtPr(props);
|
|
362
367
|
const dateFullDate = props.sdtType === "date" && props.dateValueISO ? props.dateValueISO : void 0;
|
|
363
368
|
const dropdownLastValue = (props.sdtType === "dropdown" || props.sdtType === "comboBox") && typeof props.dropdownLastValue === "string" ? props.dropdownLastValue : void 0;
|
|
364
369
|
return `<w:sdt>${reconcileRawSdtPr(baseSdtPr, props, {
|
|
365
370
|
...dateFullDate !== void 0 ? { dateFullDate } : {},
|
|
366
371
|
...dropdownLastValue !== void 0 ? { dropdownLastValue } : {}
|
|
367
|
-
})}${props.rawEndPropertiesXml
|
|
372
|
+
})}${props.rawEndPropertiesXml && isSingleWellFormedElement(props.rawEndPropertiesXml, "sdtEndPr") ? props.rawEndPropertiesXml : ""}<w:sdtContent>${contentXml}</w:sdtContent></w:sdt>`;
|
|
368
373
|
}
|
|
369
374
|
function serializeMoveRangeStart(tag, marker) {
|
|
370
375
|
return `<w:${tag} ${[`w:id="${marker.id}"`, `w:name="${escapeXml(marker.name)}"`].join(" ")}/>`;
|
|
@@ -377,7 +382,7 @@ function rewriteRunTextAsDeleted(xml) {
|
|
|
377
382
|
}
|
|
378
383
|
function serializeTrackedChange(tag, change) {
|
|
379
384
|
const info = change.info;
|
|
380
|
-
const normalizedId =
|
|
385
|
+
const normalizedId = normalizeRevisionId(info.id);
|
|
381
386
|
const authorCandidate = typeof info.author === "string" ? info.author.trim() : "";
|
|
382
387
|
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
383
388
|
const normalizedDate = typeof info.date === "string" ? info.date.trim() : void 0;
|
|
@@ -452,8 +457,8 @@ function serializeParagraphContent(content, explicitCommentReferenceIds) {
|
|
|
452
457
|
function serializeParagraph(paragraph) {
|
|
453
458
|
const parts = [];
|
|
454
459
|
const attrs = [];
|
|
455
|
-
if (paragraph.paraId) attrs.push(`w14:paraId="${paragraph.paraId}"`);
|
|
456
|
-
if (paragraph.textId) attrs.push(`w14:textId="${paragraph.textId}"`);
|
|
460
|
+
if (paragraph.paraId) attrs.push(`w14:paraId="${escapeXml(paragraph.paraId)}"`);
|
|
461
|
+
if (paragraph.textId) attrs.push(`w14:textId="${escapeXml(paragraph.textId)}"`);
|
|
457
462
|
const attrsStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
458
463
|
const pPrXml = serializeParagraphFormatting(paragraph.formatting, paragraph.propertyChanges, paragraph.pPrMark);
|
|
459
464
|
const sectionPropertiesXml = serializeSectionProperties(paragraph.sectionProperties);
|
|
@@ -478,7 +483,10 @@ function serializeParagraph(paragraph) {
|
|
|
478
483
|
}
|
|
479
484
|
function injectRenderedPageBreakIntoFirstRun(xml) {
|
|
480
485
|
const runOpeningTag = /<w:r(?=[\s>/])[^>]*>/u;
|
|
481
|
-
|
|
486
|
+
const openingTag = runOpeningTag.exec(xml);
|
|
487
|
+
if (!openingTag) return null;
|
|
488
|
+
const runEnd = xml.indexOf("</w:r>", openingTag.index + openingTag[0].length);
|
|
489
|
+
if (runEnd !== -1 && xml.slice(openingTag.index + openingTag[0].length, runEnd).includes("<w:lastRenderedPageBreak/>")) return xml;
|
|
482
490
|
return xml.replace(runOpeningTag, (match) => `${match}<w:lastRenderedPageBreak/>`);
|
|
483
491
|
}
|
|
484
492
|
/**
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { HIGHLIGHT_COLOR_VALUES } from "../../types/documentEnumValues.js";
|
|
2
|
+
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
2
3
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
4
|
+
import { serializeTable } from "./tableSerializer.js";
|
|
3
5
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
4
6
|
import { panic } from "better-result";
|
|
7
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
5
8
|
//#region src/docx/serializer/runSerializer.ts
|
|
6
9
|
/**
|
|
7
10
|
* Run Serializer - Serialize runs to OOXML XML
|
|
@@ -41,10 +44,10 @@ function serializeColorElement(color) {
|
|
|
41
44
|
if (!color) return "";
|
|
42
45
|
const attrs = [];
|
|
43
46
|
if (color.auto) attrs.push("w:val=\"auto\"");
|
|
44
|
-
else if (color.rgb) attrs.push(`w:val="${color.rgb}"`);
|
|
45
|
-
if (color.themeColor) attrs.push(`w:themeColor="${color.themeColor}"`);
|
|
46
|
-
if (color.themeTint) attrs.push(`w:themeTint="${color.themeTint}"`);
|
|
47
|
-
if (color.themeShade) attrs.push(`w:themeShade="${color.themeShade}"`);
|
|
47
|
+
else if (color.rgb && isValidHexColor(color.rgb)) attrs.push(`w:val="${escapeXml(color.rgb)}"`);
|
|
48
|
+
if (color.themeColor) attrs.push(`w:themeColor="${escapeXml(color.themeColor)}"`);
|
|
49
|
+
if (color.themeTint) attrs.push(`w:themeTint="${escapeXml(color.themeTint)}"`);
|
|
50
|
+
if (color.themeShade) attrs.push(`w:themeShade="${escapeXml(color.themeShade)}"`);
|
|
48
51
|
if (attrs.length === 0) return "";
|
|
49
52
|
return `<w:color ${attrs.join(" ")}/>`;
|
|
50
53
|
}
|
|
@@ -54,15 +57,15 @@ function serializeColorElement(color) {
|
|
|
54
57
|
function serializeShading(shading) {
|
|
55
58
|
if (!shading) return "";
|
|
56
59
|
const attrs = [];
|
|
57
|
-
if (shading.pattern) attrs.push(`w:val="${shading.pattern}"`);
|
|
60
|
+
if (shading.pattern) attrs.push(`w:val="${escapeXml(shading.pattern)}"`);
|
|
58
61
|
else attrs.push("w:val=\"clear\"");
|
|
59
|
-
if (shading.color?.rgb) attrs.push(`w:color="${shading.color.rgb}"`);
|
|
62
|
+
if (shading.color?.rgb && isValidHexColor(shading.color.rgb)) attrs.push(`w:color="${escapeXml(shading.color.rgb)}"`);
|
|
60
63
|
else if (shading.color?.auto) attrs.push("w:color=\"auto\"");
|
|
61
|
-
if (shading.fill?.rgb) attrs.push(`w:fill="${shading.fill.rgb}"`);
|
|
64
|
+
if (shading.fill?.rgb && isValidHexColor(shading.fill.rgb)) attrs.push(`w:fill="${escapeXml(shading.fill.rgb)}"`);
|
|
62
65
|
else if (shading.fill?.auto) attrs.push("w:fill=\"auto\"");
|
|
63
|
-
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${shading.fill.themeColor}"`);
|
|
64
|
-
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${shading.fill.themeTint}"`);
|
|
65
|
-
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${shading.fill.themeShade}"`);
|
|
66
|
+
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${escapeXml(shading.fill.themeColor)}"`);
|
|
67
|
+
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${escapeXml(shading.fill.themeTint)}"`);
|
|
68
|
+
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${escapeXml(shading.fill.themeShade)}"`);
|
|
66
69
|
if (attrs.length === 0) return "";
|
|
67
70
|
return `<w:shd ${attrs.join(" ")}/>`;
|
|
68
71
|
}
|
|
@@ -136,10 +139,10 @@ function serializeTextFormatting(formatting) {
|
|
|
136
139
|
if (formatting.underline) {
|
|
137
140
|
const uAttrs = [`w:val="${formatting.underline.style}"`];
|
|
138
141
|
if (formatting.underline.color) {
|
|
139
|
-
if (formatting.underline.color.rgb) uAttrs.push(`w:color="${formatting.underline.color.rgb}"`);
|
|
140
|
-
if (formatting.underline.color.themeColor) uAttrs.push(`w:themeColor="${formatting.underline.color.themeColor}"`);
|
|
141
|
-
if (formatting.underline.color.themeTint) uAttrs.push(`w:themeTint="${formatting.underline.color.themeTint}"`);
|
|
142
|
-
if (formatting.underline.color.themeShade) uAttrs.push(`w:themeShade="${formatting.underline.color.themeShade}"`);
|
|
142
|
+
if (formatting.underline.color.rgb && isValidHexColor(formatting.underline.color.rgb)) uAttrs.push(`w:color="${escapeXml(formatting.underline.color.rgb)}"`);
|
|
143
|
+
if (formatting.underline.color.themeColor) uAttrs.push(`w:themeColor="${escapeXml(formatting.underline.color.themeColor)}"`);
|
|
144
|
+
if (formatting.underline.color.themeTint) uAttrs.push(`w:themeTint="${escapeXml(formatting.underline.color.themeTint)}"`);
|
|
145
|
+
if (formatting.underline.color.themeShade) uAttrs.push(`w:themeShade="${escapeXml(formatting.underline.color.themeShade)}"`);
|
|
143
146
|
}
|
|
144
147
|
parts.push(`<w:u ${uAttrs.join(" ")}/>`);
|
|
145
148
|
}
|
|
@@ -159,7 +162,7 @@ function extractRPrInner(rPrXml) {
|
|
|
159
162
|
return rPrXml.slice(7, -8);
|
|
160
163
|
}
|
|
161
164
|
function serializeRunPropertyChange(change) {
|
|
162
|
-
const normalizedId =
|
|
165
|
+
const normalizedId = normalizeRevisionId(change.info.id);
|
|
163
166
|
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
164
167
|
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
165
168
|
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
@@ -245,11 +248,11 @@ function serializeNoBreakHyphen(_content) {
|
|
|
245
248
|
/** Serialize a color value to DrawingML a:srgbClr or a:schemeClr */
|
|
246
249
|
function serializeDrawingColor(color) {
|
|
247
250
|
if (!color) return "";
|
|
248
|
-
if (color.rgb) return `<a:srgbClr val="${color.rgb.replace("#", "")}"/>`;
|
|
251
|
+
if (color.rgb && isValidHexColor(color.rgb)) return `<a:srgbClr val="${escapeXml(color.rgb.replace("#", ""))}"/>`;
|
|
249
252
|
if (color.themeColor) {
|
|
250
|
-
let clr = `<a:schemeClr val="${color.themeColor}"`;
|
|
251
|
-
if (color.themeTint) clr += `><a:tint val="${color.themeTint}"/></a:schemeClr>`;
|
|
252
|
-
else if (color.themeShade) clr += `><a:shade val="${color.themeShade}"/></a:schemeClr>`;
|
|
253
|
+
let clr = `<a:schemeClr val="${escapeXml(color.themeColor)}"`;
|
|
254
|
+
if (color.themeTint) clr += `><a:tint val="${escapeXml(color.themeTint)}"/></a:schemeClr>`;
|
|
255
|
+
else if (color.themeShade) clr += `><a:shade val="${escapeXml(color.themeShade)}"/></a:schemeClr>`;
|
|
253
256
|
else clr += `/>`;
|
|
254
257
|
return clr;
|
|
255
258
|
}
|
|
@@ -418,8 +421,8 @@ function serializeDrawingContent(content) {
|
|
|
418
421
|
].join("");
|
|
419
422
|
}
|
|
420
423
|
/** Serialize text body content for shapes/textboxes */
|
|
421
|
-
function serializeShapeTextBody(
|
|
422
|
-
return
|
|
424
|
+
function serializeShapeTextBody(blocks) {
|
|
425
|
+
return blocks.map((block) => block.type === "paragraph" ? serializeParagraph(block) : serializeTable(block, serializeParagraph)).join("");
|
|
423
426
|
}
|
|
424
427
|
/**
|
|
425
428
|
* Serialize shape content to full DrawingML XML (wps:wsp inside w:drawing)
|
|
@@ -534,6 +537,7 @@ function serializeRunContent(content) {
|
|
|
534
537
|
case "instrText": return serializeInstrText(content);
|
|
535
538
|
case "softHyphen": return serializeSoftHyphen(content);
|
|
536
539
|
case "noBreakHyphen": return serializeNoBreakHyphen(content);
|
|
540
|
+
case "renderedPageBreak": return "<w:lastRenderedPageBreak/>";
|
|
537
541
|
case "drawing":
|
|
538
542
|
if (content.rawXml) return content.rawXml;
|
|
539
543
|
return serializeDrawingContent(content);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getUnserializedSectionPropertyChildNames } from "../sectionParser.js";
|
|
2
2
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
3
3
|
import { serializeBorder } from "./borderSerializer.js";
|
|
4
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
4
5
|
//#region src/docx/serializer/sectionPropertiesSerializer.ts
|
|
5
6
|
const serializeHeaderReference = (ref) => `<w:headerReference w:type="${ref.type}" r:id="${ref.rId}"/>`;
|
|
6
7
|
const serializeFooterReference = (ref) => `<w:footerReference w:type="${ref.type}" r:id="${ref.rId}"/>`;
|
|
@@ -132,7 +133,7 @@ function serializeOnOffElement(value, name) {
|
|
|
132
133
|
return value ? `<w:${name}/>` : `<w:${name} w:val="0"/>`;
|
|
133
134
|
}
|
|
134
135
|
function serializeSectionPropertyChange(change) {
|
|
135
|
-
const normalizedId =
|
|
136
|
+
const normalizedId = normalizeRevisionId(change.info.id);
|
|
136
137
|
const authorCandidate = typeof change.info.author === "string" ? change.info.author.trim() : "";
|
|
137
138
|
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
138
139
|
const normalizedDate = typeof change.info.date === "string" ? change.info.date.trim() : void 0;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { escapeXml } from "./xmlUtils.js";
|
|
2
|
+
import { serializeTableCellFormatting, serializeTableFormatting, serializeTableRowFormatting } from "./tableSerializer.js";
|
|
2
3
|
import { serializeTextFormatting } from "./runSerializer.js";
|
|
3
4
|
import { serializeParagraphFormatting } from "./paragraphSerializer.js";
|
|
4
|
-
import { serializeTableCellFormatting, serializeTableFormatting, serializeTableRowFormatting } from "./tableSerializer.js";
|
|
5
5
|
//#region src/docx/serializer/stylesSerializer.ts
|
|
6
6
|
const W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
7
7
|
const serializeStylesXml = (definitions) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
2
|
|
|
3
3
|
//#region src/docx/serializer/tableSerializer.d.ts
|
|
4
|
+
type ParagraphSerializer = (paragraph: document_d_exports.Paragraph) => string;
|
|
4
5
|
/**
|
|
5
6
|
* Serialize table formatting properties (w:tblPr)
|
|
6
7
|
*/
|
|
@@ -16,25 +17,25 @@ declare function serializeTableCellFormatting(formatting: document_d_exports.Tab
|
|
|
16
17
|
/**
|
|
17
18
|
* Serialize a table cell (w:tc)
|
|
18
19
|
*/
|
|
19
|
-
declare function serializeTableCell(cell: document_d_exports.TableCell): string;
|
|
20
|
+
declare function serializeTableCell(cell: document_d_exports.TableCell, serializeParagraph: ParagraphSerializer): string;
|
|
20
21
|
/**
|
|
21
22
|
* Serialize a table row (w:tr)
|
|
22
23
|
*/
|
|
23
|
-
declare function serializeTableRow(row: document_d_exports.TableRow): string;
|
|
24
|
+
declare function serializeTableRow(row: document_d_exports.TableRow, serializeParagraph: ParagraphSerializer): string;
|
|
24
25
|
/**
|
|
25
26
|
* Serialize a table to OOXML XML (w:tbl)
|
|
26
27
|
*
|
|
27
28
|
* @param table - The table to serialize
|
|
28
29
|
* @returns XML string for the table
|
|
29
30
|
*/
|
|
30
|
-
declare function serializeTable(table: document_d_exports.Table): string;
|
|
31
|
+
declare function serializeTable(table: document_d_exports.Table, serializeParagraph: ParagraphSerializer): string;
|
|
31
32
|
/**
|
|
32
33
|
* Serialize multiple tables to OOXML XML
|
|
33
34
|
*
|
|
34
35
|
* @param tables - The tables to serialize
|
|
35
36
|
* @returns XML string for all tables
|
|
36
37
|
*/
|
|
37
|
-
declare function serializeTables(tables: document_d_exports.Table[]): string;
|
|
38
|
+
declare function serializeTables(tables: document_d_exports.Table[], serializeParagraph: ParagraphSerializer): string;
|
|
38
39
|
/**
|
|
39
40
|
* Check if a table has any rows
|
|
40
41
|
*/
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
1
2
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
2
3
|
import { serializeBorder } from "./borderSerializer.js";
|
|
3
|
-
import {
|
|
4
|
+
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
4
5
|
//#region src/docx/serializer/tableSerializer.ts
|
|
5
6
|
function normalizeTrackedChangeInfo(info) {
|
|
6
|
-
const normalizedId =
|
|
7
|
+
const normalizedId = normalizeRevisionId(info.id);
|
|
7
8
|
const authorCandidate = typeof info.author === "string" ? info.author.trim() : "";
|
|
8
9
|
const normalizedAuthor = authorCandidate.length > 0 ? authorCandidate : "Unknown";
|
|
9
10
|
const normalizedDate = typeof info.date === "string" ? info.date.trim() : void 0;
|
|
@@ -78,15 +79,15 @@ function serializeCellMargins(margins, elementName) {
|
|
|
78
79
|
function serializeShading(shading) {
|
|
79
80
|
if (!shading) return "";
|
|
80
81
|
const attrs = [];
|
|
81
|
-
if (shading.pattern) attrs.push(`w:val="${shading.pattern}"`);
|
|
82
|
+
if (shading.pattern) attrs.push(`w:val="${escapeXml(shading.pattern)}"`);
|
|
82
83
|
else attrs.push("w:val=\"clear\"");
|
|
83
|
-
if (shading.color?.rgb) attrs.push(`w:color="${shading.color.rgb}"`);
|
|
84
|
+
if (shading.color?.rgb && isValidHexColor(shading.color.rgb)) attrs.push(`w:color="${escapeXml(shading.color.rgb)}"`);
|
|
84
85
|
else if (shading.color?.auto) attrs.push("w:color=\"auto\"");
|
|
85
|
-
if (shading.fill?.rgb) attrs.push(`w:fill="${shading.fill.rgb}"`);
|
|
86
|
+
if (shading.fill?.rgb && isValidHexColor(shading.fill.rgb)) attrs.push(`w:fill="${escapeXml(shading.fill.rgb)}"`);
|
|
86
87
|
else if (shading.fill?.auto) attrs.push("w:fill=\"auto\"");
|
|
87
|
-
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${shading.fill.themeColor}"`);
|
|
88
|
-
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${shading.fill.themeTint}"`);
|
|
89
|
-
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${shading.fill.themeShade}"`);
|
|
88
|
+
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${escapeXml(shading.fill.themeColor)}"`);
|
|
89
|
+
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${escapeXml(shading.fill.themeTint)}"`);
|
|
90
|
+
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${escapeXml(shading.fill.themeShade)}"`);
|
|
90
91
|
if (attrs.length === 0) return "";
|
|
91
92
|
return `<w:shd ${attrs.join(" ")}/>`;
|
|
92
93
|
}
|
|
@@ -247,12 +248,17 @@ function serializeTableCellFormatting(formatting, propertyChanges, structuralCha
|
|
|
247
248
|
if (formatting.textDirection) parts.push(`<w:textDirection w:val="${formatting.textDirection}"/>`);
|
|
248
249
|
if (formatting.fitText) parts.push("<w:tcFitText/>");
|
|
249
250
|
if (formatting.verticalAlign) parts.push(`<w:vAlign w:val="${formatting.verticalAlign}"/>`);
|
|
250
|
-
if (formatting.hideMark) parts.push("<w:hideMark/>");
|
|
251
|
+
if (formatting.hideMark !== void 0) parts.push(formatting.hideMark ? "<w:hideMark/>" : "<w:hideMark w:val=\"false\"/>");
|
|
251
252
|
}
|
|
252
253
|
if (structuralChange) {
|
|
253
254
|
if (structuralChange.type === "tableCellInsertion") parts.push(`<w:cellIns ${serializeTrackedChangeAttributes(structuralChange.info)}/>`);
|
|
254
255
|
else if (structuralChange.type === "tableCellDeletion") parts.push(`<w:cellDel ${serializeTrackedChangeAttributes(structuralChange.info)}/>`);
|
|
255
|
-
else if (structuralChange.type === "tableCellMerge")
|
|
256
|
+
else if (structuralChange.type === "tableCellMerge") {
|
|
257
|
+
const attrs = [serializeTrackedChangeAttributes(structuralChange.info)];
|
|
258
|
+
if (structuralChange.verticalMerge) attrs.push(`w:vMerge="${structuralChange.verticalMerge === "continue" ? "cont" : "rest"}"`);
|
|
259
|
+
if (structuralChange.verticalMergeOriginal) attrs.push(`w:vMergeOrig="${structuralChange.verticalMergeOriginal === "continue" ? "cont" : "rest"}"`);
|
|
260
|
+
parts.push(`<w:cellMerge ${attrs.join(" ")}/>`);
|
|
261
|
+
}
|
|
256
262
|
}
|
|
257
263
|
if (propertyChanges && propertyChanges.length > 0) parts.push(...propertyChanges.map((change) => serializeTableCellPropertyChange(change)));
|
|
258
264
|
if (parts.length === 0) return "";
|
|
@@ -277,31 +283,31 @@ function serializeTableGrid(columnWidths) {
|
|
|
277
283
|
/**
|
|
278
284
|
* Serialize cell content (paragraphs, nested tables)
|
|
279
285
|
*/
|
|
280
|
-
function serializeCellContent(content) {
|
|
286
|
+
function serializeCellContent(content, serializeParagraph) {
|
|
281
287
|
const parts = [];
|
|
282
288
|
for (const item of content) if (item.type === "paragraph") parts.push(serializeParagraph(item));
|
|
283
|
-
else parts.push(serializeTable(item));
|
|
289
|
+
else parts.push(serializeTable(item, serializeParagraph));
|
|
284
290
|
if (parts.length === 0) parts.push("<w:p/>");
|
|
285
291
|
return parts.join("");
|
|
286
292
|
}
|
|
287
293
|
/**
|
|
288
294
|
* Serialize a table cell (w:tc)
|
|
289
295
|
*/
|
|
290
|
-
function serializeTableCell(cell) {
|
|
296
|
+
function serializeTableCell(cell, serializeParagraph) {
|
|
291
297
|
const parts = [];
|
|
292
298
|
const tcPrXml = serializeTableCellFormatting(cell.formatting, cell.propertyChanges, cell.structuralChange);
|
|
293
299
|
if (tcPrXml) parts.push(tcPrXml);
|
|
294
|
-
parts.push(serializeCellContent(cell.content));
|
|
300
|
+
parts.push(serializeCellContent(cell.content, serializeParagraph));
|
|
295
301
|
return `<w:tc>${parts.join("")}</w:tc>`;
|
|
296
302
|
}
|
|
297
303
|
/**
|
|
298
304
|
* Serialize a table row (w:tr)
|
|
299
305
|
*/
|
|
300
|
-
function serializeTableRow(row) {
|
|
306
|
+
function serializeTableRow(row, serializeParagraph) {
|
|
301
307
|
const parts = [];
|
|
302
308
|
const trPrXml = serializeTableRowFormatting(row.formatting, row.propertyChanges, row.structuralChange);
|
|
303
309
|
if (trPrXml) parts.push(trPrXml);
|
|
304
|
-
for (const cell of row.cells) parts.push(serializeTableCell(cell));
|
|
310
|
+
for (const cell of row.cells) parts.push(serializeTableCell(cell, serializeParagraph));
|
|
305
311
|
return `<w:tr>${parts.join("")}</w:tr>`;
|
|
306
312
|
}
|
|
307
313
|
/**
|
|
@@ -310,13 +316,13 @@ function serializeTableRow(row) {
|
|
|
310
316
|
* @param table - The table to serialize
|
|
311
317
|
* @returns XML string for the table
|
|
312
318
|
*/
|
|
313
|
-
function serializeTable(table) {
|
|
319
|
+
function serializeTable(table, serializeParagraph) {
|
|
314
320
|
const parts = [];
|
|
315
321
|
const tblPrXml = serializeTableFormatting(table.formatting, table.propertyChanges);
|
|
316
322
|
if (tblPrXml) parts.push(tblPrXml);
|
|
317
323
|
const tblGridXml = serializeTableGrid(table.columnWidths);
|
|
318
324
|
if (tblGridXml) parts.push(tblGridXml);
|
|
319
|
-
for (const row of table.rows) parts.push(serializeTableRow(row));
|
|
325
|
+
for (const row of table.rows) parts.push(serializeTableRow(row, serializeParagraph));
|
|
320
326
|
return `<w:tbl>${parts.join("")}</w:tbl>`;
|
|
321
327
|
}
|
|
322
328
|
/**
|
|
@@ -325,8 +331,8 @@ function serializeTable(table) {
|
|
|
325
331
|
* @param tables - The tables to serialize
|
|
326
332
|
* @returns XML string for all tables
|
|
327
333
|
*/
|
|
328
|
-
function serializeTables(tables) {
|
|
329
|
-
return tables.map(serializeTable).join("");
|
|
334
|
+
function serializeTables(tables, serializeParagraph) {
|
|
335
|
+
return tables.map((table) => serializeTable(table, serializeParagraph)).join("");
|
|
330
336
|
}
|
|
331
337
|
/**
|
|
332
338
|
* Check if a table has any rows
|
|
@@ -16,5 +16,17 @@ declare function escapeXml(text: string): string;
|
|
|
16
16
|
* literal `"NaN"` or `"Infinity"` into the XML.
|
|
17
17
|
*/
|
|
18
18
|
declare function intAttr(value: number | undefined | null): string;
|
|
19
|
+
/**
|
|
20
|
+
* Verify that `xml` parses to exactly one root element named `expectedLocalName`
|
|
21
|
+
* (namespace prefix ignored). Used to gate raw XML snapshots — e.g. an SDT's
|
|
22
|
+
* `rawPropertiesXml`/`rawEndPropertiesXml` — before splicing them verbatim
|
|
23
|
+
* into a serialized document. Those snapshots are normally produced by our
|
|
24
|
+
* own parser, but they can also arrive from an untrusted surface (a
|
|
25
|
+
* programmatically constructed node, a collaboration payload); a value that
|
|
26
|
+
* is not a single well-formed `<w:sdtPr>`/`<w:sdtEndPr>` element could inject
|
|
27
|
+
* sibling markup or close the enclosing `<w:sdt>` early. Callers should fall
|
|
28
|
+
* back to a synthesized properties block when this returns `false`.
|
|
29
|
+
*/
|
|
30
|
+
declare function isSingleWellFormedElement(xml: string, expectedLocalName: string): boolean;
|
|
19
31
|
//#endregion
|
|
20
|
-
export { escapeXml, intAttr };
|
|
32
|
+
export { escapeXml, intAttr, isSingleWellFormedElement };
|