@stll/folio-core 0.47.4 → 0.47.6

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.
Files changed (50) hide show
  1. package/dist/compare/inline-atoms.js +218 -31
  2. package/dist/compare/section-boundary-properties.js +1 -0
  3. package/dist/content-controls/mutateContentControls.js +1 -3
  4. package/dist/controller/headerFooterEditorManager.d.ts +2 -1
  5. package/dist/controller/headerFooterEditorManager.js +2 -1
  6. package/dist/controller/noteEditorManager.d.ts +2 -1
  7. package/dist/controller/noteEditorManager.js +2 -1
  8. package/dist/docx/commentRangeIntegrity.js +7 -0
  9. package/dist/docx/documentParser.js +55 -3
  10. package/dist/docx/inlineWrapperContent.d.ts +18 -16
  11. package/dist/docx/inlineWrapperContent.js +18 -16
  12. package/dist/docx/normalizeBaseDirection.js +4 -0
  13. package/dist/docx/rezip.js +1 -0
  14. package/dist/docx/selectiveSave.js +11 -2
  15. package/dist/docx/serializer/documentSerializer.js +16 -1
  16. package/dist/docx/serializer/paragraphSerializer.js +8 -0
  17. package/dist/docx/serializer/tableSerializer.js +5 -2
  18. package/dist/docx/server/createBilingualDocument.js +23 -14
  19. package/dist/docx/tableParser.js +101 -75
  20. package/dist/markdown/renderRuns.js +4 -0
  21. package/dist/markdown/renderTable.js +46 -12
  22. package/dist/prosemirror/attrs/index.d.ts +3 -2
  23. package/dist/prosemirror/attrs/index.js +85 -4
  24. package/dist/prosemirror/commands/comments.js +61 -3
  25. package/dist/prosemirror/commentReferenceAttrs.js +2 -2
  26. package/dist/prosemirror/commentReferenceIntegrity.d.ts +7 -3
  27. package/dist/prosemirror/commentReferenceIntegrity.js +9 -1
  28. package/dist/prosemirror/conversion/fromProseDoc.js +177 -51
  29. package/dist/prosemirror/conversion/toProseDoc.js +108 -55
  30. package/dist/prosemirror/extensions/markRegistry.d.ts +5 -8
  31. package/dist/prosemirror/extensions/markRegistry.js +5 -8
  32. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +13 -6
  33. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +24 -6
  34. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +2 -1
  35. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +32 -7
  36. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +9 -5
  37. package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -2
  38. package/dist/prosemirror/runIdentity.d.ts +5 -5
  39. package/dist/prosemirror/runIdentity.js +5 -5
  40. package/dist/prosemirror/schema/index.d.ts +2 -2
  41. package/dist/prosemirror/schema/marks.d.ts +28 -2
  42. package/dist/prosemirror/schema/nodes.d.ts +6 -4
  43. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
  44. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
  45. package/dist/prosemirror/utils/extractTrackedChanges.js +21 -6
  46. package/dist/prosemirror/validation.js +48 -7
  47. package/dist/types/content.d.ts +2 -2
  48. package/dist/types/index.d.ts +3 -1
  49. package/dist/utils/mergeDocumentContent.js +1 -7
  50. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { CharacterSpacingAttrs, CharacterStyleAttrs, CommentAttrs, EmphasisMarkAttrs, FontFamilyAttrs, FontSizeAttrs, FootnoteRefAttrs, HighlightAttrs, HyperlinkAttrs, InlineWrapperAttrs, InlineWrapperLayer, LanguageAttrs, RunFormattingOverrideAttrs, RunIdentityMarkAttrs, RunPropertyChangeMarkAttrs, RunShadingAttrs, StrikeAttrs, TextColorAttrs, TextEffectAttrs, TrackedChangeMarkAttrs, UnderlineAttrs } from "../schema/marks.js";
1
+ import { CharacterSpacingAttrs, CharacterStyleAttrs, CommentAttrs, EmphasisMarkAttrs, FontFamilyAttrs, FontSizeAttrs, FootnoteRefAttrs, HighlightAttrs, HyperlinkAttrs, InlineWrapperAttrs, InlineWrapperLayer, LanguageAttrs, RunFormattingOverrideAttrs, RunIdentityMarkAttrs, RunPropertyChangeMarkAttrs, RunShadingAttrs, StrikeAttrs, TextColorAttrs, TextEffectAttrs, TrackedChangeMarkAttrs, TrackedRevisionAncestor, UnderlineAttrs } from "../schema/marks.js";
2
2
  import { BlockSdtAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, MathAttrs, PageBreakRunAttrs, ParagraphAttrs, PreservedBlockAttrs, PreservedXmlAttrs, SdtAttrs, ShapeAttrs, SymbolAttrs, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAttrs } from "../schema/nodes.js";
3
3
  import "../schema/index.js";
4
4
  import { Mark, Node } from "prosemirror-model";
@@ -76,6 +76,7 @@ declare const readFootnoteRefMarkAttrs: (mark: Mark) => ReadProseMirrorAttrsResu
76
76
  declare const expectFootnoteRefMarkAttrs: (mark: Mark) => FootnoteRefAttrs;
77
77
  declare const readCommentMarkAttrs: (mark: Mark) => ReadProseMirrorAttrsResult<CommentAttrs>;
78
78
  declare const expectCommentMarkAttrs: (mark: Mark) => CommentAttrs;
79
+ declare const isTrackedRevisionAncestorArray: (value: unknown) => value is readonly TrackedRevisionAncestor[];
79
80
  declare const readTrackedChangeMarkAttrs: (mark: Mark) => ReadProseMirrorAttrsResult<TrackedChangeMarkAttrs>;
80
81
  declare const expectTrackedChangeMarkAttrs: (mark: Mark) => TrackedChangeMarkAttrs;
81
82
  declare const readRunPropertyChangeMarkAttrs: (mark: Mark) => ReadProseMirrorAttrsResult<RunPropertyChangeMarkAttrs>;
@@ -118,4 +119,4 @@ declare const mergeTableRowAttrs: (node: Node, patch: NodeAttrPatch<TableRowAttr
118
119
  */
119
120
  declare const mergeTableCellAttrs: (node: Node, patch: NodeAttrPatch<TableCellAttrs>) => TableCellAttrs;
120
121
  //#endregion
121
- export { ProseMirrorAttrIssue, ReadProseMirrorAttrsResult, expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectInlineWrapperMarkAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectParagraphAttrs, expectPreservedBlockAttrs, expectPreservedXmlAttrs, expectRunFormattingOverrideMarkAttrs, expectRunIdentityMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs, mergeImageAttrs, mergeParagraphAttrs, mergeTableAttrs, mergeTableCellAttrs, mergeTableRowAttrs, readBlockSdtAttrs, readCharacterSpacingMarkAttrs, readCharacterStyleMarkAttrs, readCommentMarkAttrs, readEmphasisMarkAttrs, readFieldAttrs, readFontFamilyMarkAttrs, readFontSizeMarkAttrs, readFootnoteRefMarkAttrs, readHardBreakAttrs, readHighlightMarkAttrs, readHyperlinkMarkAttrs, readImageAttrs, readInlineWrapperMarkAttrs, readInlineWrapperStack, readLanguageMarkAttrs, readMathAttrs, readPageBreakRunAttrs, readParagraphAttrs, readPreservedBlockAttrs, readPreservedXmlAttrs, readRunFormattingOverrideMarkAttrs, readRunIdentityMarkAttrs, readRunPropertyChangeMarkAttrs, readRunShadingMarkAttrs, readSdtAttrs, readShapeAttrs, readStrikeMarkAttrs, readSymbolAttrs, readTabAttrs, readTableAttrs, readTableCellAttrs, readTableRowAttrs, readTextBoxAttrs, readTextColorMarkAttrs, readTextEffectMarkAttrs, readTrackedChangeMarkAttrs, readUnderlineMarkAttrs };
122
+ export { ProseMirrorAttrIssue, ReadProseMirrorAttrsResult, expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectInlineWrapperMarkAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectParagraphAttrs, expectPreservedBlockAttrs, expectPreservedXmlAttrs, expectRunFormattingOverrideMarkAttrs, expectRunIdentityMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs, isTrackedRevisionAncestorArray, mergeImageAttrs, mergeParagraphAttrs, mergeTableAttrs, mergeTableCellAttrs, mergeTableRowAttrs, readBlockSdtAttrs, readCharacterSpacingMarkAttrs, readCharacterStyleMarkAttrs, readCommentMarkAttrs, readEmphasisMarkAttrs, readFieldAttrs, readFontFamilyMarkAttrs, readFontSizeMarkAttrs, readFootnoteRefMarkAttrs, readHardBreakAttrs, readHighlightMarkAttrs, readHyperlinkMarkAttrs, readImageAttrs, readInlineWrapperMarkAttrs, readInlineWrapperStack, readLanguageMarkAttrs, readMathAttrs, readPageBreakRunAttrs, readParagraphAttrs, readPreservedBlockAttrs, readPreservedXmlAttrs, readRunFormattingOverrideMarkAttrs, readRunIdentityMarkAttrs, readRunPropertyChangeMarkAttrs, readRunShadingMarkAttrs, readSdtAttrs, readShapeAttrs, readStrikeMarkAttrs, readSymbolAttrs, readTabAttrs, readTableAttrs, readTableCellAttrs, readTableRowAttrs, readTextBoxAttrs, readTextColorMarkAttrs, readTextEffectMarkAttrs, readTrackedChangeMarkAttrs, readUnderlineMarkAttrs };
@@ -82,6 +82,12 @@ const NOTE_TYPES = ["footnote", "endnote"];
82
82
  const NOTE_REF_VERT_ALIGNS = ["baseline", "superscript"];
83
83
  const TEXT_BOX_DOCX_PLACEMENTS = ["standalone", "inlineWithPrevious"];
84
84
  const TRACKED_CHANGE_MOVE_KINDS = ["moveTo", "moveFrom"];
85
+ const TRACKED_REVISION_ANCESTOR_TYPES = [
86
+ "insertion",
87
+ "deletion",
88
+ "moveFrom",
89
+ "moveTo"
90
+ ];
85
91
  const TEXT_BOX_TRACKED_CHANGE_TYPES = [
86
92
  "insertion",
87
93
  "deletion",
@@ -792,6 +798,7 @@ const readCommentMarkAttrs = (mark) => {
792
798
  return attrsResult(attrs, issues);
793
799
  };
794
800
  const expectCommentMarkAttrs = (mark) => expectCachedMarkAttrs(mark, commentAttrsCache, readCommentMarkAttrs, "comment attrs");
801
+ const isTrackedRevisionAncestorArray = (value) => Array.isArray(value) && value.length > 0 && value.every((ancestor) => isRecord(ancestor) && TRACKED_REVISION_ANCESTOR_TYPES.some((type) => type === ancestor["type"]) && typeof ancestor["revisionId"] === "number" && Number.isSafeInteger(ancestor["revisionId"]) && ancestor["revisionId"] >= 0 && typeof ancestor["author"] === "string" && (ancestor["date"] === void 0 || typeof ancestor["date"] === "string") && (ancestor["utcDate"] === void 0 || typeof ancestor["utcDate"] === "string") && (ancestor["initials"] === void 0 || typeof ancestor["initials"] === "string") && typeof ancestor["outerWrapperCount"] === "number" && Number.isSafeInteger(ancestor["outerWrapperCount"]) && ancestor["outerWrapperCount"] >= 0);
795
802
  const readTrackedChangeMarkAttrs = (mark) => {
796
803
  const attrs = attrsRecord(mark.attrs);
797
804
  const issues = [];
@@ -801,6 +808,16 @@ const readTrackedChangeMarkAttrs = (mark) => {
801
808
  optionalString(attrs, "date", `${mark.type.name}.attrs.date`, issues);
802
809
  optionalString(attrs, "utcDate", `${mark.type.name}.attrs.utcDate`, issues);
803
810
  optionalString(attrs, "initials", `${mark.type.name}.attrs.initials`, issues);
811
+ const outerWrapperCount = attrs["_docxOuterWrapperCount"];
812
+ if (outerWrapperCount !== void 0 && outerWrapperCount !== null && (typeof outerWrapperCount !== "number" || !Number.isSafeInteger(outerWrapperCount) || outerWrapperCount < 0)) issues.push({
813
+ path: `${mark.type.name}.attrs._docxOuterWrapperCount`,
814
+ message: "Expected a non-negative safe integer."
815
+ });
816
+ const ancestors = attrs["_docxRevisionAncestors"];
817
+ if (ancestors !== void 0 && ancestors !== null && !isTrackedRevisionAncestorArray(ancestors)) issues.push({
818
+ path: `${mark.type.name}.attrs._docxRevisionAncestors`,
819
+ message: "Expected a non-empty array of valid revision ancestors."
820
+ });
804
821
  optionalOneOf(attrs, "moveKind", `${mark.type.name}.attrs.moveKind`, issues, TRACKED_CHANGE_MOVE_KINDS);
805
822
  optionalOneOf(attrs, "provenance", `${mark.type.name}.attrs.provenance`, issues, TRACKED_CHANGE_PROVENANCE_VALUES);
806
823
  optionalString(attrs, "suggestionId", `${mark.type.name}.attrs.suggestionId`, issues);
@@ -868,6 +885,11 @@ const taggedLayerValidator = (label) => (layer, path, issues) => {
868
885
  path: `${path}.${key}`,
869
886
  message: "Expected a string."
870
887
  });
888
+ const propertiesXml = layer["propertiesXml"];
889
+ if (typeof propertiesXml === "string" && !isSafePreservedChildXml(propertiesXml)) issues.push({
890
+ path: `${path}.propertiesXml`,
891
+ message: "Expected one bounded, well-formed XML element."
892
+ });
871
893
  for (const key of Object.keys(layer)) if (!TAGGED_LAYER_KEYS.has(key)) issues.push({
872
894
  path: `${path}.${key}`,
873
895
  message: `Unexpected ${label} wrapper property.`
@@ -894,6 +916,19 @@ const INLINE_WRAPPER_LAYER_VALIDATORS = {
894
916
  const inlineWrapperLayerValidator = (kind) => {
895
917
  return typeof kind === "string" ? INLINE_WRAPPER_LAYER_VALIDATORS[kind] : void 0;
896
918
  };
919
+ const inlineWrapperProperties = function* (layers) {
920
+ for (let index = 0; index < layers.length; index += 1) {
921
+ const layer = layers[index];
922
+ yield { xml: isRecord(layer) && typeof layer["propertiesXml"] === "string" ? layer["propertiesXml"] : "" };
923
+ }
924
+ };
925
+ const emptyHyperlinkWrapperProperties = function* (stacks) {
926
+ for (let stackIndex = 0; stackIndex < stacks.length; stackIndex += 1) {
927
+ const stack = stacks[stackIndex];
928
+ yield {};
929
+ if (Array.isArray(stack)) yield* inlineWrapperProperties(stack);
930
+ }
931
+ };
897
932
  const validateInlineWrapperStack = (value, path, issues) => {
898
933
  if (!Array.isArray(value)) {
899
934
  issues.push({
@@ -909,6 +944,13 @@ const validateInlineWrapperStack = (value, path, issues) => {
909
944
  });
910
945
  return;
911
946
  }
947
+ if (!isWithinPreservedMarkupBudget(inlineWrapperProperties(value))) {
948
+ issues.push({
949
+ path,
950
+ message: "Inline wrapper stack exceeds its resource budget."
951
+ });
952
+ return;
953
+ }
912
954
  for (const [index, layer] of value.entries()) {
913
955
  const layerPath = `${path}[${index}]`;
914
956
  if (!isRecord(layer)) {
@@ -950,6 +992,22 @@ const readInlineWrapperMarkAttrs = (mark) => {
950
992
  const issues = [];
951
993
  expectMarkType(mark, "inlineWrapper", issues);
952
994
  validateInlineWrapperStack(attrs["stack"], "inlineWrapper.attrs.stack", issues);
995
+ const hyperlinkIndex = attrs["_docxHyperlinkIndex"];
996
+ const stackStart = attrs["_docxInsideHyperlinkStackStart"];
997
+ const hasHyperlinkIndex = hyperlinkIndex !== void 0 && hyperlinkIndex !== null;
998
+ const hasStackStart = stackStart !== void 0 && stackStart !== null;
999
+ if (hasHyperlinkIndex !== hasStackStart) issues.push({
1000
+ path: "inlineWrapper.attrs",
1001
+ message: "Hyperlink wrapper provenance requires both an index and stack start."
1002
+ });
1003
+ else if (hasHyperlinkIndex && hasStackStart) {
1004
+ validateNonNegativeInteger(hyperlinkIndex, "inlineWrapper.attrs._docxHyperlinkIndex", issues);
1005
+ validateNonNegativeInteger(stackStart, "inlineWrapper.attrs._docxInsideHyperlinkStackStart", issues);
1006
+ if (typeof stackStart === "number" && Array.isArray(attrs["stack"]) && stackStart >= attrs["stack"].length) issues.push({
1007
+ path: "inlineWrapper.attrs._docxInsideHyperlinkStackStart",
1008
+ message: "Expected a stack position inside the wrapper stack."
1009
+ });
1010
+ }
953
1011
  return attrsResult(attrs, issues);
954
1012
  };
955
1013
  const expectInlineWrapperMarkAttrs = (mark) => expectCachedMarkAttrs(mark, inlineWrapperAttrsCache, readInlineWrapperMarkAttrs, "inline wrapper attrs");
@@ -1745,7 +1803,7 @@ const optionalPositionedBookmarks = (attrs, path, issues) => {
1745
1803
  });
1746
1804
  continue;
1747
1805
  }
1748
- requiredNumber(entry, "index", `${entryPath}.index`, issues);
1806
+ validateNonNegativeSafeInteger(entry["index"], `${entryPath}.index`, issues);
1749
1807
  const marker = entry["marker"];
1750
1808
  if (!isRecord(marker)) {
1751
1809
  issues.push({
@@ -1762,7 +1820,7 @@ const optionalPositionedBookmarks = (attrs, path, issues) => {
1762
1820
  });
1763
1821
  continue;
1764
1822
  }
1765
- requiredNumber(marker, "id", `${entryPath}.marker.id`, issues);
1823
+ validateNonNegativeSafeInteger(marker["id"], `${entryPath}.marker.id`, issues);
1766
1824
  if (type === "bookmarkStart") requiredString(marker, "name", `${entryPath}.marker.name`, issues);
1767
1825
  optionalContentControls(entry, `${entryPath}.contentControls`, issues);
1768
1826
  }
@@ -2574,11 +2632,17 @@ const validateNonNegativeInteger = (value, path, issues) => {
2574
2632
  });
2575
2633
  return;
2576
2634
  }
2577
- if (!Number.isInteger(value) || value < 0) issues.push({
2635
+ if (!Number.isSafeInteger(value) || value < 0) issues.push({
2578
2636
  path,
2579
2637
  message: "Expected a non-negative integer."
2580
2638
  });
2581
2639
  };
2640
+ const validateNonNegativeSafeInteger = (value, path, issues) => {
2641
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) issues.push({
2642
+ path,
2643
+ message: "Expected a non-negative safe integer."
2644
+ });
2645
+ };
2582
2646
  const optionalBookmarkArray = (value, issues) => {
2583
2647
  if (value === void 0 || value === null) return;
2584
2648
  if (!Array.isArray(value)) {
@@ -2633,7 +2697,24 @@ const optionalEmptyHyperlinkArray = (value, issues) => {
2633
2697
  optionalString(item, "target", `${itemPath}.target`, issues);
2634
2698
  optionalBoolean(item, "history", `${itemPath}.history`, issues);
2635
2699
  optionalString(item, "docLocation", `${itemPath}.docLocation`, issues);
2700
+ const wrapperStacks = item["_docxEmptyWrapperStacks"];
2701
+ if (wrapperStacks === void 0 || wrapperStacks === null) continue;
2702
+ if (!Array.isArray(wrapperStacks)) {
2703
+ issues.push({
2704
+ path: `${itemPath}._docxEmptyWrapperStacks`,
2705
+ message: "Expected an array of inline wrapper stacks."
2706
+ });
2707
+ continue;
2708
+ }
2709
+ if (!isWithinPreservedMarkupBudget(emptyHyperlinkWrapperProperties(wrapperStacks))) {
2710
+ issues.push({
2711
+ path: `${itemPath}._docxEmptyWrapperStacks`,
2712
+ message: "Empty inline wrapper stacks exceed their aggregate resource budget."
2713
+ });
2714
+ continue;
2715
+ }
2716
+ for (const [stackIndex, stack] of wrapperStacks.entries()) validateInlineWrapperStack(stack, `${itemPath}._docxEmptyWrapperStacks[${stackIndex}]`, issues);
2636
2717
  }
2637
2718
  };
2638
2719
  //#endregion
2639
- export { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectInlineWrapperMarkAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectParagraphAttrs, expectPreservedBlockAttrs, expectPreservedXmlAttrs, expectRunFormattingOverrideMarkAttrs, expectRunIdentityMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs, mergeImageAttrs, mergeParagraphAttrs, mergeTableAttrs, mergeTableCellAttrs, mergeTableRowAttrs, readBlockSdtAttrs, readCharacterSpacingMarkAttrs, readCharacterStyleMarkAttrs, readCommentMarkAttrs, readEmphasisMarkAttrs, readFieldAttrs, readFontFamilyMarkAttrs, readFontSizeMarkAttrs, readFootnoteRefMarkAttrs, readHardBreakAttrs, readHighlightMarkAttrs, readHyperlinkMarkAttrs, readImageAttrs, readInlineWrapperMarkAttrs, readInlineWrapperStack, readLanguageMarkAttrs, readMathAttrs, readPageBreakRunAttrs, readParagraphAttrs, readPreservedBlockAttrs, readPreservedXmlAttrs, readRunFormattingOverrideMarkAttrs, readRunIdentityMarkAttrs, readRunPropertyChangeMarkAttrs, readRunShadingMarkAttrs, readSdtAttrs, readShapeAttrs, readStrikeMarkAttrs, readSymbolAttrs, readTabAttrs, readTableAttrs, readTableCellAttrs, readTableRowAttrs, readTextBoxAttrs, readTextColorMarkAttrs, readTextEffectMarkAttrs, readTrackedChangeMarkAttrs, readUnderlineMarkAttrs };
2720
+ export { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectInlineWrapperMarkAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectParagraphAttrs, expectPreservedBlockAttrs, expectPreservedXmlAttrs, expectRunFormattingOverrideMarkAttrs, expectRunIdentityMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs, isTrackedRevisionAncestorArray, mergeImageAttrs, mergeParagraphAttrs, mergeTableAttrs, mergeTableCellAttrs, mergeTableRowAttrs, readBlockSdtAttrs, readCharacterSpacingMarkAttrs, readCharacterStyleMarkAttrs, readCommentMarkAttrs, readEmphasisMarkAttrs, readFieldAttrs, readFontFamilyMarkAttrs, readFontSizeMarkAttrs, readFootnoteRefMarkAttrs, readHardBreakAttrs, readHighlightMarkAttrs, readHyperlinkMarkAttrs, readImageAttrs, readInlineWrapperMarkAttrs, readInlineWrapperStack, readLanguageMarkAttrs, readMathAttrs, readPageBreakRunAttrs, readParagraphAttrs, readPreservedBlockAttrs, readPreservedXmlAttrs, readRunFormattingOverrideMarkAttrs, readRunIdentityMarkAttrs, readRunPropertyChangeMarkAttrs, readRunShadingMarkAttrs, readSdtAttrs, readShapeAttrs, readStrikeMarkAttrs, readSymbolAttrs, readTabAttrs, readTableAttrs, readTableCellAttrs, readTableRowAttrs, readTextBoxAttrs, readTextColorMarkAttrs, readTextEffectMarkAttrs, readTrackedChangeMarkAttrs, readUnderlineMarkAttrs };
@@ -2,7 +2,7 @@ import { sameStatedParagraphNumbering as sameStatedParagraphNumbering$1 } from "
2
2
  import { joinProseParagraphsWithRightPropertySource } from "../../docx/paragraphPropertySource.js";
3
3
  import { appendHeadlessInlineResolution } from "../../internal/headlessRevisionResolution.js";
4
4
  import { stateAllowsHeadlessRevisionResolution } from "../../internal/headlessRevisionResolutionGuard.js";
5
- import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs } from "../attrs/index.js";
5
+ import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs, expectTrackedChangeMarkAttrs } from "../attrs/index.js";
6
6
  import { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer } from "../containerFinalParagraph.js";
7
7
  import { resolveParagraphDefaultTextFormatting } from "../conversion/toProseDoc.js";
8
8
  import { markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval } from "../extensions/features/ParagraphChangeTrackerExtension.js";
@@ -19,6 +19,7 @@ import { reconcileTableGridAfterColumnRemoval } from "../tableGridMutation.js";
19
19
  import { holdsNoContent } from "../zeroWidthAnchors.js";
20
20
  import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot, paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties, tableCellRejectAttrPatch, tablePropertyExceptionsRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
21
21
  import { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge } from "./tableCellMergeResolution.js";
22
+ import { panic } from "better-result";
22
23
  import { PARAGRAPH_MARK_CHANGE_KINDS, REVIEW_CARRIERS } from "@stll/docx-core/model";
23
24
  import { TableMap, removeRow } from "prosemirror-tables";
24
25
  import { Mapping } from "prosemirror-transform";
@@ -55,6 +56,33 @@ function removeCommentMark(commentId) {
55
56
  return true;
56
57
  };
57
58
  }
59
+ const revisionLayerOf = (mark) => {
60
+ const attrs = expectTrackedChangeMarkAttrs(mark);
61
+ let type;
62
+ if (mark.type.name === "insertion") type = attrs.moveKind === "moveTo" ? "moveTo" : "insertion";
63
+ else type = attrs.moveKind === "moveFrom" ? "moveFrom" : "deletion";
64
+ return {
65
+ type,
66
+ revisionId: attrs.revisionId,
67
+ author: attrs.author,
68
+ ...attrs.date ? { date: attrs.date } : {},
69
+ ...attrs.utcDate ? { utcDate: attrs.utcDate } : {},
70
+ ...attrs.initials ? { initials: attrs.initials } : {},
71
+ outerWrapperCount: attrs._docxOuterWrapperCount ?? 0
72
+ };
73
+ };
74
+ const revisionLayerRemovesContent = (layer, mode) => mode === "accept" ? layer.type === "deletion" || layer.type === "moveFrom" : layer.type === "insertion" || layer.type === "moveTo";
75
+ const containsNestedRevision = (doc) => {
76
+ let found = false;
77
+ doc.descendants((node) => {
78
+ if (found) return false;
79
+ for (const mark of node.marks) if ((mark.type.name === "insertion" || mark.type.name === "deletion") && (expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors?.length ?? 0) > 0) {
80
+ found = true;
81
+ return false;
82
+ }
83
+ });
84
+ return found;
85
+ };
58
86
  /**
59
87
  * Resolve a tracked change: accept or reject.
60
88
  * - Accept: keep insertions (remove mark), delete deletions (remove text)
@@ -76,7 +104,7 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
76
104
  const removeType = mode === "accept" ? deletionType : insertionType;
77
105
  const revisionSet = revisionIds === void 0 ? null : new Set(revisionIds);
78
106
  const removeKeptMarksInBulk = revisionSet === null && keepType !== void 0;
79
- const canBulkInlineResolution = execution === "headless-bulk-inline" && revisionSet === null && from === 0 && to === state.doc.content.size && stateAllowsHeadlessRevisionResolution(state);
107
+ const canBulkInlineResolution = execution === "headless-bulk-inline" && revisionSet === null && from === 0 && to === state.doc.content.size && stateAllowsHeadlessRevisionResolution(state) && !containsNestedRevision(state.doc);
80
108
  const matchesRevision = (mark) => revisionSet === null || typeof mark.attrs["revisionId"] === "number" && revisionSet.has(mark.attrs["revisionId"]);
81
109
  if (dispatch) {
82
110
  const tr = state.tr;
@@ -189,6 +217,36 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
189
217
  revisionSet,
190
218
  styleResolver
191
219
  });
220
+ const nestedMark = node.marks.find((mark) => (mark.type === insertionType || mark.type === deletionType) && (expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors?.length ?? 0) > 0);
221
+ if (nestedMark) {
222
+ const path = [...expectTrackedChangeMarkAttrs(nestedMark)._docxRevisionAncestors ?? [], revisionLayerOf(nestedMark)];
223
+ const selected = (layer) => revisionSet === null || revisionSet.has(layer.revisionId);
224
+ if (path.some(selected)) if (path.some((layer) => selected(layer) && revisionLayerRemovesContent(layer, mode))) deleteRanges.push({
225
+ from: rangeFrom,
226
+ to: rangeTo
227
+ });
228
+ else {
229
+ tr.removeMark(rangeFrom, rangeTo, nestedMark);
230
+ const remaining = path.filter((layer) => !selected(layer));
231
+ const active = remaining.at(-1);
232
+ if (active) {
233
+ const type = active.type === "insertion" || active.type === "moveTo" ? insertionType : deletionType;
234
+ if (!type) panic("A nested tracked revision has no editor mark type");
235
+ tr.addMark(rangeFrom, rangeTo, type.create({
236
+ revisionId: active.revisionId,
237
+ author: active.author,
238
+ date: active.date ?? null,
239
+ utcDate: active.utcDate ?? null,
240
+ initials: active.initials ?? null,
241
+ moveKind: active.type === "moveTo" || active.type === "moveFrom" ? active.type : null,
242
+ _historicalFormatting: active.type === "deletion" || active.type === "moveFrom" ? true : null,
243
+ _docxOuterWrapperCount: active.outerWrapperCount,
244
+ _docxRevisionAncestors: remaining.length > 1 ? remaining.slice(0, -1) : null
245
+ }));
246
+ }
247
+ }
248
+ return true;
249
+ }
192
250
  if (removesNode) deleteRanges.push({
193
251
  from: rangeFrom,
194
252
  to: rangeTo
@@ -794,7 +852,7 @@ function findAIEditRevisionRange(state, revisionIds) {
794
852
  includeRange(pos, pos + node.nodeSize);
795
853
  break;
796
854
  }
797
- if ((mark.type === insertionType || mark.type === deletionType) && typeof mark.attrs["revisionId"] === "number" && idSet.has(mark.attrs["revisionId"])) {
855
+ if ((mark.type === insertionType || mark.type === deletionType) && (idSet.has(expectTrackedChangeMarkAttrs(mark).revisionId) || (expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors ?? []).some((ancestor) => idSet.has(ancestor.revisionId)))) {
798
856
  includeRange(pos, pos + node.nodeSize);
799
857
  break;
800
858
  }
@@ -8,9 +8,9 @@ const readCommentReferenceAttrs = (node) => {
8
8
  message: `Expected commentReference, got ${node.type.name}.`
9
9
  });
10
10
  const commentId = node.attrs["commentId"];
11
- if (typeof commentId !== "number" || !Number.isInteger(commentId) || commentId < 0) issues.push({
11
+ if (typeof commentId !== "number" || !Number.isSafeInteger(commentId)) issues.push({
12
12
  path: "commentReference.attrs.commentId",
13
- message: "Expected a non-negative integer."
13
+ message: "Expected a safe integer."
14
14
  });
15
15
  if (issues.length > 0 || typeof commentId !== "number") return {
16
16
  ok: false,
@@ -10,13 +10,17 @@
10
10
  * a comment mark creates none — so the repair is computed here and applied by
11
11
  * the extension's `appendTransaction`, rather than left to each call site.
12
12
  */
13
- type CommentReferenceOccurrence = {
14
- commentId: number;
13
+ type PositionedReference = {
15
14
  position: number;
16
15
  /** Node size, so a caller can delete the node without re-reading it. */
17
16
  size: number;
18
- malformed: boolean;
19
17
  };
18
+ type CommentReferenceOccurrence = (PositionedReference & {
19
+ status: "valid";
20
+ commentId: number;
21
+ }) | (PositionedReference & {
22
+ status: "malformed";
23
+ });
20
24
  /** Where a comment's mark last covers content, and how far that content runs. */
21
25
  type CommentMarkExtent = {
22
26
  commentId: number;
@@ -10,7 +10,15 @@ const planCommentReferenceRepairs = ({ references, markExtents }) => {
10
10
  const deletions = [];
11
11
  const keptIds = /* @__PURE__ */ new Set();
12
12
  for (const reference of references) {
13
- if (reference.malformed || !markedIds.has(reference.commentId)) {
13
+ if (reference.status === "malformed") {
14
+ deletions.push({
15
+ type: "delete",
16
+ position: reference.position,
17
+ size: reference.size
18
+ });
19
+ continue;
20
+ }
21
+ if (!markedIds.has(reference.commentId)) {
14
22
  deletions.push({
15
23
  type: "delete",
16
24
  position: reference.position,