@stll/folio-core 0.55.0 → 0.56.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 +169 -38
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +476 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComposition.d.ts +20 -3
- package/dist/controller/canonicalComposition.js +166 -38
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +52 -13
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalSession.d.ts +24 -6
- package/dist/controller/canonicalSession.js +259 -111
- package/dist/controller/canonicalStoryEditor.d.ts +5 -3
- package/dist/controller/canonicalStoryEditor.js +7 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +5 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +8 -7
- package/dist/controller/hiddenEditorApi.d.ts +12 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +216 -34
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +8 -7
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphPropertySource.js +2 -1
- package/dist/docx/parser.js +2 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +745 -229
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +32 -3
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +32 -13
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +5 -4
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +39 -30
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/markUtils.js +3 -1
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +7 -5
- package/dist/types/canonicalCapabilities.d.ts +215 -0
- package/dist/types/canonicalCapabilities.js +212 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/package.json +4 -4
package/dist/ai-edits/apply.js
CHANGED
|
@@ -17,7 +17,7 @@ import { directParagraphAlignment } from "../prosemirror/paragraphAlignment.js";
|
|
|
17
17
|
import { styleResolvedParagraphFormatting } from "../prosemirror/paragraphFormattingProvenance.js";
|
|
18
18
|
import { directParagraphIndentation, paragraphIndentationAttrPatch, paragraphIndentationEqual, paragraphIndentationFromFormatting, withDirectParagraphIndentation } from "../prosemirror/paragraphIndentation.js";
|
|
19
19
|
import { joinAtParagraphMark } from "../prosemirror/paragraphMarkJoin.js";
|
|
20
|
-
import { carryParagraphProperties, paragraphLeftAfter, propertiesSetInBatch, recordReplacedParagraphProperties } from "../prosemirror/paragraphPropertyCarry.js";
|
|
20
|
+
import { carriedParagraphProperties, carryParagraphProperties, paragraphLeftAfter, propertiesSetInBatch, recordReplacedParagraphProperties } from "../prosemirror/paragraphPropertyCarry.js";
|
|
21
21
|
import { directParagraphSpacing, paragraphSpacingAttrPatch, paragraphSpacingEqual, paragraphSpacingFromFormatting, withDirectParagraphSpacing } from "../prosemirror/paragraphSpacing.js";
|
|
22
22
|
import { getDocumentNumbering, getDocumentNumberingInstanceIds } from "../prosemirror/plugins/documentNumbering.js";
|
|
23
23
|
import { getDocumentStyleDefinitions, getDocumentStyleResolver } from "../prosemirror/plugins/documentStyleState.js";
|
|
@@ -33,6 +33,7 @@ import { listAttrsFromNumbering, listLevelAttrPatch } from "../prosemirror/style
|
|
|
33
33
|
import { removeRowsWithoutCellsAfterBatch } from "../prosemirror/tableGridMutation.js";
|
|
34
34
|
import { isZeroWidthAnchor } from "../prosemirror/zeroWidthAnchors.js";
|
|
35
35
|
import { getFolioParaIdFromBlockId } from "../types/block-id.js";
|
|
36
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
36
37
|
import { BatchClaims } from "./batch-claims.js";
|
|
37
38
|
import { stripBlockIdentityAttrs } from "./block-identity.js";
|
|
38
39
|
import { describeCharacterSplit } from "./character-boundaries.js";
|
|
@@ -436,6 +437,10 @@ const preserveRunFormattingAcrossTrackedStyleChange = ({ allocateRevisionInfo, n
|
|
|
436
437
|
revisionIds
|
|
437
438
|
};
|
|
438
439
|
};
|
|
440
|
+
const appendParagraphPropertyChange = (existing, change) => {
|
|
441
|
+
if (change.info.provenance !== "suggested" && hasSerializableParagraphPropertyChange(existing)) panic("A paragraph-property write must resolve its occupied revision slot first");
|
|
442
|
+
return [...existing ?? [], change];
|
|
443
|
+
};
|
|
439
444
|
/**
|
|
440
445
|
* Apply one paragraph-property patch to a live node. A tracked patch stores
|
|
441
446
|
* the complete previous pPr: a partial snapshot cannot distinguish a property
|
|
@@ -482,7 +487,7 @@ const applyBlockParagraphProperties = ({ tr, position, node, properties, styleRe
|
|
|
482
487
|
const nextAttrs = {
|
|
483
488
|
...node.attrs,
|
|
484
489
|
...patch,
|
|
485
|
-
...change ? { _propertyChanges:
|
|
490
|
+
...change ? { _propertyChanges: appendParagraphPropertyChange(existing, change) } : {}
|
|
486
491
|
};
|
|
487
492
|
const bridgeResult = preserveRunFormatting && revisionInfo ? preserveRunFormattingAcrossTrackedStyleChange({
|
|
488
493
|
allocateRevisionInfo: revisionInfo,
|
|
@@ -560,7 +565,7 @@ const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) =>
|
|
|
560
565
|
const nextAttrs = {
|
|
561
566
|
...block.attrs,
|
|
562
567
|
...patch,
|
|
563
|
-
...change ? { _propertyChanges:
|
|
568
|
+
...change ? { _propertyChanges: appendParagraphPropertyChange(existing, change) } : {}
|
|
564
569
|
};
|
|
565
570
|
const bridgeResult = preserveRunFormatting && revisionInfo ? preserveRunFormattingAcrossTrackedStyleChange({
|
|
566
571
|
allocateRevisionInfo: revisionInfo,
|
|
@@ -1280,6 +1285,11 @@ const isInsertedPPrMark = (value) => typeof value === "object" && value !== null
|
|
|
1280
1285
|
const isSuggestedParagraphInsert = (paragraph) => typeof paragraph.attrs["_suggestedInsert"] === "object" && paragraph.attrs["_suggestedInsert"] !== null;
|
|
1281
1286
|
/** A paragraph mark that is a pending deletion, or a relocation's source. */
|
|
1282
1287
|
const isDeletedPPrMark = (value) => typeof value === "object" && value !== null && "kind" in value && (value.kind === "del" || value.kind === "moveFrom");
|
|
1288
|
+
const pendingParagraphMarkPropertyRefusal = {
|
|
1289
|
+
reason: "pendingParagraphMarkDeletion",
|
|
1290
|
+
canonicalRefusal: { gap: CANONICAL_GAP.publicPendingParagraphMarkProperties },
|
|
1291
|
+
message: "Resolve the pending paragraph mark deletion before editing its properties, or provide mergedParagraphProperties on the merge operation for atomic intent."
|
|
1292
|
+
};
|
|
1283
1293
|
const hasRevisionMarker = (value) => typeof value === "object" && value !== null && "revisionId" in value;
|
|
1284
1294
|
const isDeletedCell = (cell) => {
|
|
1285
1295
|
const marker = cell.attrs["cellMarker"];
|
|
@@ -1501,6 +1511,10 @@ const crossesBatchDeletion = ({ doc, from, to, batchRevisionIds }) => {
|
|
|
1501
1511
|
}
|
|
1502
1512
|
return false;
|
|
1503
1513
|
};
|
|
1514
|
+
const canRetractFinalBreak = ({ predecessor, target }) => {
|
|
1515
|
+
if (target.type !== predecessor.type) return false;
|
|
1516
|
+
return !(JSON.stringify(paragraphPropertiesBeforePendingChanges(target)) !== JSON.stringify(paragraphPropertiesSnapshot(predecessor)) && hasSerializableParagraphPropertyChange(expectParagraphAttrs(predecessor)._propertyChanges));
|
|
1517
|
+
};
|
|
1504
1518
|
/** Pending retirements, read after the merge has mapped any inserted separator. */
|
|
1505
1519
|
const pendingRemovedFinalBreakPositions = (tr, deletions) => {
|
|
1506
1520
|
const positions = /* @__PURE__ */ new Set();
|
|
@@ -1512,6 +1526,92 @@ const pendingRemovedFinalBreakPositions = (tr, deletions) => {
|
|
|
1512
1526
|
}
|
|
1513
1527
|
return positions;
|
|
1514
1528
|
};
|
|
1529
|
+
/** An unoccupied final carrier takes admissible writes from the finished batch. */
|
|
1530
|
+
const finalParagraphCarry = ({ tr, at, target, predecessor, batchRevisionIds, styleResolver, numbering }) => {
|
|
1531
|
+
const { node: previous, position } = predecessor;
|
|
1532
|
+
const beforeBatch = hasSerializableParagraphPropertyChange(expectParagraphAttrs(target)._propertyChanges) ? resolveParagraphChangeAttrs({
|
|
1533
|
+
node: previous,
|
|
1534
|
+
mode: "reject",
|
|
1535
|
+
boundaryCovered: true,
|
|
1536
|
+
revisionSet: batchRevisionIds,
|
|
1537
|
+
styleResolver,
|
|
1538
|
+
numbering
|
|
1539
|
+
}) : null;
|
|
1540
|
+
return {
|
|
1541
|
+
source: beforeBatch ? previous.type.create(beforeBatch, previous.content, previous.marks) : previous,
|
|
1542
|
+
keep: crossesBatchDeletion({
|
|
1543
|
+
doc: tr.doc,
|
|
1544
|
+
from: position + previous.nodeSize,
|
|
1545
|
+
to: at,
|
|
1546
|
+
batchRevisionIds
|
|
1547
|
+
}) ? /* @__PURE__ */ new Set() : propertiesSetInBatch(target, batchRevisionIds)
|
|
1548
|
+
};
|
|
1549
|
+
};
|
|
1550
|
+
/** Deferred retirement still owns a slot before a later explicit formatting merge. */
|
|
1551
|
+
const hasDeferredParagraphPropertyWrite = ({ tr, deletions, targets, mergedPropertyTargets, batchRevisionIds, styleResolver, numbering }) => {
|
|
1552
|
+
for (const deletion of deletions) {
|
|
1553
|
+
const at = tr.mapping.slice(deletion.mappedFrom).map(deletion.position);
|
|
1554
|
+
const target = tr.doc.nodeAt(at);
|
|
1555
|
+
if (!target) continue;
|
|
1556
|
+
const predecessor = finalParagraphPredecessor(tr.doc, at);
|
|
1557
|
+
if (!predecessor) continue;
|
|
1558
|
+
const mark = predecessor.node.attrs["pPrMark"];
|
|
1559
|
+
if (mark == null && mergedPropertyTargets.some(({ position, mappedFrom }) => {
|
|
1560
|
+
const mapped = tr.mapping.slice(mappedFrom).mapResult(position);
|
|
1561
|
+
return !mapped.deleted && mapped.pos === at;
|
|
1562
|
+
})) continue;
|
|
1563
|
+
const writeTarget = mark == null ? target : tr.doc.nodeAt(predecessor.position + predecessor.node.nodeSize);
|
|
1564
|
+
if (!writeTarget || !targets.includes(writeTarget)) continue;
|
|
1565
|
+
if (mark != null && !(isInsertedPPrMark(mark) && canRetractFinalBreak({
|
|
1566
|
+
predecessor: predecessor.node,
|
|
1567
|
+
target: writeTarget
|
|
1568
|
+
}))) continue;
|
|
1569
|
+
const transfer = mark == null ? finalParagraphCarry({
|
|
1570
|
+
tr,
|
|
1571
|
+
at,
|
|
1572
|
+
target,
|
|
1573
|
+
predecessor,
|
|
1574
|
+
batchRevisionIds,
|
|
1575
|
+
styleResolver,
|
|
1576
|
+
numbering
|
|
1577
|
+
}) : {
|
|
1578
|
+
source: predecessor.node,
|
|
1579
|
+
keep: propertiesSetInBatch(writeTarget, batchRevisionIds)
|
|
1580
|
+
};
|
|
1581
|
+
if (JSON.stringify(paragraphPropertiesSnapshot(writeTarget)) !== JSON.stringify(carriedParagraphProperties({
|
|
1582
|
+
...transfer,
|
|
1583
|
+
target: writeTarget
|
|
1584
|
+
}))) return true;
|
|
1585
|
+
}
|
|
1586
|
+
return false;
|
|
1587
|
+
};
|
|
1588
|
+
/** The paragraph a merge leaves owns its properties, even across pending deleted breaks. */
|
|
1589
|
+
const paragraphPropertyRevisionTargets = ({ item, tr, deletedFinalParagraphs }) => {
|
|
1590
|
+
const position = tr.mapping.map(item.blockFrom, item.operation.type === "replaceBlock" ? -1 : 1);
|
|
1591
|
+
const source = tr.doc.nodeAt(position) ?? item.blockNode;
|
|
1592
|
+
const targets = source.type.name === "paragraph" ? [source] : [];
|
|
1593
|
+
if (item.operation.type !== "mergeBlockWithNext") return targets;
|
|
1594
|
+
const removedBreakPositions = pendingRemovedFinalBreakPositions(tr, deletedFinalParagraphs);
|
|
1595
|
+
for (const deletion of deletedFinalParagraphs) {
|
|
1596
|
+
const at = tr.mapping.slice(deletion.mappedFrom).map(deletion.position);
|
|
1597
|
+
const predecessor = finalParagraphPredecessor(tr.doc, at);
|
|
1598
|
+
if (!predecessor || !isInsertedPPrMark(predecessor.node.attrs["pPrMark"])) continue;
|
|
1599
|
+
const target = tr.doc.nodeAt(predecessor.position + predecessor.node.nodeSize);
|
|
1600
|
+
if (!target) continue;
|
|
1601
|
+
if (canRetractFinalBreak({
|
|
1602
|
+
predecessor: predecessor.node,
|
|
1603
|
+
target
|
|
1604
|
+
})) removedBreakPositions.add(predecessor.position);
|
|
1605
|
+
}
|
|
1606
|
+
const survivorPosition = paragraphLeftAfter({
|
|
1607
|
+
doc: tr.doc,
|
|
1608
|
+
paragraphPos: position,
|
|
1609
|
+
removedBreakPositions
|
|
1610
|
+
});
|
|
1611
|
+
const survivor = survivorPosition === null ? null : tr.doc.nodeAt(survivorPosition);
|
|
1612
|
+
if (survivor?.type.name === "paragraph") targets.push(survivor);
|
|
1613
|
+
return targets;
|
|
1614
|
+
};
|
|
1515
1615
|
/**
|
|
1516
1616
|
* Finish the tracked deletion of every paragraph a container ends with.
|
|
1517
1617
|
*
|
|
@@ -1562,21 +1662,21 @@ const withRetiredFinalParagraphs = ({ tr, deletions, mergedPropertyTargets, appl
|
|
|
1562
1662
|
...revisionExtras
|
|
1563
1663
|
}
|
|
1564
1664
|
});
|
|
1565
|
-
const beforeBatch = resolveParagraphChangeAttrs({
|
|
1566
|
-
node: previous,
|
|
1567
|
-
mode: "reject",
|
|
1568
|
-
boundaryCovered: true,
|
|
1569
|
-
revisionSet: batchRevisionIds,
|
|
1570
|
-
styleResolver,
|
|
1571
|
-
numbering
|
|
1572
|
-
});
|
|
1573
1665
|
if (!mergedPropertyTargets.some(({ position: target, mappedFrom }) => {
|
|
1574
1666
|
const mapped = tr.mapping.slice(mappedFrom).mapResult(target);
|
|
1575
1667
|
return !mapped.deleted && mapped.pos === at;
|
|
1576
1668
|
})) carryParagraphProperties({
|
|
1577
1669
|
tr,
|
|
1578
1670
|
position: at,
|
|
1579
|
-
|
|
1671
|
+
...finalParagraphCarry({
|
|
1672
|
+
tr,
|
|
1673
|
+
at,
|
|
1674
|
+
target: emptied,
|
|
1675
|
+
predecessor,
|
|
1676
|
+
batchRevisionIds,
|
|
1677
|
+
styleResolver,
|
|
1678
|
+
numbering
|
|
1679
|
+
}),
|
|
1580
1680
|
styleResolver,
|
|
1581
1681
|
numbering,
|
|
1582
1682
|
revision: {
|
|
@@ -1584,13 +1684,7 @@ const withRetiredFinalParagraphs = ({ tr, deletions, mergedPropertyTargets, appl
|
|
|
1584
1684
|
author,
|
|
1585
1685
|
date,
|
|
1586
1686
|
...revisionExtras
|
|
1587
|
-
}
|
|
1588
|
-
keep: crossesBatchDeletion({
|
|
1589
|
-
doc: tr.doc,
|
|
1590
|
-
from: position + previous.nodeSize,
|
|
1591
|
-
to: at,
|
|
1592
|
-
batchRevisionIds
|
|
1593
|
-
}) ? /* @__PURE__ */ new Set() : propertiesSetInBatch(emptied, batchRevisionIds)
|
|
1687
|
+
}
|
|
1594
1688
|
});
|
|
1595
1689
|
resolvedOperationIds.add(operationId);
|
|
1596
1690
|
addedRevisions.push({
|
|
@@ -1601,11 +1695,10 @@ const withRetiredFinalParagraphs = ({ tr, deletions, mergedPropertyTargets, appl
|
|
|
1601
1695
|
}
|
|
1602
1696
|
if (isInsertedPPrMark(mark)) {
|
|
1603
1697
|
const following = tr.doc.nodeAt(position + previous.nodeSize);
|
|
1604
|
-
if (following
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
if (formattingChanges && hasSerializableParagraphPropertyChange(existing)) continue;
|
|
1698
|
+
if (!following || !canRetractFinalBreak({
|
|
1699
|
+
predecessor: previous,
|
|
1700
|
+
target: following
|
|
1701
|
+
})) continue;
|
|
1609
1702
|
joinAtParagraphMark({
|
|
1610
1703
|
tr,
|
|
1611
1704
|
paragraphPos: position,
|
|
@@ -2148,6 +2241,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations: reques
|
|
|
2148
2241
|
skipped.push({
|
|
2149
2242
|
id: operation.id,
|
|
2150
2243
|
reason: resolution.reason,
|
|
2244
|
+
...resolution.canonicalRefusal !== void 0 && { canonicalRefusal: resolution.canonicalRefusal },
|
|
2151
2245
|
...resolution.message !== void 0 && { message: resolution.message }
|
|
2152
2246
|
});
|
|
2153
2247
|
continue;
|
|
@@ -2344,9 +2438,22 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations: reques
|
|
|
2344
2438
|
if (!item) panic("The operation execution index exceeded the resolved plan", { executionIndex });
|
|
2345
2439
|
continueSharedRevisionIds();
|
|
2346
2440
|
if (mode === "tracked-changes" && writesParagraphPropertyChange(item)) {
|
|
2347
|
-
const
|
|
2348
|
-
const
|
|
2349
|
-
|
|
2441
|
+
const appliedIds = new Set(applied.map(({ id }) => id));
|
|
2442
|
+
const pendingDeletions = deletedFinalParagraphs.filter(({ operationId }) => appliedIds.has(operationId));
|
|
2443
|
+
const targets = paragraphPropertyRevisionTargets({
|
|
2444
|
+
item,
|
|
2445
|
+
tr,
|
|
2446
|
+
deletedFinalParagraphs: pendingDeletions
|
|
2447
|
+
});
|
|
2448
|
+
if (targets.some((target) => hasSerializableParagraphPropertyChange(expectParagraphAttrs(target)._propertyChanges)) || item.operation.type === "mergeBlockWithNext" && hasDeferredParagraphPropertyWrite({
|
|
2449
|
+
tr,
|
|
2450
|
+
deletions: pendingDeletions,
|
|
2451
|
+
targets,
|
|
2452
|
+
mergedPropertyTargets,
|
|
2453
|
+
batchRevisionIds: new Set(applied.flatMap(({ revisionIds }) => revisionIds ?? [])),
|
|
2454
|
+
styleResolver,
|
|
2455
|
+
numbering
|
|
2456
|
+
})) {
|
|
2350
2457
|
skipped.push({
|
|
2351
2458
|
id: item.operation.id,
|
|
2352
2459
|
reason: "pendingParagraphPropertyChange"
|
|
@@ -2580,6 +2687,13 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations: reques
|
|
|
2580
2687
|
case "replaceBlock": {
|
|
2581
2688
|
if (!isResolvedReplaceBlockOperation(item)) panic("Resolved replaceBlock operation lost its impact discriminator");
|
|
2582
2689
|
const { changesStyle, changesText } = REPLACE_BLOCK_IMPACT[item.replaceBlockImpact];
|
|
2690
|
+
if (changesStyle && isDeletedPPrMark(tr.doc.nodeAt(tr.mapping.map(item.blockFrom, -1))?.attrs["pPrMark"])) {
|
|
2691
|
+
skipped.push({
|
|
2692
|
+
id: item.operation.id,
|
|
2693
|
+
...pendingParagraphMarkPropertyRefusal
|
|
2694
|
+
});
|
|
2695
|
+
continue;
|
|
2696
|
+
}
|
|
2583
2697
|
const revisionIdDelete = operationRevisionSeed;
|
|
2584
2698
|
const revisionIdInsert = changesText ? operationRevisionSeed + 1 : operationRevisionSeed;
|
|
2585
2699
|
const revisionIdBackgroundSeed = changesText ? operationRevisionSeed + 2 : operationRevisionSeed;
|
|
@@ -3312,6 +3426,13 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations: reques
|
|
|
3312
3426
|
continue;
|
|
3313
3427
|
}
|
|
3314
3428
|
const blockPosition = mapped.pos;
|
|
3429
|
+
if (isDeletedPPrMark(liveBlock.attrs["pPrMark"])) {
|
|
3430
|
+
skipped.push({
|
|
3431
|
+
id: item.operation.id,
|
|
3432
|
+
...pendingParagraphMarkPropertyRefusal
|
|
3433
|
+
});
|
|
3434
|
+
continue;
|
|
3435
|
+
}
|
|
3315
3436
|
const appliedProperties = applyBlockParagraphProperties({
|
|
3316
3437
|
tr,
|
|
3317
3438
|
position: blockPosition,
|
|
@@ -4889,17 +5010,23 @@ const resolveOperationTarget = ({ snapshot, operation, liveBlocks, liveBlocksByP
|
|
|
4889
5010
|
}
|
|
4890
5011
|
};
|
|
4891
5012
|
}
|
|
4892
|
-
if (operation.type === "setBlockParagraphProperties")
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
5013
|
+
if (operation.type === "setBlockParagraphProperties") {
|
|
5014
|
+
if (isDeletedPPrMark(blockNode.attrs["pPrMark"])) return {
|
|
5015
|
+
type: "skip",
|
|
5016
|
+
...pendingParagraphMarkPropertyRefusal
|
|
5017
|
+
};
|
|
5018
|
+
return {
|
|
5019
|
+
type: "resolved",
|
|
5020
|
+
operation: {
|
|
5021
|
+
operation,
|
|
5022
|
+
from: blockFrom,
|
|
5023
|
+
to: blockTo,
|
|
5024
|
+
blockFrom,
|
|
5025
|
+
blockTo,
|
|
5026
|
+
blockNode
|
|
5027
|
+
}
|
|
5028
|
+
};
|
|
5029
|
+
}
|
|
4903
5030
|
if (operation.type === "splitBlock") {
|
|
4904
5031
|
const separator = operation.separator ?? "";
|
|
4905
5032
|
const startOffset = operation.offset;
|
|
@@ -4965,6 +5092,10 @@ const resolveOperationTarget = ({ snapshot, operation, liveBlocks, liveBlocksByP
|
|
|
4965
5092
|
if (operation.type === "deleteBlock" || operation.type === "replaceBlock") {
|
|
4966
5093
|
const replaceChangesText = operation.type === "replaceBlock" && operation.text !== currentText;
|
|
4967
5094
|
const replaceChangesStyle = operation.type === "replaceBlock" && operation.styleId !== void 0 && operation.styleId !== (expectParagraphAttrs(blockNode).styleId ?? null);
|
|
5095
|
+
if (replaceChangesStyle && isDeletedPPrMark(blockNode.attrs["pPrMark"])) return {
|
|
5096
|
+
type: "skip",
|
|
5097
|
+
...pendingParagraphMarkPropertyRefusal
|
|
5098
|
+
};
|
|
4968
5099
|
if (replaceChangesText && cleanBlock.structuralBoundaries.some((boundary) => boundary.type !== "field" && boundary.type !== "noteReference")) return {
|
|
4969
5100
|
type: "skip",
|
|
4970
5101
|
reason: "unsupportedBlock"
|
|
@@ -5,8 +5,7 @@ import { importReferencedStyleDefinitions } from "../compare/style-resources.js"
|
|
|
5
5
|
import { applyFolioDocumentOperations } from "../document-operations.js";
|
|
6
6
|
import { applyReplyThreadMarkers } from "../docx/commentReplyMarkers.js";
|
|
7
7
|
import { rebindDrawingImageRelationship } from "../docx/drawingRelationships.js";
|
|
8
|
-
import {
|
|
9
|
-
import { getHeaderFooterText } from "../docx/headerFooterParser.js";
|
|
8
|
+
import { isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
|
|
10
9
|
import { createNumberingIdAllocator } from "../docx/numberingIds.js";
|
|
11
10
|
import { getCachedNumberingMap } from "../docx/numberingParser.js";
|
|
12
11
|
import { recreateProseNodeWithParagraphPropertySource, transferProseParagraphPropertySource } from "../docx/paragraphPropertySource.js";
|
|
@@ -15,6 +14,7 @@ import { createReply } from "../docx/replyToComment.js";
|
|
|
15
14
|
import { repackDocx } from "../docx/rezip.js";
|
|
16
15
|
import { sectionReferenceHistory } from "../docx/sectionReferenceHistory.js";
|
|
17
16
|
import { attemptSelectiveSave } from "../docx/selectiveSave.js";
|
|
17
|
+
import { getEndnoteText, getFootnoteText, getHeaderFooterText } from "../docx/storyPlainText.js";
|
|
18
18
|
import { pluginsForHeadlessRevisionResolution } from "../internal/headlessRevisionResolutionGuard.js";
|
|
19
19
|
import { withTrackedSectionEndpointRemoval } from "../internal/sectionEndpointResolution.js";
|
|
20
20
|
import { captureSectionReferenceInventory, resolvedSectionReferenceLosses, withSectionReferenceResolution } from "../internal/sectionReferenceResolution.js";
|
package/dist/ai-edits/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { CanonicalGap } from "../types/canonicalCapabilities.js";
|
|
2
3
|
import { FolioContentBlock, FolioContentInlineBooleanProperty, FolioContentInlineFormatting, FolioContentInlineFormattingPatch, FolioContentListReference, FolioContentParagraphIndentation, FolioContentParagraphKind, FolioContentParagraphSpacing, FolioContentRun, FolioContentSnapshot, FolioContentTableLocation } from "../compare/content-types.js";
|
|
3
4
|
import { ListKind } from "../docx/listNumberingInstances.js";
|
|
4
5
|
//#region src/ai-edits/types.d.ts
|
|
@@ -656,7 +657,9 @@ type FolioAIEditSkipReason = "missingBlock" | "changedBlock" | "ambiguousFind" |
|
|
|
656
657
|
* deletion is accepted. Reject that deletion first, or insert a new block
|
|
657
658
|
* next to it.
|
|
658
659
|
*/
|
|
659
|
-
"pendingDeletion"
|
|
660
|
+
"pendingDeletion" |
|
|
661
|
+
/** Resolve the removed paragraph mark before editing its properties separately. */
|
|
662
|
+
"pendingParagraphMarkDeletion";
|
|
660
663
|
type FolioAIEditAppliedOperation = {
|
|
661
664
|
id: string;
|
|
662
665
|
commentId?: number;
|
|
@@ -689,6 +692,9 @@ type FolioAIEditAppliedOperation = {
|
|
|
689
692
|
type FolioAIEditSkippedOperation = {
|
|
690
693
|
id: string;
|
|
691
694
|
reason: FolioAIEditSkipReason;
|
|
695
|
+
canonicalRefusal?: {
|
|
696
|
+
gap: CanonicalGap;
|
|
697
|
+
};
|
|
692
698
|
/**
|
|
693
699
|
* What exactly was wrong when the reason alone does not say: the values a
|
|
694
700
|
* `payloadDoesNotFit` skip could not place, the earlier operation an
|
package/dist/compare/compare.js
CHANGED
|
@@ -486,6 +486,7 @@ const COMPARE_SKIP_DISPOSITION = {
|
|
|
486
486
|
staleRange: "fatal",
|
|
487
487
|
emptyOperation: "unwritable",
|
|
488
488
|
pendingParagraphPropertyChange: "unwritable",
|
|
489
|
+
pendingParagraphMarkDeletion: "unwritable",
|
|
489
490
|
pendingRunPropertyChange: "unwritable",
|
|
490
491
|
noopOperation: "unwritable",
|
|
491
492
|
documentVersionMismatch: "fatal",
|
|
@@ -1,21 +1,4 @@
|
|
|
1
1
|
//#region src/compare/reproducible-package.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* The last two clocks in the compare path are outside the document body.
|
|
4
|
-
*
|
|
5
|
-
* Every part the serializer rewrites is stored with JSZip's default entry
|
|
6
|
-
* date, which is `new Date()`. The XML is identical between two runs, but the
|
|
7
|
-
* DOS timestamp fields in the local headers are not, and they only agree when
|
|
8
|
-
* both runs land in the same two-second bucket — so the packages match most of
|
|
9
|
-
* the time and differ occasionally, which is worse than differing always.
|
|
10
|
-
*
|
|
11
|
-
* The save also stamps `dcterms:modified` in `docProps/core.xml` from the wall
|
|
12
|
-
* clock, which is the same failure one part deeper: two runs over identical
|
|
13
|
-
* inputs differ in that part alone.
|
|
14
|
-
*
|
|
15
|
-
* Restamping both from the comparison's own timestamp removes them. It also
|
|
16
|
-
* states the truth about the package: a generated redline is dated by the
|
|
17
|
-
* comparison that produced it, not by the second it happened to be written.
|
|
18
|
-
*/
|
|
19
2
|
declare const withFixedPackageDates: (buffer: ArrayBuffer, date: Date) => Promise<ArrayBuffer>;
|
|
20
3
|
//#endregion
|
|
21
4
|
export { withFixedPackageDates };
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
+
import { writeZipPart } from "@stll/docx-core/zip";
|
|
1
2
|
import JSZip from "jszip";
|
|
2
3
|
//#region src/compare/reproducible-package.ts
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* date, which is `new Date()`. The XML is identical between two runs, but the
|
|
8
|
-
* DOS timestamp fields in the local headers are not, and they only agree when
|
|
9
|
-
* both runs land in the same two-second bucket — so the packages match most of
|
|
10
|
-
* the time and differ occasionally, which is worse than differing always.
|
|
11
|
-
*
|
|
12
|
-
* The save also stamps `dcterms:modified` in `docProps/core.xml` from the wall
|
|
13
|
-
* clock, which is the same failure one part deeper: two runs over identical
|
|
14
|
-
* inputs differ in that part alone.
|
|
15
|
-
*
|
|
16
|
-
* Restamping both from the comparison's own timestamp removes them. It also
|
|
17
|
-
* states the truth about the package: a generated redline is dated by the
|
|
18
|
-
* comparison that produced it, not by the second it happened to be written.
|
|
5
|
+
* Date comparison output from the comparison's timestamp. Imported entries
|
|
6
|
+
* retain source dates, and saves can stamp `dcterms:modified` from the wall
|
|
7
|
+
* clock; restamping both makes repeated comparisons reproducible.
|
|
19
8
|
*/
|
|
20
9
|
/** JSZip deflate level `repackDocx` writes DOCX parts at. */
|
|
21
10
|
const DOCX_COMPRESSION_LEVEL = 6;
|
|
@@ -30,9 +19,14 @@ const withFixedModifiedDate = (corePropsXml, date) => corePropsXml.replace(MODIF
|
|
|
30
19
|
const withFixedPackageDates = async (buffer, date) => {
|
|
31
20
|
const zip = await JSZip.loadAsync(buffer);
|
|
32
21
|
const coreProps = zip.file(CORE_PROPERTIES_PATH);
|
|
33
|
-
if (coreProps)
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
if (coreProps) writeZipPart({
|
|
23
|
+
zip,
|
|
24
|
+
path: CORE_PROPERTIES_PATH,
|
|
25
|
+
data: withFixedModifiedDate(await coreProps.async("text"), date),
|
|
26
|
+
options: {
|
|
27
|
+
compression: "DEFLATE",
|
|
28
|
+
compressionOptions: { level: DOCX_COMPRESSION_LEVEL }
|
|
29
|
+
}
|
|
36
30
|
});
|
|
37
31
|
zip.forEach((_path, file) => {
|
|
38
32
|
file.date = date;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { CanonicalCommit, CanonicalSession, CanonicalSessionError } from "./canonicalSession.js";
|
|
3
|
+
import { Slice } from "prosemirror-model";
|
|
4
|
+
import { EditorState } from "prosemirror-state";
|
|
5
|
+
import { Result } from "better-result";
|
|
6
|
+
//#region src/controller/canonicalClipboard.d.ts
|
|
7
|
+
/** Clipboard slices are input payloads; their paragraph identities and private captures are not owners. */
|
|
8
|
+
type PrepareCanonicalPasteOptions = {
|
|
9
|
+
session: CanonicalSession;
|
|
10
|
+
state: EditorState;
|
|
11
|
+
slice: Slice;
|
|
12
|
+
plain?: boolean;
|
|
13
|
+
moveTarget?: number;
|
|
14
|
+
pasteTarget?: number;
|
|
15
|
+
sourceDocument?: document_d_exports.Document;
|
|
16
|
+
moveSource?: {
|
|
17
|
+
from: number;
|
|
18
|
+
to: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
declare const prepareCanonicalPaste: ({ session, state, slice, plain, moveTarget, pasteTarget, sourceDocument, moveSource }: PrepareCanonicalPasteOptions) => Result<CanonicalCommit, CanonicalSessionError>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { prepareCanonicalPaste };
|