@stll/folio-core 0.37.4 → 0.38.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.js +275 -88
- package/dist/ai-edits/clean-text.js +12 -1
- package/dist/ai-edits/headless.d.ts +110 -0
- package/dist/ai-edits/headless.js +569 -40
- package/dist/ai-edits/index.d.ts +2 -1
- package/dist/ai-edits/snapshot.d.ts +24 -1
- package/dist/ai-edits/snapshot.js +206 -9
- package/dist/ai-edits/table-geometry.d.ts +7 -7
- package/dist/ai-edits/table-geometry.js +43 -27
- package/dist/ai-edits/table-template.d.ts +2 -1
- package/dist/ai-edits/table-template.js +9 -3
- package/dist/ai-edits/types.d.ts +38 -16
- package/dist/compare/__fixtures__/body-sequence.d.ts +4 -0
- package/dist/compare/__fixtures__/body-sequence.js +5 -3
- package/dist/compare/compare.d.ts +26 -2
- package/dist/compare/compare.js +444 -16
- package/dist/compare/content-alignment.js +216 -137
- package/dist/compare/content-types.d.ts +36 -2
- package/dist/compare/content.d.ts +13 -10
- package/dist/compare/content.js +69 -23
- package/dist/compare/formatting.d.ts +4 -22
- package/dist/compare/formatting.js +8 -112
- package/dist/compare/inline-atom-resources.d.ts +6 -0
- package/dist/compare/inline-atom-resources.js +26 -0
- package/dist/compare/inline-atoms.d.ts +35 -0
- package/dist/compare/inline-atoms.js +383 -0
- package/dist/compare/inline-provenance.d.ts +36 -0
- package/dist/compare/inline-provenance.js +334 -0
- package/dist/compare/plan.d.ts +4 -1
- package/dist/compare/plan.js +32 -4
- package/dist/compare/scenario.d.ts +4 -6
- package/dist/compare/section-boundary-properties.d.ts +63 -0
- package/dist/compare/section-boundary-properties.js +235 -0
- package/dist/compare/style-resources.d.ts +30 -0
- package/dist/compare/style-resources.js +404 -0
- package/dist/compare/types.d.ts +50 -11
- package/dist/compare/types.js +3 -1
- package/dist/compare/verification.d.ts +3 -5
- package/dist/compare/verification.js +8 -39
- package/dist/compat/eigenpal.d.ts +4 -4
- package/dist/compat/eigenpal.js +3 -3
- package/dist/document-operations.d.ts +5 -3
- package/dist/document-operations.js +112 -5
- package/dist/docx/blockContentParser.js +14 -2
- package/dist/docx/drawingIdNormalization.js +43 -2
- package/dist/docx/drawingRelationships.d.ts +10 -0
- package/dist/docx/drawingRelationships.js +28 -0
- package/dist/docx/fieldParser.js +1 -1
- package/dist/docx/hyperlinkParser.js +3 -5
- package/dist/docx/imageRawXml.d.ts +8 -0
- package/dist/docx/imageRawXml.js +13 -0
- package/dist/docx/newImage.d.ts +2 -2
- package/dist/docx/newImage.js +3 -3
- package/dist/docx/numberingParser.d.ts +1 -13
- package/dist/docx/numberingParser.js +31 -37
- package/dist/docx/paragraphParser.js +12 -9
- package/dist/docx/paragraphPropertySource.d.ts +8 -5
- package/dist/docx/paragraphPropertySource.js +16 -4
- package/dist/docx/removeHeaderFooterParts.d.ts +14 -0
- package/dist/docx/removeHeaderFooterParts.js +87 -0
- package/dist/docx/rezip.d.ts +3 -1
- package/dist/docx/rezip.js +143 -41
- package/dist/docx/runParser.js +16 -5
- package/dist/docx/sectionParser.js +3 -0
- package/dist/docx/sectionReferenceHistory.d.ts +17 -0
- package/dist/docx/sectionReferenceHistory.js +59 -0
- package/dist/docx/selectiveSave.js +11 -31
- package/dist/docx/selectiveXmlPatch.d.ts +8 -1
- package/dist/docx/selectiveXmlPatch.js +62 -2
- package/dist/docx/serializer/borderSerializer.d.ts +4 -1
- package/dist/docx/serializer/borderSerializer.js +20 -18
- package/dist/docx/serializer/commentSerializer.js +1 -1
- package/dist/docx/serializer/numberingSerializer.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +13 -177
- package/dist/docx/serializer/partNamespaces.d.ts +1 -1
- package/dist/docx/serializer/partNamespaces.js +4 -0
- package/dist/docx/serializer/runSerializer.d.ts +1 -5
- package/dist/docx/serializer/runSerializer.js +4 -130
- package/dist/docx/serializer/sectionPropertiesSerializer.js +5 -2
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/textFormattingSerializer.d.ts +17 -0
- package/dist/docx/serializer/textFormattingSerializer.js +144 -0
- package/dist/docx/tableParser.js +21 -11
- package/dist/docx/xmlParser.d.ts +10 -1
- package/dist/docx/xmlParser.js +23 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/internal/compare/inline-presentation.d.ts +20 -0
- package/dist/internal/compare/inline-presentation.js +222 -0
- package/dist/internal/paragraphFormattingSerialization.d.ts +25 -0
- package/dist/internal/paragraphFormattingSerialization.js +164 -0
- package/dist/internal/sectionReferenceResolution.d.ts +21 -0
- package/dist/internal/sectionReferenceResolution.js +72 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +1 -0
- package/dist/markdown/renderRuns.js +1 -0
- package/dist/markdown/renderTable.js +1 -0
- package/dist/prosemirror/attrs/index.js +20 -1
- package/dist/prosemirror/commands/comments.d.ts +11 -1
- package/dist/prosemirror/commands/comments.js +68 -6
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +9 -3
- package/dist/prosemirror/commands/propertyChangeScope.js +4 -10
- package/dist/prosemirror/conversion/fromProseDoc.js +22 -22
- package/dist/prosemirror/conversion/toProseDoc.js +16 -57
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +3 -0
- package/dist/prosemirror/imageCommit.js +7 -9
- package/dist/prosemirror/paragraphIndentation.d.ts +21 -0
- package/dist/prosemirror/paragraphIndentation.js +72 -0
- package/dist/prosemirror/plugins/documentNumbering.d.ts +3 -1
- package/dist/prosemirror/plugins/documentNumbering.js +7 -1
- package/dist/prosemirror/plugins/documentStyles.d.ts +3 -1
- package/dist/prosemirror/plugins/documentStyles.js +7 -1
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +3 -1
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +2 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +15 -2
- package/dist/prosemirror/runFormattingInlineCarriers.js +33 -3
- package/dist/prosemirror/runStyleFormatting.d.ts +15 -2
- package/dist/prosemirror/runStyleFormatting.js +76 -2
- package/dist/prosemirror/schema/marks.d.ts +3 -1
- package/dist/prosemirror/schema/marks.js +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +3 -0
- package/dist/prosemirror/tableCellRevisionVisibility.d.ts +6 -0
- package/dist/prosemirror/tableCellRevisionVisibility.js +14 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
- package/dist/redline.js +15 -2
- package/dist/server.d.ts +3 -2
- package/dist/server.js +2 -2
- package/dist/version-comparison.d.ts +2 -0
- package/dist/version-comparison.js +30 -29
- package/package.json +2 -2
|
@@ -2,13 +2,12 @@ import { parseCommentsExtended } from "./commentParser.js";
|
|
|
2
2
|
import { withoutOrphanCommentRanges } from "./commentRangeIntegrity.js";
|
|
3
3
|
import { hasUnsynthesizedReplyRanges } from "./commentReplyMarkers.js";
|
|
4
4
|
import { validateFolioDocumentModel } from "./modelValidation.js";
|
|
5
|
-
import { isNewDataUrlDrawing } from "./newImage.js";
|
|
6
5
|
import { parseNumbering } from "./numberingParser.js";
|
|
7
6
|
import { isUnsafePackagePath } from "./packageParts.js";
|
|
8
7
|
import { RELATIONSHIP_TYPES } from "./relsParser.js";
|
|
9
|
-
import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, updateCoreProperties, withoutAttachedTemplate } from "./rezip.js";
|
|
8
|
+
import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedInlineResources, updateCoreProperties, withoutAttachedTemplate } from "./rezip.js";
|
|
10
9
|
import "./selectiveSaveFlags.js";
|
|
11
|
-
import { buildPatchedDocumentXml, buildPatchedNoteXml,
|
|
10
|
+
import { buildPatchedDocumentXml, buildPatchedNoteXml, collectParaIds, patchNumberingDefinitions } from "./selectiveXmlPatch.js";
|
|
12
11
|
import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
13
12
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
14
13
|
import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
|
|
@@ -16,25 +15,6 @@ import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
|
16
15
|
import { readRootNamespaceBindings } from "./serializer/partNamespaces.js";
|
|
17
16
|
//#region src/docx/selectiveSave.ts
|
|
18
17
|
/**
|
|
19
|
-
* Check if document content has new images (data: URL without rId) or
|
|
20
|
-
* new hyperlinks (href without rId). Combined into a single traversal
|
|
21
|
-
* to avoid walking the block tree twice.
|
|
22
|
-
*/
|
|
23
|
-
function hasNewImagesOrHyperlinks(blocks) {
|
|
24
|
-
const runHasNewImage = (run) => run.content.some(isNewDataUrlDrawing);
|
|
25
|
-
for (const block of blocks) if (block.type === "paragraph") {
|
|
26
|
-
for (const item of block.content) if (item.type === "run") {
|
|
27
|
-
if (runHasNewImage(item)) return true;
|
|
28
|
-
} else if (item.type === "hyperlink" && item.href && !item.rId && !item.anchor) return true;
|
|
29
|
-
else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
|
|
30
|
-
for (const sub of item.content) if (sub.type === "run" && runHasNewImage(sub)) return true;
|
|
31
|
-
}
|
|
32
|
-
} else if (block.type === "table") {
|
|
33
|
-
for (const row of block.rows) for (const cell of row.cells) if (hasNewImagesOrHyperlinks(cell.content)) return true;
|
|
34
|
-
}
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
18
|
* Splice edited footnote/endnote paragraphs into their parts and return the
|
|
39
19
|
* candidate ids that could NOT be routed to a note part (an id that is neither
|
|
40
20
|
* a body nor a note paragraph — the caller bails on those).
|
|
@@ -139,7 +119,7 @@ async function ensureCommentsExtendedPackaging(zip, updates) {
|
|
|
139
119
|
* Numbering definitions carry no `paraId`, so this is NOT keyed off
|
|
140
120
|
* `changedParaIds` — it always runs (like the comments/header updates) and uses
|
|
141
121
|
* a re-parse+re-serialize baseline to detect which `w:abstractNum` / `w:num`
|
|
142
|
-
* definitions
|
|
122
|
+
* definitions changed or were minted. The model omits parts of numbering.xml
|
|
143
123
|
* (`w:nsid`/`w:tmpl`, custom formats, level sub-elements), so only the changed
|
|
144
124
|
* definitions are spliced by id; every other definition stays byte-exact.
|
|
145
125
|
*
|
|
@@ -159,12 +139,12 @@ async function patchNumberingPart(zip, doc, updates) {
|
|
|
159
139
|
}
|
|
160
140
|
if (!file) return;
|
|
161
141
|
const originalXml = await file.async("text");
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (patched === null) return;
|
|
142
|
+
const patched = patchNumberingDefinitions({
|
|
143
|
+
originalXml,
|
|
144
|
+
baselineXml: serializeNumberingXml(parseNumbering(originalXml).definitions),
|
|
145
|
+
currentXml: serializeNumberingXml(numbering)
|
|
146
|
+
});
|
|
147
|
+
if (patched === null || patched === originalXml) return;
|
|
168
148
|
updates.set(file.name, patched);
|
|
169
149
|
}
|
|
170
150
|
/**
|
|
@@ -196,13 +176,13 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
196
176
|
if (hasUntrackedChanges) return null;
|
|
197
177
|
if (originalBuffer.byteLength > maxBytes) return null;
|
|
198
178
|
const content = doc.package.document.content;
|
|
199
|
-
if (
|
|
179
|
+
if (hasUnmaterializedInlineResources(content)) return null;
|
|
200
180
|
for (const part of [
|
|
201
181
|
...doc.package.headers?.values() ?? [],
|
|
202
182
|
...doc.package.footers?.values() ?? [],
|
|
203
183
|
...doc.package.footnotes ?? [],
|
|
204
184
|
...doc.package.endnotes ?? []
|
|
205
|
-
]) if (
|
|
185
|
+
]) if (hasUnmaterializedInlineResources(part.content)) return null;
|
|
206
186
|
if (hasUnmaterializedHeaderFooter(doc)) return null;
|
|
207
187
|
if (hasModelDrivenPictureWatermark(doc)) return null;
|
|
208
188
|
if (withoutOrphanCommentRanges(doc) !== doc) return null;
|
|
@@ -159,6 +159,13 @@ declare function buildPatchedNumberingXml(originalXml: string, currentXml: strin
|
|
|
159
159
|
* because they cannot be spliced by id; they are appended instead.
|
|
160
160
|
*/
|
|
161
161
|
declare function collectAddedNumberingDefs(baselineXml: string, currentXml: string): ChangedNumberingDefs;
|
|
162
|
+
type PatchNumberingDefinitionsOptions = {
|
|
163
|
+
originalXml: string;
|
|
164
|
+
baselineXml: string;
|
|
165
|
+
currentXml: string;
|
|
166
|
+
};
|
|
167
|
+
/** Both save paths must write changed definitions and newly referenced instances together. */
|
|
168
|
+
declare const patchNumberingDefinitions: ({ originalXml, baselineXml, currentXml }: PatchNumberingDefinitionsOptions) => string | null;
|
|
162
169
|
/**
|
|
163
170
|
* Append added `w:abstractNum` / `w:num` definitions from `currentXml` to
|
|
164
171
|
* `xml`. ECMA-376 §17.9 orders every `w:abstractNum` before the first `w:num`,
|
|
@@ -171,4 +178,4 @@ declare function collectAddedNumberingDefs(baselineXml: string, currentXml: stri
|
|
|
171
178
|
*/
|
|
172
179
|
declare function appendNumberingDefs(xml: string, currentXml: string, added: ChangedNumberingDefs): string | null;
|
|
173
180
|
//#endregion
|
|
174
|
-
export { ChangedNumberingDefs, ParagraphOffsets, PatchSafetyOptions, PatchValidationResult, appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
|
|
181
|
+
export { ChangedNumberingDefs, ParagraphOffsets, PatchSafetyOptions, PatchValidationResult, appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, patchNumberingDefinitions, validatePatchSafety };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
2
|
+
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findAttributeByNamespaceUri, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, parseXmlDocument } from "./xmlParser.js";
|
|
2
3
|
//#region src/docx/selectiveXmlPatch.ts
|
|
3
4
|
/**
|
|
4
5
|
* Selective XML Patch Module
|
|
@@ -757,6 +758,65 @@ function collectAddedNumberingDefs(baselineXml, currentXml) {
|
|
|
757
758
|
};
|
|
758
759
|
}
|
|
759
760
|
const NUMBERING_CLOSE_ROOT = "</w:numbering>";
|
|
761
|
+
const numberingDefinitionIdentity = (element) => {
|
|
762
|
+
if (!WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(element) ?? "")) return null;
|
|
763
|
+
const kind = getLocalName(element.name);
|
|
764
|
+
if (kind !== "abstractNum" && kind !== "num") return null;
|
|
765
|
+
const id = getAttributeByNamespaceUri(element, WORDPROCESSINGML_NAMESPACE_URIS, kind === "num" ? "numId" : "abstractNumId");
|
|
766
|
+
return id === null ? null : {
|
|
767
|
+
kind,
|
|
768
|
+
id
|
|
769
|
+
};
|
|
770
|
+
};
|
|
771
|
+
const patchNumberingByNamespace = ({ original, currentXml, changed, added }) => {
|
|
772
|
+
const current = parseXmlDocument(currentXml);
|
|
773
|
+
if (!current) return null;
|
|
774
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
775
|
+
const namespaceDeclarations = Object.fromEntries(Object.entries(current.attributes ?? {}).filter(([name]) => name === "xmlns" || name.startsWith("xmlns:")));
|
|
776
|
+
for (const child of getChildElements(current)) {
|
|
777
|
+
const identity = numberingDefinitionIdentity(child);
|
|
778
|
+
if (!identity) continue;
|
|
779
|
+
const detached = parseXmlDocument(captureVerbatimXml(cloneElement(child, { attributes: {
|
|
780
|
+
...namespaceDeclarations,
|
|
781
|
+
...child.attributes
|
|
782
|
+
} })));
|
|
783
|
+
if (!detached) return null;
|
|
784
|
+
replacements.set(`${identity.kind}:${identity.id}`, detached);
|
|
785
|
+
}
|
|
786
|
+
const elements = [];
|
|
787
|
+
for (const child of original.elements ?? []) {
|
|
788
|
+
const identity = numberingDefinitionIdentity(child);
|
|
789
|
+
if (!identity || !changed[identity.kind === "num" ? "nums" : "abstractNums"].has(identity.id)) {
|
|
790
|
+
elements.push(child);
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
const replacement = replacements.get(`${identity.kind}:${identity.id}`);
|
|
794
|
+
if (!replacement) return null;
|
|
795
|
+
elements.push(replacement);
|
|
796
|
+
}
|
|
797
|
+
for (const [kind, ids] of [["abstractNum", added.abstractNums], ["num", added.nums]]) for (const id of ids) {
|
|
798
|
+
const replacement = replacements.get(`${kind}:${id}`);
|
|
799
|
+
if (!replacement) return null;
|
|
800
|
+
const firstNum = kind === "abstractNum" ? elements.findIndex((child) => numberingDefinitionIdentity(child)?.kind === "num") : -1;
|
|
801
|
+
elements.splice(firstNum < 0 ? elements.length : firstNum, 0, replacement);
|
|
802
|
+
}
|
|
803
|
+
return captureVerbatimXml(cloneElement(original, { elements }));
|
|
804
|
+
};
|
|
805
|
+
/** Both save paths must write changed definitions and newly referenced instances together. */
|
|
806
|
+
const patchNumberingDefinitions = ({ originalXml, baselineXml, currentXml }) => {
|
|
807
|
+
const changed = collectChangedNumberingDefs(baselineXml, currentXml);
|
|
808
|
+
const added = collectAddedNumberingDefs(baselineXml, currentXml);
|
|
809
|
+
const original = parseXmlDocument(originalXml);
|
|
810
|
+
if (!original || getLocalName(original.name) !== "numbering" || !WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(original) ?? "")) return null;
|
|
811
|
+
if (getNamespacePrefix(original.name ?? "") !== "w") return patchNumberingByNamespace({
|
|
812
|
+
original,
|
|
813
|
+
currentXml,
|
|
814
|
+
changed,
|
|
815
|
+
added
|
|
816
|
+
});
|
|
817
|
+
const spliced = buildPatchedNumberingXml(originalXml, currentXml, changed);
|
|
818
|
+
return spliced === null ? null : appendNumberingDefs(spliced, currentXml, added);
|
|
819
|
+
};
|
|
760
820
|
/**
|
|
761
821
|
* Append added `w:abstractNum` / `w:num` definitions from `currentXml` to
|
|
762
822
|
* `xml`. ECMA-376 §17.9 orders every `w:abstractNum` before the first `w:num`,
|
|
@@ -812,4 +872,4 @@ function escapeRegExp(str) {
|
|
|
812
872
|
return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
813
873
|
}
|
|
814
874
|
//#endregion
|
|
815
|
-
export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, validatePatchSafety };
|
|
875
|
+
export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, patchNumberingDefinitions, validatePatchSafety };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
2
|
//#region src/docx/serializer/borderSerializer.d.ts
|
|
3
|
+
type ExhaustiveFields<Source, Classified extends keyof Source> = Exclude<keyof Source, Classified> extends never ? Source : never;
|
|
4
|
+
type ClassifiedBorderField = "style" | "color" | "size" | "space" | "shadow" | "frame" | "artRelationshipId" | "topLeftArtRelationshipId" | "topRightArtRelationshipId" | "bottomLeftArtRelationshipId" | "bottomRightArtRelationshipId";
|
|
5
|
+
type ExhaustiveBorder = ExhaustiveFields<document_d_exports.BorderSpec, ClassifiedBorderField>;
|
|
3
6
|
/**
|
|
4
7
|
* Serialize a single border element (`<w:top .../>`, `<w:left .../>`, ...).
|
|
5
8
|
*
|
|
@@ -19,6 +22,6 @@ import { document_d_exports } from "../../types/document.js";
|
|
|
19
22
|
* untrusted and are `escapeXml`'d before re-entering XML attributes; for valid
|
|
20
23
|
* documents these are enum/hex values, so escaping is a no-op.
|
|
21
24
|
*/
|
|
22
|
-
declare function serializeBorder(
|
|
25
|
+
declare function serializeBorder(input: ExhaustiveBorder | undefined, elementName: string): string;
|
|
23
26
|
//#endregion
|
|
24
27
|
export { serializeBorder };
|
|
@@ -19,25 +19,27 @@ import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
|
19
19
|
* untrusted and are `escapeXml`'d before re-entering XML attributes; for valid
|
|
20
20
|
* documents these are enum/hex values, so escaping is a no-op.
|
|
21
21
|
*/
|
|
22
|
-
function serializeBorder(
|
|
23
|
-
if (!
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
if (
|
|
32
|
-
if (
|
|
22
|
+
function serializeBorder(input, elementName) {
|
|
23
|
+
if (!input) return "";
|
|
24
|
+
const { style, color, size, space, shadow, frame, artRelationshipId, topLeftArtRelationshipId, topRightArtRelationshipId, bottomLeftArtRelationshipId, bottomRightArtRelationshipId } = input;
|
|
25
|
+
const attrs = [`w:val="${escapeXml(style)}"`];
|
|
26
|
+
if (size !== void 0) attrs.push(`w:sz="${intAttr(size)}"`);
|
|
27
|
+
if (space !== void 0) attrs.push(`w:space="${intAttr(space)}"`);
|
|
28
|
+
if (color) {
|
|
29
|
+
const { auto, rgb, themeColor, themeTint, themeShade } = color;
|
|
30
|
+
if (auto) attrs.push("w:color=\"auto\"");
|
|
31
|
+
else if (rgb) attrs.push(`w:color="${escapeXml(rgb)}"`);
|
|
32
|
+
if (themeColor) attrs.push(`w:themeColor="${escapeXml(themeColor)}"`);
|
|
33
|
+
if (themeTint) attrs.push(`w:themeTint="${escapeXml(themeTint)}"`);
|
|
34
|
+
if (themeShade) attrs.push(`w:themeShade="${escapeXml(themeShade)}"`);
|
|
33
35
|
}
|
|
34
|
-
if (
|
|
35
|
-
if (
|
|
36
|
-
if (
|
|
37
|
-
if (
|
|
38
|
-
if (
|
|
39
|
-
if (
|
|
40
|
-
if (
|
|
36
|
+
if (shadow) attrs.push("w:shadow=\"true\"");
|
|
37
|
+
if (frame) attrs.push("w:frame=\"true\"");
|
|
38
|
+
if (artRelationshipId) attrs.push(`w:id="${escapeXml(artRelationshipId)}"`);
|
|
39
|
+
if (topLeftArtRelationshipId) attrs.push(`w:topLeft="${escapeXml(topLeftArtRelationshipId)}"`);
|
|
40
|
+
if (topRightArtRelationshipId) attrs.push(`w:topRight="${escapeXml(topRightArtRelationshipId)}"`);
|
|
41
|
+
if (bottomLeftArtRelationshipId) attrs.push(`w:bottomLeft="${escapeXml(bottomLeftArtRelationshipId)}"`);
|
|
42
|
+
if (bottomRightArtRelationshipId) attrs.push(`w:bottomRight="${escapeXml(bottomRightArtRelationshipId)}"`);
|
|
41
43
|
return `<w:${elementName} ${attrs.join(" ")}/>`;
|
|
42
44
|
}
|
|
43
45
|
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { deterministicHexId } from "../../utils/hexId.js";
|
|
2
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
3
|
import { serializePartElement } from "./partNamespaces.js";
|
|
4
|
-
import { serializeTextFormatting } from "./
|
|
4
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
5
5
|
import { escapeXml } from "./xmlUtils.js";
|
|
6
6
|
//#region src/docx/serializer/commentSerializer.ts
|
|
7
7
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { serializePartElement } from "./partNamespaces.js";
|
|
2
|
-
import { serializeTextFormatting } from "./
|
|
2
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
3
3
|
import { escapeXml, intAttr } from "./xmlUtils.js";
|
|
4
4
|
//#region src/docx/serializer/numberingSerializer.ts
|
|
5
5
|
/**
|
|
@@ -1,142 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { numPrEqual } from "../numberingParser.js";
|
|
4
|
-
import { getParagraphPropertySource } from "../paragraphPropertySource.js";
|
|
1
|
+
import { modelParagraphFormattingEmission } from "../../internal/paragraphFormattingSerialization.js";
|
|
2
|
+
import { getParagraphPropertySource, paragraphPropertySourceMatchesEmission } from "../paragraphPropertySource.js";
|
|
5
3
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
6
4
|
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
7
5
|
import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
|
|
8
6
|
import { captureVerbatimXml, sanitizeCapturedXmlElement } from "../verbatimCapture.js";
|
|
9
7
|
import { NAMESPACES, OOXML_NAMESPACE_SCOPE, cloneElement, getChildElements, getLocalName, parseXml } from "../xmlParser.js";
|
|
10
|
-
import {
|
|
11
|
-
import { serializeRun, serializeTextFormatting } from "./runSerializer.js";
|
|
8
|
+
import { serializeRun } from "./runSerializer.js";
|
|
12
9
|
import { serializeSectionProperties } from "./sectionPropertiesSerializer.js";
|
|
10
|
+
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
13
11
|
import { serializeTrackedChangeAttributes, trackedChangeAttributeRecord } from "./trackedChangeAttributes.js";
|
|
14
|
-
import { escapeXml,
|
|
12
|
+
import { escapeXml, isSingleWellFormedElement } from "./xmlUtils.js";
|
|
15
13
|
import { panic } from "better-result";
|
|
16
14
|
import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
|
|
17
15
|
//#region src/docx/serializer/paragraphSerializer.ts
|
|
18
16
|
/**
|
|
19
|
-
* Serialize paragraph borders (w:pBdr)
|
|
20
|
-
*/
|
|
21
|
-
function serializeParagraphBorders(borders) {
|
|
22
|
-
if (!borders) return "";
|
|
23
|
-
const parts = [];
|
|
24
|
-
if (borders.top) {
|
|
25
|
-
const topXml = serializeBorder(borders.top, "top");
|
|
26
|
-
if (topXml) parts.push(topXml);
|
|
27
|
-
}
|
|
28
|
-
if (borders.left) {
|
|
29
|
-
const leftXml = serializeBorder(borders.left, "left");
|
|
30
|
-
if (leftXml) parts.push(leftXml);
|
|
31
|
-
}
|
|
32
|
-
if (borders.bottom) {
|
|
33
|
-
const bottomXml = serializeBorder(borders.bottom, "bottom");
|
|
34
|
-
if (bottomXml) parts.push(bottomXml);
|
|
35
|
-
}
|
|
36
|
-
if (borders.right) {
|
|
37
|
-
const rightXml = serializeBorder(borders.right, "right");
|
|
38
|
-
if (rightXml) parts.push(rightXml);
|
|
39
|
-
}
|
|
40
|
-
if (borders.between) {
|
|
41
|
-
const betweenXml = serializeBorder(borders.between, "between");
|
|
42
|
-
if (betweenXml) parts.push(betweenXml);
|
|
43
|
-
}
|
|
44
|
-
if (borders.bar) {
|
|
45
|
-
const barXml = serializeBorder(borders.bar, "bar");
|
|
46
|
-
if (barXml) parts.push(barXml);
|
|
47
|
-
}
|
|
48
|
-
if (parts.length === 0) return "";
|
|
49
|
-
return `<w:pBdr>${parts.join("")}</w:pBdr>`;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Serialize shading properties (w:shd)
|
|
53
|
-
*/
|
|
54
|
-
function serializeShading(shading) {
|
|
55
|
-
if (!shading) return "";
|
|
56
|
-
const attrs = [];
|
|
57
|
-
if (shading.pattern) attrs.push(`w:val="${escapeXml(shading.pattern)}"`);
|
|
58
|
-
else attrs.push("w:val=\"clear\"");
|
|
59
|
-
if (shading.color?.rgb && isValidHexColor(shading.color.rgb)) attrs.push(`w:color="${escapeXml(shading.color.rgb)}"`);
|
|
60
|
-
else if (shading.color?.auto) attrs.push("w:color=\"auto\"");
|
|
61
|
-
if (shading.fill?.rgb && isValidHexColor(shading.fill.rgb)) attrs.push(`w:fill="${escapeXml(shading.fill.rgb)}"`);
|
|
62
|
-
else if (shading.fill?.auto) attrs.push("w:fill=\"auto\"");
|
|
63
|
-
if (shading.fill?.themeColor) attrs.push(`w:themeFill="${escapeXml(shading.fill.themeColor)}"`);
|
|
64
|
-
if (shading.fill?.themeTint) attrs.push(`w:themeFillTint="${escapeXml(shading.fill.themeTint)}"`);
|
|
65
|
-
if (shading.fill?.themeShade) attrs.push(`w:themeFillShade="${escapeXml(shading.fill.themeShade)}"`);
|
|
66
|
-
if (attrs.length === 0) return "";
|
|
67
|
-
return `<w:shd ${attrs.join(" ")}/>`;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Serialize tab stops (w:tabs)
|
|
71
|
-
*/
|
|
72
|
-
function serializeTabStops(tabs) {
|
|
73
|
-
if (!tabs || tabs.length === 0) return "";
|
|
74
|
-
return `<w:tabs>${tabs.map((tab) => {
|
|
75
|
-
const attrs = [`w:val="${tab.alignment}"`, `w:pos="${intAttr(tab.position)}"`];
|
|
76
|
-
if (tab.leader && tab.leader !== "none") attrs.push(`w:leader="${tab.leader}"`);
|
|
77
|
-
return `<w:tab ${attrs.join(" ")}/>`;
|
|
78
|
-
}).join("")}</w:tabs>`;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Serialize spacing properties (w:spacing)
|
|
82
|
-
*/
|
|
83
|
-
function serializeSpacing(formatting) {
|
|
84
|
-
const attrs = [];
|
|
85
|
-
if (formatting.spaceBefore !== void 0) attrs.push(`w:before="${intAttr(formatting.spaceBefore)}"`);
|
|
86
|
-
if (formatting.spaceAfter !== void 0) attrs.push(`w:after="${intAttr(formatting.spaceAfter)}"`);
|
|
87
|
-
if (formatting.lineSpacing !== void 0) attrs.push(`w:line="${intAttr(formatting.lineSpacing)}"`);
|
|
88
|
-
if (formatting.lineSpacingRule) attrs.push(`w:lineRule="${formatting.lineSpacingRule}"`);
|
|
89
|
-
if (formatting.beforeAutospacing !== void 0) attrs.push(`w:beforeAutospacing="${formatting.beforeAutospacing ? "1" : "0"}"`);
|
|
90
|
-
if (formatting.afterAutospacing !== void 0) attrs.push(`w:afterAutospacing="${formatting.afterAutospacing ? "1" : "0"}"`);
|
|
91
|
-
if (attrs.length === 0) return "";
|
|
92
|
-
return `<w:spacing ${attrs.join(" ")}/>`;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Serialize indentation properties (w:ind)
|
|
96
|
-
*/
|
|
97
|
-
function serializeIndentation(formatting) {
|
|
98
|
-
const attrs = [];
|
|
99
|
-
if (formatting.indentLeft !== void 0) attrs.push(`w:left="${intAttr(formatting.indentLeft)}"`);
|
|
100
|
-
if (formatting.indentRight !== void 0) attrs.push(`w:right="${intAttr(formatting.indentRight)}"`);
|
|
101
|
-
if (formatting.indentFirstLine !== void 0) if (formatting.hangingIndent) attrs.push(`w:hanging="${intAttr(Math.abs(formatting.indentFirstLine))}"`);
|
|
102
|
-
else attrs.push(`w:firstLine="${intAttr(formatting.indentFirstLine)}"`);
|
|
103
|
-
if (attrs.length === 0) return "";
|
|
104
|
-
return `<w:ind ${attrs.join(" ")}/>`;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Serialize numbering properties (w:numPr)
|
|
108
|
-
*/
|
|
109
|
-
function serializeNumbering(numPr) {
|
|
110
|
-
if (!numPr) return "";
|
|
111
|
-
const parts = [];
|
|
112
|
-
if (numPr.ilvl !== void 0) parts.push(`<w:ilvl w:val="${intAttr(numPr.ilvl)}"/>`);
|
|
113
|
-
if (numPr.numId !== void 0) parts.push(`<w:numId w:val="${intAttr(numPr.numId)}"/>`);
|
|
114
|
-
if (parts.length === 0) return "";
|
|
115
|
-
return `<w:numPr>${parts.join("")}</w:numPr>`;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Serialize frame properties (w:framePr)
|
|
119
|
-
*/
|
|
120
|
-
function serializeFrameProperties(frame) {
|
|
121
|
-
if (!frame) return "";
|
|
122
|
-
const attrs = [];
|
|
123
|
-
if (frame.dropCap) attrs.push(`w:dropCap="${frame.dropCap}"`);
|
|
124
|
-
if (frame.lines !== void 0) attrs.push(`w:lines="${intAttr(frame.lines)}"`);
|
|
125
|
-
if (frame.width !== void 0) attrs.push(`w:w="${intAttr(frame.width)}"`);
|
|
126
|
-
if (frame.height !== void 0) attrs.push(`w:h="${intAttr(frame.height)}"`);
|
|
127
|
-
if (frame.hSpace !== void 0) attrs.push(`w:hSpace="${intAttr(frame.hSpace)}"`);
|
|
128
|
-
if (frame.vSpace !== void 0) attrs.push(`w:vSpace="${intAttr(frame.vSpace)}"`);
|
|
129
|
-
if (frame.hAnchor) attrs.push(`w:hAnchor="${frame.hAnchor}"`);
|
|
130
|
-
if (frame.vAnchor) attrs.push(`w:vAnchor="${frame.vAnchor}"`);
|
|
131
|
-
if (frame.x !== void 0) attrs.push(`w:x="${frame.x}"`);
|
|
132
|
-
if (frame.y !== void 0) attrs.push(`w:y="${frame.y}"`);
|
|
133
|
-
if (frame.xAlign) attrs.push(`w:xAlign="${frame.xAlign}"`);
|
|
134
|
-
if (frame.yAlign) attrs.push(`w:yAlign="${frame.yAlign}"`);
|
|
135
|
-
if (frame.wrap) attrs.push(`w:wrap="${frame.wrap}"`);
|
|
136
|
-
if (attrs.length === 0) return "";
|
|
137
|
-
return `<w:framePr ${attrs.join(" ")}/>`;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
17
|
* Serialize paragraph formatting properties to w:pPr XML
|
|
141
18
|
*/
|
|
142
19
|
function serializeParagraphMarkChange(mark) {
|
|
@@ -361,7 +238,7 @@ const verifiedParagraphPropertySource = (formatting, source) => {
|
|
|
361
238
|
if (!source) return null;
|
|
362
239
|
const replayableSource = replayableParagraphPropertySourceXml(source.xml);
|
|
363
240
|
if (replayableSource === null) return null;
|
|
364
|
-
return
|
|
241
|
+
return paragraphPropertySourceMatchesEmission(source, formatting) ? replayableSource : null;
|
|
365
242
|
};
|
|
366
243
|
const withTrailingParagraphPropertyChildren = (sourceXml, children) => {
|
|
367
244
|
const written = children.join("");
|
|
@@ -398,6 +275,7 @@ const withParagraphMarkChange = (sourceXml, mark) => {
|
|
|
398
275
|
return captureVerbatimXml(cloneElement(root, { elements }));
|
|
399
276
|
};
|
|
400
277
|
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, propertySource, sectionProperties } = {}) => {
|
|
278
|
+
const modeledFormatting = modelParagraphFormattingEmission(formatting);
|
|
401
279
|
const serializablePropertyChangeCount = propertyChanges?.length ?? 0;
|
|
402
280
|
if (serializablePropertyChangeCount > 1) panic("A paragraph cannot serialize more than one w:pPrChange", { count: serializablePropertyChangeCount });
|
|
403
281
|
const paragraphMarkXml = paragraphMarkChange ? serializeParagraphMarkChange(paragraphMarkChange) : "";
|
|
@@ -408,50 +286,15 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
408
286
|
sectionPropertiesXml,
|
|
409
287
|
...propertyChangesXml
|
|
410
288
|
].some((xml) => xml.includes(`${DATE_UTC_ATTRIBUTE}=`));
|
|
411
|
-
const verifiedSource = verifiedParagraphPropertySource(
|
|
289
|
+
const verifiedSource = verifiedParagraphPropertySource(modeledFormatting, propertySource);
|
|
412
290
|
if (verifiedSource !== null && (!composedChildrenUseDateUtc || !sourceShadowsDateUtcPrefix(verifiedSource))) {
|
|
413
291
|
const sourceWithMark = paragraphMarkChange ? withParagraphMarkChange(verifiedSource, paragraphMarkChange) : verifiedSource;
|
|
414
292
|
return withTrailingParagraphPropertyChildren(sourceWithMark, [sectionPropertiesXml, ...propertyChangesXml]);
|
|
415
293
|
}
|
|
416
294
|
const parts = [];
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
};
|
|
421
|
-
if (formatting) {
|
|
422
|
-
if (formatting.styleId) parts.push(`<w:pStyle w:val="${escapeXml(formatting.styleId)}"/>`);
|
|
423
|
-
pushToggle("keepNext", formatting.keepNext);
|
|
424
|
-
pushToggle("keepLines", formatting.keepLines);
|
|
425
|
-
pushToggle("pageBreakBefore", formatting.pageBreakBefore);
|
|
426
|
-
const frameXml = serializeFrameProperties(formatting.frame);
|
|
427
|
-
if (frameXml) parts.push(frameXml);
|
|
428
|
-
pushToggle("widowControl", formatting.widowControl);
|
|
429
|
-
const numPrXml = formatting.numPrFromStyle != null && numPrEqual(formatting.numPr, formatting.numPrFromStyle) ? "" : serializeNumbering(formatting.numPr);
|
|
430
|
-
if (numPrXml) parts.push(numPrXml);
|
|
431
|
-
pushToggle("suppressLineNumbers", formatting.suppressLineNumbers);
|
|
432
|
-
const bordersXml = serializeParagraphBorders(formatting.borders);
|
|
433
|
-
if (bordersXml) parts.push(bordersXml);
|
|
434
|
-
const shadingXml = serializeShading(formatting.shading);
|
|
435
|
-
if (shadingXml) parts.push(shadingXml);
|
|
436
|
-
const tabsXml = serializeTabStops(formatting.tabs);
|
|
437
|
-
if (tabsXml) parts.push(tabsXml);
|
|
438
|
-
pushToggle("suppressAutoHyphens", formatting.suppressAutoHyphens);
|
|
439
|
-
pushToggle("kinsoku", formatting.kinsoku);
|
|
440
|
-
pushToggle("overflowPunct", formatting.overflowPunctuation);
|
|
441
|
-
pushToggle("bidi", formatting.bidi);
|
|
442
|
-
pushToggle("snapToGrid", formatting.snapToGrid);
|
|
443
|
-
const spacingXml = serializeSpacing(formatting);
|
|
444
|
-
if (spacingXml) parts.push(spacingXml);
|
|
445
|
-
const indXml = serializeIndentation(formatting);
|
|
446
|
-
if (indXml) parts.push(indXml);
|
|
447
|
-
pushToggle("contextualSpacing", formatting.contextualSpacing);
|
|
448
|
-
if (formatting.alignment) parts.push(`<w:jc w:val="${formatting.alignment}"/>`);
|
|
449
|
-
if (formatting.outlineLevel !== void 0) parts.push(`<w:outlineLvl w:val="${formatting.outlineLevel}"/>`);
|
|
450
|
-
if (paragraphMarkChange || formatting.runProperties || formatting.runInWithNext) {
|
|
451
|
-
const fullInner = `${paragraphMarkChange ? paragraphMarkXml : ""}${formatting.runProperties ? extractRPrInner(serializeTextFormatting(formatting.runProperties)) : ""}${formatting.runInWithNext ? "<w:specVanish/>" : ""}`;
|
|
452
|
-
if (fullInner.length > 0) parts.push(`<w:rPr>${fullInner}</w:rPr>`);
|
|
453
|
-
}
|
|
454
|
-
} else if (paragraphMarkChange) parts.push(`<w:rPr>${paragraphMarkXml}</w:rPr>`);
|
|
295
|
+
if (modeledFormatting.propertiesXml) parts.push(modeledFormatting.propertiesXml);
|
|
296
|
+
const paragraphMarkPropertiesInnerXml = `${paragraphMarkXml}${modeledFormatting.paragraphMarkPropertiesInnerXml ?? ""}`;
|
|
297
|
+
if (paragraphMarkPropertiesInnerXml) parts.push(`<w:rPr>${paragraphMarkPropertiesInnerXml}</w:rPr>`);
|
|
455
298
|
parts.push(sectionPropertiesXml);
|
|
456
299
|
if (propertyChangesXml.length > 0) parts.push(...propertyChangesXml);
|
|
457
300
|
const inner = parts.join("");
|
|
@@ -468,15 +311,6 @@ function extractPPrInner(pPrXml) {
|
|
|
468
311
|
if (!pPrXml.startsWith("<w:pPr>") || !pPrXml.endsWith("</w:pPr>")) return "";
|
|
469
312
|
return pPrXml.slice(7, -8);
|
|
470
313
|
}
|
|
471
|
-
/**
|
|
472
|
-
* Strip the outer `<w:rPr>...</w:rPr>` wrapper so callers can splice
|
|
473
|
-
* additional rPr children (e.g. `<w:specVanish/>`) and re-emit a
|
|
474
|
-
* single rPr element.
|
|
475
|
-
*/
|
|
476
|
-
function extractRPrInner(rPrXml) {
|
|
477
|
-
if (!rPrXml.startsWith("<w:rPr>") || !rPrXml.endsWith("</w:rPr>")) return "";
|
|
478
|
-
return rPrXml.slice(7, -8);
|
|
479
|
-
}
|
|
480
314
|
function serializeParagraphPropertyChange(change) {
|
|
481
315
|
const previousPPrInner = extractPPrInner(serializeParagraphFormatting(change.previousFormatting) || "<w:pPr/>");
|
|
482
316
|
const normalizedPreviousPPr = previousPPrInner.length > 0 ? `<w:pPr>${previousPPrInner}</w:pPr>` : "<w:pPr/>";
|
|
@@ -675,6 +509,7 @@ function serializeTrackedChange(tag, change) {
|
|
|
675
509
|
const xml = item.type === "simpleField" ? serializeSimpleField(item) : serializeComplexField(item);
|
|
676
510
|
return tag === "del" || tag === "moveFrom" ? rewriteRunTextAsDeleted(xml) : xml;
|
|
677
511
|
}
|
|
512
|
+
if (item.type === "mathEquation") return item.ommlXml;
|
|
678
513
|
if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return serializeTrackedChange(trackedChangeTag(item), item);
|
|
679
514
|
return item.type === "bookmarkStart" ? serializeBookmarkStart(item) : serializeBookmarkEnd(item);
|
|
680
515
|
};
|
|
@@ -751,6 +586,7 @@ function serializeParagraph(paragraph) {
|
|
|
751
586
|
const attrs = [];
|
|
752
587
|
if (paragraph.paraId) attrs.push(`w14:paraId="${escapeXml(paragraph.paraId)}"`);
|
|
753
588
|
if (paragraph.textId) attrs.push(`w14:textId="${escapeXml(paragraph.textId)}"`);
|
|
589
|
+
if (paragraph.reviewCarrier) attrs.push(`folio:reviewCarrier="${paragraph.reviewCarrier}"`);
|
|
754
590
|
const attrsStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
755
591
|
parts.push(serializeParagraphFormattingWithOptions(paragraph.formatting, {
|
|
756
592
|
propertyChanges: paragraph.propertyChanges,
|
|
@@ -25,7 +25,7 @@ type PackagingPrefix = "ct" | "pr";
|
|
|
25
25
|
* over the union: a member with no entry, or an entry with no member, does not
|
|
26
26
|
* compile.
|
|
27
27
|
*/
|
|
28
|
-
type OoxmlNamespacePrefix = Exclude<OoxmlPrefix, PackagingPrefix> | "cx" | "cx1" | "cx2" | "cx3" | "cx4" | "cx5" | "cx6" | "cx7" | "cx8" | "aink" | "am3d" | "oel" | "w10" | "w16" | "w16cex" | "w16cid" | "w16du" | "w16sdtdh" | "w16se" | "wpi" | "wne";
|
|
28
|
+
type OoxmlNamespacePrefix = Exclude<OoxmlPrefix, PackagingPrefix> | "cx" | "cx1" | "cx2" | "cx3" | "cx4" | "cx5" | "cx6" | "cx7" | "cx8" | "aink" | "am3d" | "oel" | "w10" | "w16" | "w16cex" | "w16cid" | "w16du" | "w16sdtdh" | "w16se" | "folio" | "wpi" | "wne";
|
|
29
29
|
/**
|
|
30
30
|
* Every namespace a rebuilt part can declare, in the order producers write them.
|
|
31
31
|
*
|
|
@@ -143,6 +143,10 @@ const OOXML_NAMESPACES = {
|
|
|
143
143
|
uri: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
|
|
144
144
|
ignorable: true
|
|
145
145
|
},
|
|
146
|
+
folio: {
|
|
147
|
+
uri: "urn:stella:folio:review-history:1",
|
|
148
|
+
ignorable: true
|
|
149
|
+
},
|
|
146
150
|
wpg: {
|
|
147
151
|
uri: OOXML_NS.wpg,
|
|
148
152
|
ignorable: false
|
|
@@ -5,10 +5,6 @@ import { document_d_exports } from "../../types/document.js";
|
|
|
5
5
|
* to keep IDs deterministic across saves.
|
|
6
6
|
*/
|
|
7
7
|
declare function resetAutoIdCounter(): void;
|
|
8
|
-
/**
|
|
9
|
-
* Serialize text formatting properties to w:rPr XML
|
|
10
|
-
*/
|
|
11
|
-
declare function serializeTextFormatting(formatting: document_d_exports.TextFormatting | undefined): string;
|
|
12
8
|
/**
|
|
13
9
|
* Serialize a run to OOXML XML (w:r)
|
|
14
10
|
*
|
|
@@ -52,4 +48,4 @@ declare function createBreakRun(breakType?: "page" | "column" | "textWrapping",
|
|
|
52
48
|
*/
|
|
53
49
|
declare function createTabRun(formatting?: document_d_exports.TextFormatting): document_d_exports.Run;
|
|
54
50
|
//#endregion
|
|
55
|
-
export { createBreakRun, createEmptyRun, createTabRun, createTextRun, getRunPlainText, hasRunContent, hasRunFormatting, resetAutoIdCounter, serializeRun, serializeRuns
|
|
51
|
+
export { createBreakRun, createEmptyRun, createTabRun, createTextRun, getRunPlainText, hasRunContent, hasRunFormatting, resetAutoIdCounter, serializeRun, serializeRuns };
|