@stll/folio-core 0.45.0 → 0.46.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 +59 -19
- package/dist/ai-edits/headless.js +1 -1
- package/dist/compare/compare.js +2 -5
- package/dist/compare/scenario.js +2 -5
- package/dist/compare/types.d.ts +9 -1
- package/dist/compare/types.js +12 -1
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/content-controls/checkboxDisplay.d.ts +11 -0
- package/dist/content-controls/checkboxDisplay.js +40 -0
- package/dist/content-controls/findContentControls.js +3 -1
- package/dist/content-controls/mutateContentControls.js +17 -2
- package/dist/controller/contentControlWidgetController.d.ts +1 -0
- package/dist/controller/contentControlWidgetController.js +3 -0
- package/dist/controller/hiddenEditorApi.js +3 -1
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +6 -3
- package/dist/display-list/build/buildDisplayList.js +20 -1
- package/dist/display-list/build/imagePrimitives.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +3 -1
- package/dist/display-list/build/paragraphPrimitives.js +21 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +10 -2
- package/dist/display-list/types.d.ts +17 -0
- package/dist/docx/attributeRemainder.d.ts +43 -0
- package/dist/docx/attributeRemainder.js +65 -0
- package/dist/docx/blockContentParser.d.ts +1 -1
- package/dist/docx/blockContentParser.js +87 -63
- package/dist/docx/blockPlainText.d.ts +3 -4
- package/dist/docx/blockPlainText.js +1 -0
- package/dist/docx/bookmarkPlacement.js +2 -0
- package/dist/docx/commentAnchorIndex.d.ts +30 -0
- package/dist/docx/commentAnchorIndex.js +50 -0
- package/dist/docx/commentParser.d.ts +1 -1
- package/dist/docx/commentParser.js +54 -37
- package/dist/docx/commentRangeIntegrity.d.ts +16 -1
- package/dist/docx/commentRangeIntegrity.js +42 -1
- package/dist/docx/commentRangeJoin.d.ts +9 -0
- package/dist/docx/commentRangeJoin.js +33 -0
- package/dist/docx/commentReferenceCompletion.d.ts +9 -0
- package/dist/docx/commentReferenceCompletion.js +47 -0
- package/dist/docx/commentReferenceNormalization.js +1 -0
- package/dist/docx/commentReplyMarkers.js +11 -19
- package/dist/docx/compatibility.js +1 -0
- package/dist/docx/containerChildren.d.ts +111 -0
- package/dist/docx/containerChildren.gen.d.ts +28 -0
- package/dist/docx/containerChildren.gen.js +246 -0
- package/dist/docx/containerChildren.js +103 -0
- package/dist/docx/documentParser.d.ts +1 -1
- package/dist/docx/documentParser.js +3 -3
- package/dist/docx/ensureParaIds.js +17 -7
- package/dist/docx/fieldParser.d.ts +1 -1
- package/dist/docx/fieldParser.js +4 -4
- package/dist/docx/fieldState.d.ts +26 -0
- package/dist/docx/fieldState.js +53 -0
- package/dist/docx/footnoteParser.d.ts +1 -1
- package/dist/docx/graphicFrameLocks.d.ts +16 -4
- package/dist/docx/graphicFrameLocks.js +19 -6
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/headerFooterReferenceNormalization.js +1 -0
- package/dist/docx/hyperlinkParser.d.ts +27 -8
- package/dist/docx/hyperlinkParser.js +76 -18
- package/dist/docx/imageParser.js +33 -8
- package/dist/docx/inlineWrapperContent.d.ts +85 -0
- package/dist/docx/inlineWrapperContent.js +84 -0
- package/dist/docx/normalizeBaseDirection.js +10 -1
- package/dist/docx/paraIdAttribute.d.ts +21 -0
- package/dist/docx/paraIdAttribute.js +64 -0
- package/dist/docx/paragraphParser.d.ts +1 -1
- package/dist/docx/paragraphParser.js +277 -168
- package/dist/docx/paragraphPropertySource.js +5 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +6 -52
- package/dist/docx/paragraphTraversal.js +7 -4
- package/dist/docx/parseWarningMessage.js +2 -1
- package/dist/docx/preservedRunContent.d.ts +32 -0
- package/dist/docx/preservedRunContent.js +86 -0
- package/dist/docx/renderedPageBreakNormalization.js +2 -4
- package/dist/docx/rezip.js +74 -18
- package/dist/docx/runParser.d.ts +1 -1
- package/dist/docx/runParser.js +16 -12
- package/dist/docx/sectionParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.d.ts +46 -2
- package/dist/docx/selectiveXmlPatch.js +86 -39
- package/dist/docx/serializer/borderSerializer.js +2 -2
- package/dist/docx/serializer/commentSerializer.js +5 -7
- package/dist/docx/serializer/documentSerializer.js +8 -11
- package/dist/docx/serializer/headerFooterSerializer.js +7 -9
- package/dist/docx/serializer/noteSerializer.js +8 -8
- package/dist/docx/serializer/paragraphSerializer.js +76 -56
- package/dist/docx/serializer/runSerializer.js +25 -16
- package/dist/docx/serializer/sectionPropertiesSerializer.js +8 -4
- package/dist/docx/serializer/tableSerializer.js +18 -8
- package/dist/docx/server/createBilingualDocument.js +3 -1
- package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
- package/dist/docx/server/materializeYjsDocx.js +9 -1
- package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
- package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
- package/dist/docx/shapeParser.js +5 -5
- package/dist/docx/tableParser.d.ts +1 -1
- package/dist/docx/tableParser.js +206 -85
- package/dist/docx/textBoxParser.d.ts +25 -2
- package/dist/docx/textBoxParser.js +52 -2
- package/dist/docx/unzip.js +5 -4
- package/dist/docx/vmlImageParser.d.ts +17 -1
- package/dist/docx/vmlImageParser.js +17 -1
- package/dist/docx/xmlEncoding.d.ts +5 -0
- package/dist/docx/xmlEncoding.js +12 -0
- package/dist/docx/xmlParser.d.ts +10 -1
- package/dist/docx/xmlParser.js +14 -1
- package/dist/headless-layout.js +10 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +2 -0
- package/dist/layout-engine/types.d.ts +23 -1
- package/dist/layout-painter/renderImage.d.ts +5 -1
- package/dist/layout-painter/renderImage.js +10 -3
- package/dist/layout-painter/renderPage.d.ts +2 -0
- package/dist/layout-painter/renderPage.js +4 -0
- package/dist/layout-painter/renderParagraph.d.ts +13 -1
- package/dist/layout-painter/renderParagraph.js +22 -3
- package/dist/managers/autoSaveCodec.d.ts +9 -1
- package/dist/managers/autoSaveCodec.js +12 -4
- package/dist/markdown/renderBlock.js +1 -0
- package/dist/markdown/renderRuns.d.ts +1 -1
- package/dist/markdown/renderRuns.js +28 -5
- package/dist/markdown/renderTable.js +22 -5
- package/dist/markdown/trailers.js +4 -1
- package/dist/pdf/images.js +142 -6
- package/dist/prosemirror/attrs/index.d.ts +14 -3
- package/dist/prosemirror/attrs/index.js +155 -2
- package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
- package/dist/prosemirror/authoredTransformAttrs.js +64 -0
- package/dist/prosemirror/commands/contentControls.js +10 -2
- package/dist/prosemirror/commands/image.d.ts +9 -2
- package/dist/prosemirror/commands/image.js +42 -28
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
- package/dist/prosemirror/commentReferenceAttrs.js +33 -0
- package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
- package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +269 -70
- package/dist/prosemirror/conversion/index.d.ts +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
- package/dist/prosemirror/conversion/toProseDoc.js +468 -308
- package/dist/prosemirror/extensions/StarterKit.js +8 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
- package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
- package/dist/prosemirror/extensions/markRegistry.js +75 -0
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +16 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +3 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
- package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
- package/dist/prosemirror/inlineWrapperStack.js +75 -0
- package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
- package/dist/prosemirror/pageBreakRunProjection.js +19 -9
- package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
- package/dist/prosemirror/replacedAnnotations.js +165 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +25 -1
- package/dist/prosemirror/schema/nodes.d.ts +90 -3
- package/dist/prosemirror/schema/nodes.js +16 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
- package/dist/prosemirror/validation.js +16 -2
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
- package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
- package/dist/prosemirror/zeroWidthAnchors.js +2 -0
- package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
- package/dist/render-dom/commentAnchorAttributes.js +54 -0
- package/dist/server.d.ts +3 -1
- package/dist/server.js +3 -1
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/clipboard.d.ts +9 -1
- package/dist/utils/clipboard.js +27 -1
- package/dist/utils/findReplace.js +1 -1
- package/dist/utils/imageLuminance.d.ts +15 -0
- package/dist/utils/imageLuminance.js +32 -0
- package/dist/utils/mergeDocumentContent.js +7 -17
- package/dist/utils/replaceText.js +1 -0
- package/package.json +2 -2
- package/dist/docx/blockRangeMarkers.d.ts +0 -36
- package/dist/docx/blockRangeMarkers.js +0 -59
- package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
- package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
2
|
+
import { normalizeImageLuminancePercent } from "../../utils/imageLuminance.js";
|
|
3
|
+
import { serializePreservedAttributes } from "../attributeRemainder.js";
|
|
2
4
|
import { THEME_COLOR_TO_DRAWING_SCHEME } from "../drawingUtils.js";
|
|
5
|
+
import { fieldStateAttributes } from "../fieldState.js";
|
|
3
6
|
import { serializeGraphicFrameLocks } from "../graphicFrameLocks.js";
|
|
4
7
|
import { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE } from "../imageParser.js";
|
|
5
8
|
import { canReplayEditableImageRawXml } from "../imageRawXml.js";
|
|
@@ -103,10 +106,7 @@ function serializeNoteReference(content) {
|
|
|
103
106
|
* Serialize field character (w:fldChar)
|
|
104
107
|
*/
|
|
105
108
|
function serializeFieldChar(content) {
|
|
106
|
-
|
|
107
|
-
if (content.fldLock) attrs.push("w:fldLock=\"true\"");
|
|
108
|
-
if (content.dirty) attrs.push("w:dirty=\"true\"");
|
|
109
|
-
return `<w:fldChar ${attrs.join(" ")}/>`;
|
|
109
|
+
return `<w:fldChar ${[`w:fldCharType="${content.charType}"`, ...fieldStateAttributes(content)].join(" ")}/>`;
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
112
|
* Serialize field instruction text (w:instrText)
|
|
@@ -209,6 +209,17 @@ function serializeWrap(wrap) {
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
/**
|
|
212
|
+
* `a:xfrm` attributes for an authored transform.
|
|
213
|
+
*
|
|
214
|
+
* Written iff authored: `rot="0"` and `flipH="0"` are OOXML's defaults, so a
|
|
215
|
+
* truthiness guard cannot tell "the author said none" from "the author said
|
|
216
|
+
* nothing", and a save erased an authored zero.
|
|
217
|
+
*/
|
|
218
|
+
const serializeTransformAttrs = (transform) => {
|
|
219
|
+
if (transform === void 0) return "";
|
|
220
|
+
return `${transform.rotation === void 0 ? "" : ` rot="${Math.round(transform.rotation * 6e4)}"`}${transform.flipH === void 0 ? "" : ` flipH="${transform.flipH ? 1 : 0}"`}${transform.flipV === void 0 ? "" : ` flipV="${transform.flipV ? 1 : 0}"`}`;
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
212
223
|
* Build the common a:graphic > pic:pic element for images.
|
|
213
224
|
*
|
|
214
225
|
* Takes the relationship id as a separate argument so the caller has to have
|
|
@@ -221,18 +232,18 @@ function serializePicGraphic(image, imageRId, sharedId) {
|
|
|
221
232
|
const rId = escapeXmlAttribute(imageRId);
|
|
222
233
|
const id = sharedId;
|
|
223
234
|
const name = image.filename || `image${id}`;
|
|
224
|
-
|
|
225
|
-
if (image.transform?.rotation) xfrmAttrs += ` rot="${Math.round(image.transform.rotation * 6e4)}"`;
|
|
226
|
-
if (image.transform?.flipH) xfrmAttrs += " flipH=\"1\"";
|
|
227
|
-
if (image.transform?.flipV) xfrmAttrs += " flipV=\"1\"";
|
|
235
|
+
const xfrmAttrs = serializeTransformAttrs(image.transform);
|
|
228
236
|
const cropAttrs = [];
|
|
229
237
|
if (image.crop?.left) cropAttrs.push(`l="${Math.round(image.crop.left * 1e5)}"`);
|
|
230
238
|
if (image.crop?.top) cropAttrs.push(`t="${Math.round(image.crop.top * 1e5)}"`);
|
|
231
239
|
if (image.crop?.right) cropAttrs.push(`r="${Math.round(image.crop.right * 1e5)}"`);
|
|
232
240
|
if (image.crop?.bottom) cropAttrs.push(`b="${Math.round(image.crop.bottom * 1e5)}"`);
|
|
233
241
|
const srcRectEl = cropAttrs.length > 0 ? `<a:srcRect ${cropAttrs.join(" ")}/>` : "";
|
|
234
|
-
const
|
|
235
|
-
|
|
242
|
+
const luminanceAttrs = [];
|
|
243
|
+
if (image.effects?.brightness !== void 0 && Number.isFinite(image.effects.brightness)) luminanceAttrs.push(`bright="${Math.round(normalizeImageLuminancePercent(image.effects.brightness) * 1e3)}"`);
|
|
244
|
+
if (image.effects?.contrast !== void 0 && Number.isFinite(image.effects.contrast)) luminanceAttrs.push(`contrast="${Math.round(normalizeImageLuminancePercent(image.effects.contrast) * 1e3)}"`);
|
|
245
|
+
const blipChildren = `${luminanceAttrs.length === 0 ? "" : `<a:lum ${luminanceAttrs.join(" ")}/>`}${image.opacity !== void 0 && image.opacity < 1 ? `<a:alphaModFix amt="${Math.round(Math.max(0, image.opacity) * 1e5)}"/>` : ""}`;
|
|
246
|
+
const blipEl = blipChildren ? `<a:blip r:embed="${rId}">${blipChildren}</a:blip>` : `<a:blip r:embed="${rId}"/>`;
|
|
236
247
|
return [
|
|
237
248
|
"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">",
|
|
238
249
|
"<a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">",
|
|
@@ -373,13 +384,9 @@ function serializeShapeContent(content) {
|
|
|
373
384
|
...shape.alt !== void 0 ? { alt: shape.alt } : {},
|
|
374
385
|
...shape.title !== void 0 ? { title: shape.title } : {}
|
|
375
386
|
});
|
|
376
|
-
let xfrmAttrs = "";
|
|
377
|
-
if (shape.transform?.rotation) xfrmAttrs += ` rot="${Math.round(shape.transform.rotation * 6e4)}"`;
|
|
378
|
-
if (shape.transform?.flipH) xfrmAttrs += " flipH=\"1\"";
|
|
379
|
-
if (shape.transform?.flipV) xfrmAttrs += " flipV=\"1\"";
|
|
380
387
|
const spPr = [
|
|
381
388
|
"<wps:spPr>",
|
|
382
|
-
`<a:xfrm${
|
|
389
|
+
`<a:xfrm${serializeTransformAttrs(shape.transform)}>`,
|
|
383
390
|
"<a:off x=\"0\" y=\"0\"/>",
|
|
384
391
|
`<a:ext cx="${intAttr(cx)}" cy="${intAttr(cy)}"/>`,
|
|
385
392
|
"</a:xfrm>",
|
|
@@ -475,6 +482,7 @@ function serializeRunContent(content) {
|
|
|
475
482
|
case "softHyphen": return serializeSoftHyphen(content);
|
|
476
483
|
case "noBreakHyphen": return serializeNoBreakHyphen(content);
|
|
477
484
|
case "renderedPageBreak": return "<w:lastRenderedPageBreak/>";
|
|
485
|
+
case "preservedXml": return content.xml;
|
|
478
486
|
case "drawing":
|
|
479
487
|
if (content.rawXml && canReplayEditableImageRawXml(content)) return content.rawXml;
|
|
480
488
|
return serializeDrawingContent(content);
|
|
@@ -496,7 +504,8 @@ function serializeRun(run) {
|
|
|
496
504
|
const contentXml = serializeRunContent(content);
|
|
497
505
|
if (contentXml) parts.push(contentXml);
|
|
498
506
|
}
|
|
499
|
-
|
|
507
|
+
const attrs = serializePreservedAttributes([], run.preservedAttributes);
|
|
508
|
+
return `<w:r${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}>${parts.join("")}</w:r>`;
|
|
500
509
|
}
|
|
501
510
|
/**
|
|
502
511
|
* Serialize multiple runs to OOXML XML
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serializePreservedAttributes } from "../attributeRemainder.js";
|
|
1
2
|
import { getUnserializedSectionPropertyChildNames } from "../sectionParser.js";
|
|
2
3
|
import { serializeSectionReferenceHistory } from "../sectionReferenceHistory.js";
|
|
3
4
|
import { serializeBorder } from "./borderSerializer.js";
|
|
@@ -53,12 +54,12 @@ function serializePaperSource(props) {
|
|
|
53
54
|
return attrs.length > 0 ? `<w:paperSrc ${attrs.join(" ")}/>` : "";
|
|
54
55
|
}
|
|
55
56
|
function serializeColumns(props) {
|
|
56
|
-
if (props.columnCount === void 0 && !props.columns?.length && props.columnSpace === void 0 && props.equalWidth === void 0) return "";
|
|
57
|
+
if (props.columnCount === void 0 && !props.columns?.length && props.columnSpace === void 0 && props.equalWidth === void 0 && props.separator === void 0) return "";
|
|
57
58
|
const attrs = [];
|
|
58
59
|
if (props.columnCount !== void 0 && props.columnCount >= 1) attrs.push(`w:num="${intAttr(props.columnCount)}"`);
|
|
59
60
|
if (props.columnSpace !== void 0) attrs.push(`w:space="${intAttr(props.columnSpace)}"`);
|
|
60
61
|
if (props.equalWidth !== void 0) attrs.push(`w:equalWidth="${props.equalWidth ? "1" : "0"}"`);
|
|
61
|
-
if (props.separator) attrs.push(
|
|
62
|
+
if (props.separator !== void 0) attrs.push(`w:sep="${props.separator ? "1" : "0"}"`);
|
|
62
63
|
const colElements = (props.columns ?? []).map((col) => {
|
|
63
64
|
const colAttrs = [];
|
|
64
65
|
if (col.width !== void 0) colAttrs.push(`w:w="${intAttr(col.width)}"`);
|
|
@@ -178,8 +179,11 @@ function serializeSectionProperties(props) {
|
|
|
178
179
|
for (const change of props.propertyChanges ?? []) parts.push(serializeSectionPropertyChange(change));
|
|
179
180
|
const unserializedChildNames = getUnserializedSectionPropertyChildNames(props);
|
|
180
181
|
if (unserializedChildNames && unserializedChildNames.length > 0) return "";
|
|
181
|
-
|
|
182
|
-
|
|
182
|
+
const attributes = serializePreservedAttributes([], props.preservedAttributes);
|
|
183
|
+
const startTag = attributes.length > 0 ? `<w:sectPr ${attributes.join(" ")}` : "<w:sectPr";
|
|
184
|
+
if (parts.length > 0) return `${startTag}>${parts.join("")}</w:sectPr>`;
|
|
185
|
+
if (Object.keys(props).some((key) => key !== "preservedAttributes")) return "";
|
|
186
|
+
if (attributes.length > 0) return `${startTag}/>`;
|
|
183
187
|
return "<w:sectPr/>";
|
|
184
188
|
}
|
|
185
189
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { canonicalJson } from "../../utils/canonicalJson.js";
|
|
2
2
|
import { isValidHexColor } from "../../utils/colorResolver.js";
|
|
3
|
-
import {
|
|
3
|
+
import { serializePreservedAttributes } from "../attributeRemainder.js";
|
|
4
|
+
import { serializeWithPreservedChildren } from "../containerChildren.js";
|
|
4
5
|
import { TABLE_LOOK_FLAGS } from "../tableLook.js";
|
|
5
6
|
import { parseTableCellProperties, parseTableGrid, parseTableProperties, parseTableRowProperties } from "../tableParser.js";
|
|
6
7
|
import { sanitizeCapturedXmlElement } from "../verbatimCapture.js";
|
|
@@ -369,8 +370,14 @@ const replayableGridChangeXml = (gridChangeXml) => sanitizeCapturedXmlElement(gr
|
|
|
369
370
|
* Serialize cell content (paragraphs, nested tables)
|
|
370
371
|
*/
|
|
371
372
|
function serializeCellContent(content, serializeParagraph) {
|
|
372
|
-
const parts =
|
|
373
|
-
|
|
373
|
+
const parts = content.map((block) => {
|
|
374
|
+
switch (block.type) {
|
|
375
|
+
case "paragraph": return serializeParagraph(block);
|
|
376
|
+
case "table": return serializeTable(block, serializeParagraph);
|
|
377
|
+
case "preservedBlock": return block.xml;
|
|
378
|
+
default: return block;
|
|
379
|
+
}
|
|
380
|
+
});
|
|
374
381
|
if (parts.length === 0) parts.push("<w:p/>");
|
|
375
382
|
return parts.join("");
|
|
376
383
|
}
|
|
@@ -391,8 +398,9 @@ function serializeTableRow(row, serializeParagraph) {
|
|
|
391
398
|
const parts = [];
|
|
392
399
|
const trPrXml = serializeTableRowFormatting(row.formatting, row.propertyChanges, row.structuralChange);
|
|
393
400
|
if (trPrXml) parts.push(trPrXml);
|
|
394
|
-
|
|
395
|
-
|
|
401
|
+
parts.push(serializeWithPreservedChildren(row.cells.map((cell) => serializeTableCell(cell, serializeParagraph)), row.preserved));
|
|
402
|
+
const attrs = serializePreservedAttributes([], row.preservedAttributes);
|
|
403
|
+
return `<w:tr${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}>${parts.join("")}</w:tr>`;
|
|
396
404
|
}
|
|
397
405
|
/**
|
|
398
406
|
* Serialize a table to OOXML XML (w:tbl)
|
|
@@ -401,9 +409,11 @@ function serializeTableRow(row, serializeParagraph) {
|
|
|
401
409
|
* @returns XML string for the table
|
|
402
410
|
*/
|
|
403
411
|
function serializeTable(table, serializeParagraph) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
412
|
+
return `<w:tbl>${[
|
|
413
|
+
serializeTableFormatting(table.formatting, table.propertyChanges) || "<w:tblPr/>",
|
|
414
|
+
serializeTableGrid(table),
|
|
415
|
+
serializeWithPreservedChildren(table.rows.map((row) => serializeTableRow(row, serializeParagraph)), table.preserved)
|
|
416
|
+
].join("")}</w:tbl>`;
|
|
407
417
|
}
|
|
408
418
|
/**
|
|
409
419
|
* Serialize multiple tables to OOXML XML
|
|
@@ -203,6 +203,7 @@ const flattenBlocks = (content) => {
|
|
|
203
203
|
out.push(block);
|
|
204
204
|
return;
|
|
205
205
|
}
|
|
206
|
+
if (block.type === "preservedBlock") return;
|
|
206
207
|
for (const child of block.content) visit(child);
|
|
207
208
|
};
|
|
208
209
|
for (const block of content) visit(block);
|
|
@@ -462,7 +463,7 @@ const remapListRendering = (rendering, cloner) => {
|
|
|
462
463
|
const collectTableParagraphs = (table) => {
|
|
463
464
|
const out = [];
|
|
464
465
|
for (const row of table.rows) for (const cell of row.cells) for (const item of cell.content) if (item.type === "paragraph") out.push(item);
|
|
465
|
-
else out.push(...collectTableParagraphs(item));
|
|
466
|
+
else if (item.type === "table") out.push(...collectTableParagraphs(item));
|
|
466
467
|
return out;
|
|
467
468
|
};
|
|
468
469
|
const cloneTableForTarget = ({ table, editableParagraphIds, paraIds, styleCloner, cloner, bookmarkIds }) => {
|
|
@@ -475,6 +476,7 @@ const cloneTableForTarget = ({ table, editableParagraphIds, paraIds, styleCloner
|
|
|
475
476
|
...structuredClone(cell),
|
|
476
477
|
content: cell.content.map((item) => {
|
|
477
478
|
if (item.type === "table") return cloneTable(item);
|
|
479
|
+
if (item.type !== "paragraph") return structuredClone(item);
|
|
478
480
|
const targetParaId = paraIds.mint(item.paraId);
|
|
479
481
|
const copy = cloneParagraphForTarget(item, targetParaId, styleCloner, cloner, bookmarkIds);
|
|
480
482
|
if (isTranslatableParagraph(item, editableParagraphIds)) paragraphs.push({
|
|
@@ -4,7 +4,7 @@ declare const FOLIO_YJS_PROSEMIRROR_FRAGMENT_NAME = "prosemirror";
|
|
|
4
4
|
/** Maximum accepted size of a complete Yjs collaboration state update. */
|
|
5
5
|
declare const FOLIO_YJS_UPDATE_MAX_BYTES: number;
|
|
6
6
|
/** Stable failure codes returned by server-side Yjs-to-DOCX materialization. */
|
|
7
|
-
declare const FOLIO_YJS_DOCX_MATERIALIZATION_ERROR_CODES: readonly ["empty_update", "invalid_update", "missing_document", "source_mismatch", "update_too_large"];
|
|
7
|
+
declare const FOLIO_YJS_DOCX_MATERIALIZATION_ERROR_CODES: readonly ["empty_update", "invalid_update", "missing_document", "source_mismatch", "stale_attr_schema", "update_too_large"];
|
|
8
8
|
/** Failure code for a rejected Yjs-to-DOCX materialization request. */
|
|
9
9
|
type FolioYjsDocxMaterializationErrorCode = (typeof FOLIO_YJS_DOCX_MATERIALIZATION_ERROR_CODES)[number];
|
|
10
10
|
declare const FolioYjsDocxMaterializationError_base: import("better-result").TaggedErrorClass<"FolioYjsDocxMaterializationError">;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromProseDoc } from "../../prosemirror/conversion/fromProseDoc.js";
|
|
2
2
|
import { schema } from "../../prosemirror/schema/index.js";
|
|
3
|
-
import { readYjsParagraphSourceContract, withParagraphSourceContract } from "../../prosemirror/
|
|
3
|
+
import { applyAttrSchemaMigrations, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
4
4
|
import { ParagraphPropertySourceValidationError } from "../paragraphPropertySource.js";
|
|
5
5
|
import { parseDocx } from "../parser.js";
|
|
6
6
|
import { repackDocx } from "../rezip.js";
|
|
@@ -18,6 +18,7 @@ const FOLIO_YJS_DOCX_MATERIALIZATION_ERROR_CODES = [
|
|
|
18
18
|
"invalid_update",
|
|
19
19
|
"missing_document",
|
|
20
20
|
"source_mismatch",
|
|
21
|
+
"stale_attr_schema",
|
|
21
22
|
"update_too_large"
|
|
22
23
|
];
|
|
23
24
|
/** Typed failure raised when a collaboration snapshot cannot be materialized. */
|
|
@@ -40,6 +41,13 @@ const readProseMirrorDocument = (yjsUpdate) => {
|
|
|
40
41
|
code: "missing_document",
|
|
41
42
|
message: "Yjs update does not contain a Folio document."
|
|
42
43
|
});
|
|
44
|
+
const attrSchemaVersion = readYjsAttrSchemaVersion(ydoc);
|
|
45
|
+
if (attrSchemaVersion.isErr()) throw new FolioYjsDocxMaterializationError({
|
|
46
|
+
cause: attrSchemaVersion.error,
|
|
47
|
+
code: "stale_attr_schema",
|
|
48
|
+
message: attrSchemaVersion.error.message
|
|
49
|
+
});
|
|
50
|
+
applyAttrSchemaMigrations(ydoc, fragment, attrSchemaVersion.value);
|
|
43
51
|
const contract = readYjsParagraphSourceContract(ydoc);
|
|
44
52
|
if (!contract) throw new FolioYjsDocxMaterializationError({
|
|
45
53
|
code: "source_mismatch",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { FolioYjsAttrSchemaVersion } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
//#region src/docx/server/migrateYjsAttrSchema.d.ts
|
|
4
|
+
/** Stable failure codes returned by an offline snapshot migration. */
|
|
5
|
+
declare const FOLIO_YJS_SNAPSHOT_MIGRATION_ERROR_CODES: readonly ["invalid_update", "unsupported_version", "update_too_large"];
|
|
6
|
+
/** Failure code for a snapshot that could not be migrated. */
|
|
7
|
+
type FolioYjsSnapshotMigrationErrorCode = (typeof FOLIO_YJS_SNAPSHOT_MIGRATION_ERROR_CODES)[number];
|
|
8
|
+
declare const FolioYjsSnapshotMigrationError_base: import("better-result").TaggedErrorClass<"FolioYjsSnapshotMigrationError">;
|
|
9
|
+
/** Typed failure raised when a collaboration snapshot cannot be migrated. */
|
|
10
|
+
declare class FolioYjsSnapshotMigrationError extends FolioYjsSnapshotMigrationError_base<{
|
|
11
|
+
code: FolioYjsSnapshotMigrationErrorCode;
|
|
12
|
+
message: string;
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
}> {}
|
|
15
|
+
/** What an offline migration did to one snapshot. */
|
|
16
|
+
type FolioYjsSnapshotMigrationResult = {
|
|
17
|
+
/** The complete state update to store in place of the input. */
|
|
18
|
+
update: Uint8Array;
|
|
19
|
+
/** The attr-schema version the input was written under. */
|
|
20
|
+
fromVersion: FolioYjsAttrSchemaVersion;
|
|
21
|
+
/** The attr-schema version the output carries. */
|
|
22
|
+
toVersion: FolioYjsAttrSchemaVersion;
|
|
23
|
+
/** Paragraphs whose attrs the migration rewrote. */
|
|
24
|
+
paragraphsRewritten: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Carry a stored collaboration snapshot forward to the attr schema this build
|
|
28
|
+
* writes, without a ProseMirror schema and without rebuilding a single node.
|
|
29
|
+
*
|
|
30
|
+
* A Yjs XML element's attributes are ordinary CRDT map entries holding JSON, so
|
|
31
|
+
* {@link applyAttrSchemaMigrations} rewrites values in the fragment directly.
|
|
32
|
+
* Nothing here can trip y-prosemirror's node rebuild, which deletes an element
|
|
33
|
+
* it fails to construct. The function is pure and offline: no network, no
|
|
34
|
+
* DOCX, no editor.
|
|
35
|
+
*
|
|
36
|
+
* A snapshot already at the current version is returned byte for byte, so a
|
|
37
|
+
* host may run this over its whole corpus repeatedly.
|
|
38
|
+
*
|
|
39
|
+
* **The contract a reseed must respect.** This function never reseeds and never
|
|
40
|
+
* touches the paragraph-source contract: it preserves whichever source binding
|
|
41
|
+
* the snapshot already carries. A reseed does the opposite, and Folio holds it
|
|
42
|
+
* to one rule: *the DOCX handed to the seeding editor must be the same bytes
|
|
43
|
+
* the host will later pass to `materializeYjsDocx` as that room's source*.
|
|
44
|
+
* The contract is a digest of those bytes, so seeding from one document while
|
|
45
|
+
* recording another as the room's source makes every later save fail with
|
|
46
|
+
* `source_mismatch`. The reverse mistake is worse and Folio cannot see it: a
|
|
47
|
+
* host that reseeds from the document a room was *created* from, rather than
|
|
48
|
+
* from the latest content it published, produces a perfectly well-formed
|
|
49
|
+
* snapshot whose collaborative history has been replaced by an older document.
|
|
50
|
+
* Rebind the recorded source in the same statement that clears the seed, or do
|
|
51
|
+
* not clear it.
|
|
52
|
+
*/
|
|
53
|
+
declare const migrateFolioYjsSnapshot: (update: Uint8Array) => Result<FolioYjsSnapshotMigrationResult, FolioYjsSnapshotMigrationError>;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { FOLIO_YJS_SNAPSHOT_MIGRATION_ERROR_CODES, FolioYjsSnapshotMigrationError, FolioYjsSnapshotMigrationErrorCode, FolioYjsSnapshotMigrationResult, migrateFolioYjsSnapshot };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { applyAttrSchemaMigrations, readYjsAttrSchemaVersion } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
2
|
+
import { FOLIO_YJS_PROSEMIRROR_FRAGMENT_NAME } from "./materializeYjsDocx.js";
|
|
3
|
+
import { Result, TaggedError } from "better-result";
|
|
4
|
+
import * as Y from "yjs";
|
|
5
|
+
//#region src/docx/server/migrateYjsAttrSchema.ts
|
|
6
|
+
/** Stable failure codes returned by an offline snapshot migration. */
|
|
7
|
+
const FOLIO_YJS_SNAPSHOT_MIGRATION_ERROR_CODES = [
|
|
8
|
+
"invalid_update",
|
|
9
|
+
"unsupported_version",
|
|
10
|
+
"update_too_large"
|
|
11
|
+
];
|
|
12
|
+
/** Typed failure raised when a collaboration snapshot cannot be migrated. */
|
|
13
|
+
var FolioYjsSnapshotMigrationError = class extends TaggedError("FolioYjsSnapshotMigrationError") {};
|
|
14
|
+
/**
|
|
15
|
+
* Carry a stored collaboration snapshot forward to the attr schema this build
|
|
16
|
+
* writes, without a ProseMirror schema and without rebuilding a single node.
|
|
17
|
+
*
|
|
18
|
+
* A Yjs XML element's attributes are ordinary CRDT map entries holding JSON, so
|
|
19
|
+
* {@link applyAttrSchemaMigrations} rewrites values in the fragment directly.
|
|
20
|
+
* Nothing here can trip y-prosemirror's node rebuild, which deletes an element
|
|
21
|
+
* it fails to construct. The function is pure and offline: no network, no
|
|
22
|
+
* DOCX, no editor.
|
|
23
|
+
*
|
|
24
|
+
* A snapshot already at the current version is returned byte for byte, so a
|
|
25
|
+
* host may run this over its whole corpus repeatedly.
|
|
26
|
+
*
|
|
27
|
+
* **The contract a reseed must respect.** This function never reseeds and never
|
|
28
|
+
* touches the paragraph-source contract: it preserves whichever source binding
|
|
29
|
+
* the snapshot already carries. A reseed does the opposite, and Folio holds it
|
|
30
|
+
* to one rule: *the DOCX handed to the seeding editor must be the same bytes
|
|
31
|
+
* the host will later pass to `materializeYjsDocx` as that room's source*.
|
|
32
|
+
* The contract is a digest of those bytes, so seeding from one document while
|
|
33
|
+
* recording another as the room's source makes every later save fail with
|
|
34
|
+
* `source_mismatch`. The reverse mistake is worse and Folio cannot see it: a
|
|
35
|
+
* host that reseeds from the document a room was *created* from, rather than
|
|
36
|
+
* from the latest content it published, produces a perfectly well-formed
|
|
37
|
+
* snapshot whose collaborative history has been replaced by an older document.
|
|
38
|
+
* Rebind the recorded source in the same statement that clears the seed, or do
|
|
39
|
+
* not clear it.
|
|
40
|
+
*/
|
|
41
|
+
const migrateFolioYjsSnapshot = (update) => {
|
|
42
|
+
if (update.byteLength === 0) return Result.err(new FolioYjsSnapshotMigrationError({
|
|
43
|
+
code: "invalid_update",
|
|
44
|
+
message: "Cannot migrate an empty Yjs update."
|
|
45
|
+
}));
|
|
46
|
+
if (update.byteLength > 10485760) return Result.err(new FolioYjsSnapshotMigrationError({
|
|
47
|
+
code: "update_too_large",
|
|
48
|
+
message: "Yjs update exceeds the snapshot migration limit."
|
|
49
|
+
}));
|
|
50
|
+
const ydoc = new Y.Doc();
|
|
51
|
+
const applied = Result.try({
|
|
52
|
+
try: () => {
|
|
53
|
+
Y.applyUpdate(ydoc, update);
|
|
54
|
+
},
|
|
55
|
+
catch: (cause) => new FolioYjsSnapshotMigrationError({
|
|
56
|
+
cause,
|
|
57
|
+
code: "invalid_update",
|
|
58
|
+
message: "Yjs update is not a valid Folio collaboration snapshot."
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
if (applied.isErr()) {
|
|
62
|
+
ydoc.destroy();
|
|
63
|
+
return Result.err(applied.error);
|
|
64
|
+
}
|
|
65
|
+
const read = readYjsAttrSchemaVersion(ydoc);
|
|
66
|
+
if (read.isErr()) {
|
|
67
|
+
ydoc.destroy();
|
|
68
|
+
return Result.err(new FolioYjsSnapshotMigrationError({
|
|
69
|
+
cause: read.error,
|
|
70
|
+
code: "unsupported_version",
|
|
71
|
+
message: read.error.message
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
const fromVersion = read.value;
|
|
75
|
+
if (fromVersion === 3) {
|
|
76
|
+
ydoc.destroy();
|
|
77
|
+
return Result.ok({
|
|
78
|
+
fromVersion,
|
|
79
|
+
paragraphsRewritten: 0,
|
|
80
|
+
toVersion: 3,
|
|
81
|
+
update
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const paragraphsRewritten = applyAttrSchemaMigrations(ydoc, ydoc.getXmlFragment(FOLIO_YJS_PROSEMIRROR_FRAGMENT_NAME), fromVersion);
|
|
85
|
+
const migrated = Y.encodeStateAsUpdate(ydoc);
|
|
86
|
+
ydoc.destroy();
|
|
87
|
+
return Result.ok({
|
|
88
|
+
fromVersion,
|
|
89
|
+
paragraphsRewritten,
|
|
90
|
+
toVersion: 3,
|
|
91
|
+
update: migrated
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
export { FOLIO_YJS_SNAPSHOT_MIGRATION_ERROR_CODES, FolioYjsSnapshotMigrationError, migrateFolioYjsSnapshot };
|
package/dist/docx/shapeParser.js
CHANGED
|
@@ -27,13 +27,13 @@ function parseTransform(xfrm) {
|
|
|
27
27
|
height: parseNumericAttribute(ext, null, "cy") ?? 0
|
|
28
28
|
};
|
|
29
29
|
const rotation = rotToDegrees(getAttribute(xfrm, null, "rot"));
|
|
30
|
-
const flipH = parseOnOffAttribute(xfrm, null, "flipH")
|
|
31
|
-
const flipV = parseOnOffAttribute(xfrm, null, "flipV")
|
|
32
|
-
if (rotation === void 0 &&
|
|
30
|
+
const flipH = parseOnOffAttribute(xfrm, null, "flipH");
|
|
31
|
+
const flipV = parseOnOffAttribute(xfrm, null, "flipV");
|
|
32
|
+
if (rotation === void 0 && flipH === void 0 && flipV === void 0) return { size };
|
|
33
33
|
const transform = {};
|
|
34
34
|
if (rotation !== void 0) transform.rotation = rotation;
|
|
35
|
-
if (flipH) transform.flipH =
|
|
36
|
-
if (flipV) transform.flipV =
|
|
35
|
+
if (flipH !== void 0) transform.flipH = flipH;
|
|
36
|
+
if (flipV !== void 0) transform.flipV = flipV;
|
|
37
37
|
return {
|
|
38
38
|
size,
|
|
39
39
|
transform
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { NumberingMap } from "./numberingParser.js";
|
|
3
|
-
import { StyleMap } from "./styleParser.js";
|
|
4
3
|
import { XmlElement } from "./xmlParser.js";
|
|
4
|
+
import { StyleMap } from "./styleParser.js";
|
|
5
5
|
//#region src/docx/tableParser.d.ts
|
|
6
6
|
/**
|
|
7
7
|
* Sanity cap on `w:gridSpan` (and the derived table column count). Word's
|