@stll/folio-core 0.54.2 → 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.
Files changed (267) hide show
  1. package/dist/ai-edits/apply.js +185 -33
  2. package/dist/ai-edits/headless.js +3 -2
  3. package/dist/ai-edits/types.d.ts +7 -1
  4. package/dist/compare/compare.js +1 -0
  5. package/dist/compare/content-types.d.ts +3 -15
  6. package/dist/compare/reproducible-package.d.ts +0 -17
  7. package/dist/compare/reproducible-package.js +12 -18
  8. package/dist/controller/canonicalClipboard.d.ts +23 -0
  9. package/dist/controller/canonicalClipboard.js +476 -0
  10. package/dist/controller/canonicalClipboardResources.d.ts +21 -0
  11. package/dist/controller/canonicalClipboardResources.js +382 -0
  12. package/dist/controller/canonicalComposition.d.ts +53 -0
  13. package/dist/controller/canonicalComposition.js +296 -0
  14. package/dist/controller/canonicalInlineProjection.d.ts +113 -0
  15. package/dist/controller/canonicalInlineProjection.js +393 -0
  16. package/dist/controller/canonicalInput.d.ts +54 -0
  17. package/dist/controller/canonicalInput.js +377 -0
  18. package/dist/controller/canonicalInputTimer.d.ts +7 -0
  19. package/dist/controller/canonicalInputTimer.js +11 -0
  20. package/dist/controller/canonicalOperations.d.ts +22 -0
  21. package/dist/controller/canonicalOperations.js +85 -0
  22. package/dist/controller/canonicalPublicOperations.d.ts +48 -0
  23. package/dist/controller/canonicalPublicOperations.js +556 -0
  24. package/dist/controller/canonicalReview.d.ts +12 -0
  25. package/dist/controller/canonicalReview.js +19 -0
  26. package/dist/controller/canonicalSession.d.ts +167 -0
  27. package/dist/controller/canonicalSession.js +1186 -0
  28. package/dist/controller/canonicalStoryEditor.d.ts +36 -0
  29. package/dist/controller/canonicalStoryEditor.js +87 -0
  30. package/dist/controller/canonicalStructure.d.ts +16 -0
  31. package/dist/controller/canonicalStructure.js +322 -0
  32. package/dist/controller/canonicalTocSelection.d.ts +11 -0
  33. package/dist/controller/canonicalTocSelection.js +43 -0
  34. package/dist/controller/folioEditor.d.ts +3 -10
  35. package/dist/controller/folioEditor.js +14 -4
  36. package/dist/controller/headerFooterEditorManager.d.ts +5 -0
  37. package/dist/controller/headerFooterEditorManager.js +72 -3
  38. package/dist/controller/hiddenEditorApi.d.ts +45 -0
  39. package/dist/controller/hiddenEditorApi.js +29 -8
  40. package/dist/controller/hiddenEditorManager.d.ts +13 -2
  41. package/dist/controller/hiddenEditorManager.js +639 -31
  42. package/dist/controller/layoutPipeline.d.ts +1 -1
  43. package/dist/controller/layoutPipeline.js +2 -0
  44. package/dist/controller/noteEditorManager.d.ts +5 -0
  45. package/dist/controller/noteEditorManager.js +114 -15
  46. package/dist/document-operations.d.ts +8 -1
  47. package/dist/document-operations.js +6 -4
  48. package/dist/docx/attributeRemainder.js +1 -0
  49. package/dist/docx/blockPlainText.d.ts +1 -1
  50. package/dist/docx/blockPlainText.js +11 -3
  51. package/dist/docx/canonicalResourceSave.d.ts +16 -0
  52. package/dist/docx/canonicalResourceSave.js +27 -0
  53. package/dist/docx/canonicalSave.d.ts +29 -0
  54. package/dist/docx/canonicalSave.js +101 -0
  55. package/dist/docx/canonicalSessionInput.d.ts +11 -0
  56. package/dist/docx/canonicalSessionInput.js +27 -0
  57. package/dist/docx/canonicalStoryRepack.d.ts +10 -0
  58. package/dist/docx/canonicalStoryRepack.js +74 -0
  59. package/dist/docx/contentTypeRegistry.d.ts +8 -0
  60. package/dist/docx/contentTypeRegistry.js +64 -0
  61. package/dist/docx/documentParser.d.ts +1 -13
  62. package/dist/docx/documentParser.js +1 -47
  63. package/dist/docx/ensureParaIds.d.ts +7 -1
  64. package/dist/docx/ensureParaIds.js +173 -215
  65. package/dist/docx/foldedListNumberFields.d.ts +85 -0
  66. package/dist/docx/foldedListNumberFields.js +267 -0
  67. package/dist/docx/footnoteParser.d.ts +1 -11
  68. package/dist/docx/footnoteParser.js +1 -16
  69. package/dist/docx/headerFooterParser.d.ts +1 -9
  70. package/dist/docx/headerFooterParser.js +1 -12
  71. package/dist/docx/headerFooterVerbatim.d.ts +39 -1
  72. package/dist/docx/headerFooterVerbatim.js +173 -2
  73. package/dist/docx/imageParser.d.ts +13 -1
  74. package/dist/docx/imageParser.js +20 -11
  75. package/dist/docx/metadataPrivacy.js +6 -1
  76. package/dist/docx/noteIds.d.ts +5 -0
  77. package/dist/docx/noteIds.js +6 -2
  78. package/dist/docx/noteReferenceMark.d.ts +3 -1
  79. package/dist/docx/noteReferenceMark.js +15 -14
  80. package/dist/docx/numberingParser.d.ts +3 -1
  81. package/dist/docx/numberingParser.js +17 -3
  82. package/dist/docx/packageParts.d.ts +3 -1
  83. package/dist/docx/packageParts.js +74 -19
  84. package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
  85. package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
  86. package/dist/docx/paragraphParser.js +101 -53
  87. package/dist/docx/paragraphPropertySource.d.ts +15 -1
  88. package/dist/docx/paragraphPropertySource.js +77 -22
  89. package/dist/docx/parser.js +3 -1
  90. package/dist/docx/removeHeaderFooterParts.js +17 -6
  91. package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
  92. package/dist/docx/reviewHistoryNamespace.js +4 -0
  93. package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
  94. package/dist/docx/reviewResolutionProvenance.js +153 -0
  95. package/dist/docx/rezip.d.ts +54 -6
  96. package/dist/docx/rezip.js +835 -257
  97. package/dist/docx/runConsolidator.d.ts +2 -58
  98. package/dist/docx/runConsolidator.js +3 -175
  99. package/dist/docx/runParser.d.ts +2 -1
  100. package/dist/docx/runParser.js +156 -116
  101. package/dist/docx/saveDiagnostics.d.ts +22 -0
  102. package/dist/docx/saveDiagnostics.js +0 -0
  103. package/dist/docx/selectiveSave.d.ts +3 -1
  104. package/dist/docx/selectiveSave.js +36 -4
  105. package/dist/docx/selectiveXmlPatch.d.ts +16 -8
  106. package/dist/docx/selectiveXmlPatch.js +81 -7
  107. package/dist/docx/serializer/documentSerializer.d.ts +9 -2
  108. package/dist/docx/serializer/documentSerializer.js +29 -10
  109. package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
  110. package/dist/docx/serializer/headerFooterSerializer.js +19 -11
  111. package/dist/docx/serializer/noteSerializer.d.ts +2 -2
  112. package/dist/docx/serializer/noteSerializer.js +24 -8
  113. package/dist/docx/serializer/paragraphSerializer.js +41 -4
  114. package/dist/docx/serializer/partNamespaces.js +2 -1
  115. package/dist/docx/serializer/runSerializer.js +3 -1
  116. package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
  117. package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
  118. package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
  119. package/dist/docx/settingsParser.d.ts +1 -2
  120. package/dist/docx/settingsParser.js +5 -6
  121. package/dist/docx/storyBlockReplay.d.ts +31 -0
  122. package/dist/docx/storyBlockReplay.js +471 -0
  123. package/dist/docx/storyPlainText.d.ts +20 -0
  124. package/dist/docx/storyPlainText.js +23 -0
  125. package/dist/docx/streamingXmlParser.d.ts +22 -1
  126. package/dist/docx/streamingXmlParser.js +49 -3
  127. package/dist/docx/structuralXmlPatch.js +18 -23
  128. package/dist/docx/styleParser.d.ts +5 -1
  129. package/dist/docx/styleParser.js +1 -1
  130. package/dist/docx/tableParser.d.ts +1 -8
  131. package/dist/docx/tableParser.js +1 -28
  132. package/dist/docx/textBoxParser.d.ts +1 -5
  133. package/dist/docx/textBoxParser.js +1 -20
  134. package/dist/docx/unzip.js +6 -1
  135. package/dist/docx/verbatimCapture.d.ts +3 -1
  136. package/dist/docx/verbatimCapture.js +49 -6
  137. package/dist/i18n/messages/ar.gen.d.ts +5 -0
  138. package/dist/i18n/messages/ar.gen.js +656 -0
  139. package/dist/i18n/messages/cs.gen.d.ts +5 -0
  140. package/dist/i18n/messages/cs.gen.js +656 -0
  141. package/dist/i18n/messages/de.gen.d.ts +5 -0
  142. package/dist/i18n/messages/de.gen.js +656 -0
  143. package/dist/i18n/messages/en.gen.d.ts +5 -0
  144. package/dist/i18n/messages/en.gen.js +656 -0
  145. package/dist/i18n/messages/es.gen.d.ts +5 -0
  146. package/dist/i18n/messages/es.gen.js +656 -0
  147. package/dist/i18n/messages/et.gen.d.ts +5 -0
  148. package/dist/i18n/messages/et.gen.js +656 -0
  149. package/dist/i18n/messages/fr.gen.d.ts +5 -0
  150. package/dist/i18n/messages/fr.gen.js +656 -0
  151. package/dist/i18n/messages/he.gen.d.ts +5 -0
  152. package/dist/i18n/messages/he.gen.js +656 -0
  153. package/dist/i18n/messages/hi.gen.d.ts +5 -0
  154. package/dist/i18n/messages/hi.gen.js +656 -0
  155. package/dist/i18n/messages/hu.gen.d.ts +5 -0
  156. package/dist/i18n/messages/hu.gen.js +656 -0
  157. package/dist/i18n/messages/locales.d.ts +5 -0
  158. package/dist/i18n/messages/locales.js +22 -0
  159. package/dist/i18n/messages/lt.gen.d.ts +5 -0
  160. package/dist/i18n/messages/lt.gen.js +656 -0
  161. package/dist/i18n/messages/lv.gen.d.ts +5 -0
  162. package/dist/i18n/messages/lv.gen.js +656 -0
  163. package/dist/i18n/messages/pl.gen.d.ts +5 -0
  164. package/dist/i18n/messages/pl.gen.js +656 -0
  165. package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
  166. package/dist/i18n/messages/pt-BR.gen.js +656 -0
  167. package/dist/i18n/messages/sk.gen.d.ts +5 -0
  168. package/dist/i18n/messages/sk.gen.js +656 -0
  169. package/dist/i18n/messages/tr.gen.d.ts +5 -0
  170. package/dist/i18n/messages/tr.gen.js +656 -0
  171. package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
  172. package/dist/i18n/messages/zh-CN.gen.js +656 -0
  173. package/dist/i18n/messages.d.ts +2 -3
  174. package/dist/i18n/messages.js +1 -19
  175. package/dist/internal/acceptedBlockProjection.d.ts +12 -0
  176. package/dist/internal/acceptedBlockProjection.js +45 -0
  177. package/dist/internal/noteMarkerAttrs.d.ts +8 -0
  178. package/dist/internal/noteMarkerAttrs.js +16 -0
  179. package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
  180. package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
  181. package/dist/internal/prosemirrorAttrBoundary.js +50 -0
  182. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  183. package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
  184. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  185. package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
  186. package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
  187. package/dist/layout-bridge/convert/noteReferences.js +1 -6
  188. package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
  189. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
  190. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
  191. package/dist/managers/DocumentLoaderManager.d.ts +1 -0
  192. package/dist/managers/DocumentLoaderManager.js +9 -1
  193. package/dist/markdown/escape.d.ts +3 -1
  194. package/dist/markdown/escape.js +9 -2
  195. package/dist/markdown/renderBlock.js +20 -121
  196. package/dist/markdown/renderParagraph.js +13 -15
  197. package/dist/markdown/renderRuns.d.ts +7 -1
  198. package/dist/markdown/renderRuns.js +35 -15
  199. package/dist/markdown/renderTable.js +2 -0
  200. package/dist/markdown/types.d.ts +3 -9
  201. package/dist/prosemirror/attrs/index.d.ts +2 -12
  202. package/dist/prosemirror/attrs/index.js +22 -48
  203. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
  204. package/dist/prosemirror/canonicalCommands.d.ts +121 -0
  205. package/dist/prosemirror/canonicalCommands.js +35 -0
  206. package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
  207. package/dist/prosemirror/canonicalSelectionRange.js +15 -0
  208. package/dist/prosemirror/clipboardIntent.d.ts +7 -0
  209. package/dist/prosemirror/clipboardIntent.js +9 -0
  210. package/dist/prosemirror/commands/pageBreak.js +15 -1
  211. package/dist/prosemirror/commands/pastePlainText.js +2 -1
  212. package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
  213. package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
  214. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
  215. package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
  216. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
  217. package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
  218. package/dist/prosemirror/conversion/toProseDoc.d.ts +11 -4
  219. package/dist/prosemirror/conversion/toProseDoc.js +55 -14
  220. package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
  221. package/dist/prosemirror/executeEditorCommand.js +26 -0
  222. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  223. package/dist/prosemirror/extensions/core/ParagraphExtension.js +88 -48
  224. package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
  225. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
  226. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
  227. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
  228. package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
  229. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  230. package/dist/prosemirror/extensions/marks/markUtils.js +72 -8
  231. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
  232. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
  233. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
  234. package/dist/prosemirror/insertOperations.js +2 -1
  235. package/dist/prosemirror/listMarker.d.ts +1 -0
  236. package/dist/prosemirror/listMarker.js +16 -7
  237. package/dist/prosemirror/listNumbering.js +26 -5
  238. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  239. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  240. package/dist/prosemirror/markupViewNotes.js +3 -2
  241. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
  242. package/dist/prosemirror/noteReferenceReview.js +5 -3
  243. package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
  244. package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
  245. package/dist/prosemirror/plugins/suggestionMode.js +57 -7
  246. package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
  247. package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
  248. package/dist/prosemirror/runFormattingFromMarks.js +15 -1
  249. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
  250. package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
  251. package/dist/prosemirror/schema/marks.d.ts +2 -0
  252. package/dist/prosemirror/schema/nodes.d.ts +10 -2
  253. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
  254. package/dist/prosemirror/textInput.js +5 -1
  255. package/dist/prosemirror/trackedRevisionPath.js +2 -1
  256. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
  257. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
  258. package/dist/prosemirror/validation.js +4 -0
  259. package/dist/types/canonicalCapabilities.d.ts +215 -0
  260. package/dist/types/canonicalCapabilities.js +212 -0
  261. package/dist/types/canonicalSave.d.ts +11 -0
  262. package/dist/types/canonicalSave.js +0 -0
  263. package/dist/types/content.d.ts +2 -2
  264. package/dist/types/docxSerialization.d.ts +14 -0
  265. package/dist/types/docxSerialization.js +7 -0
  266. package/dist/utils/createDocument.js +2 -2
  267. package/package.json +16 -4
@@ -0,0 +1,267 @@
1
+ //#region src/docx/foldedListNumberFields.ts
2
+ /** Zero-width markup that can stand between a field and its tab. */
3
+ const RANGE_MARKER_TYPES = /* @__PURE__ */ new Set([
4
+ "bookmarkStart",
5
+ "bookmarkEnd",
6
+ "commentRangeStart",
7
+ "commentRangeEnd",
8
+ "commentReference"
9
+ ]);
10
+ /** Markup that shows nothing and so does not end the start of a paragraph. */
11
+ const ZERO_WIDTH_TYPES = /* @__PURE__ */ new Set([
12
+ ...RANGE_MARKER_TYPES,
13
+ "moveFromRangeStart",
14
+ "moveFromRangeEnd",
15
+ "moveToRangeStart",
16
+ "moveToRangeEnd"
17
+ ]);
18
+ /** Whether `content` is markup that may stand between a field and the tab that follows it. */
19
+ const isListNumberGapMarker = (content) => RANGE_MARKER_TYPES.has(content.type);
20
+ const isZeroWidth = (content) => ZERO_WIDTH_TYPES.has(content.type) || content.type === "preservedInline" && content.text === "";
21
+ /** Whether `content` is a `LISTNUM` field, by its parsed type or its instruction. */
22
+ const isListNumberField = (content) => content.type === "complexField" && (content.fieldType === "LISTNUM" || content.instruction.trim().toUpperCase().startsWith("LISTNUM"));
23
+ /** A run that holds one tab and nothing else. */
24
+ const isTabOnlyRun = (content) => content.type === "run" && content.content.length === 1 && content.content[0]?.type === "tab";
25
+ /** The text a field's cached result puts in the marker. */
26
+ const cachedListNumberText = (field) => {
27
+ let text = "";
28
+ for (const run of field.fieldResult) for (const piece of run.content) if (piece.type === "text") text += piece.text;
29
+ return text;
30
+ };
31
+ const isRecord = (value) => typeof value === "object" && value !== null;
32
+ /** Whether `value` is what a capture stands for: a complex field, or a run. */
33
+ const isFoldedListNumber = (value) => {
34
+ if (!isRecord(value)) return false;
35
+ if (value["kind"] === "field") {
36
+ const field = value["field"];
37
+ return isRecord(field) && field["type"] === "complexField" && typeof field["instruction"] === "string" && Array.isArray(field["fieldCode"]) && Array.isArray(field["fieldResult"]);
38
+ }
39
+ if (value["kind"] === "tab") {
40
+ const run = value["run"];
41
+ return isRecord(run) && run["type"] === "run" && Array.isArray(run["content"]);
42
+ }
43
+ return false;
44
+ };
45
+ /** What `content` stands for when it is a capture the fold left, else nothing. */
46
+ const foldedListNumberOf = (content) => content.type === "preservedInline" ? content.foldedListNumber : void 0;
47
+ /** Whether `content` is a capture the fold left in place of a field or its tab. */
48
+ const isFoldedListNumberCapture = (content) => foldedListNumberOf(content) !== void 0;
49
+ /**
50
+ * Replace the `LISTNUM` fields that open a paragraph, and the tab after each,
51
+ * by captures of the markup they were read from.
52
+ *
53
+ * Only what stands ahead of the first thing the line shows is folded: a field
54
+ * after text is on the line where the text is. `sourceMarkupOf` answers the
55
+ * markup; a field it has none for is left as the field it is, and ends the
56
+ * fold. Bookmark and comment markers between a field and its tab stay where
57
+ * they are, and the tab is still the field's when only they separate the two.
58
+ */
59
+ const foldListNumberFields = (content, sourceMarkupOf) => {
60
+ const folded = [];
61
+ const cached = [];
62
+ let fieldCount = 0;
63
+ let leading = true;
64
+ let awaitingTab = false;
65
+ for (const item of content) {
66
+ if (isListNumberField(item)) fieldCount += 1;
67
+ if (!leading) {
68
+ folded.push(item);
69
+ continue;
70
+ }
71
+ if (awaitingTab && RANGE_MARKER_TYPES.has(item.type)) {
72
+ folded.push(item);
73
+ continue;
74
+ }
75
+ if (awaitingTab) {
76
+ awaitingTab = false;
77
+ const tabMarkup = isTabOnlyRun(item) ? sourceMarkupOf(item) : void 0;
78
+ if (isTabOnlyRun(item) && tabMarkup !== void 0) {
79
+ folded.push({
80
+ type: "preservedInline",
81
+ xml: tabMarkup,
82
+ text: "",
83
+ foldedListNumber: {
84
+ kind: "tab",
85
+ run: item
86
+ }
87
+ });
88
+ continue;
89
+ }
90
+ }
91
+ if (isListNumberField(item)) {
92
+ const markup = sourceMarkupOf(item);
93
+ if (markup !== void 0) {
94
+ folded.push({
95
+ type: "preservedInline",
96
+ xml: markup,
97
+ text: "",
98
+ foldedListNumber: {
99
+ kind: "field",
100
+ field: item
101
+ }
102
+ });
103
+ const text = cachedListNumberText(item);
104
+ if (text) cached.push(text);
105
+ awaitingTab = true;
106
+ continue;
107
+ }
108
+ }
109
+ folded.push(item);
110
+ leading = isZeroWidth(item);
111
+ }
112
+ return {
113
+ content: folded,
114
+ cached,
115
+ fieldCount
116
+ };
117
+ };
118
+ const isCapture = (item) => item?.kind === "field" || item?.kind === "tab";
119
+ /**
120
+ * Decide which captures of a paragraph stay hidden, and what its marker shows.
121
+ *
122
+ * `markerShowsFields` says whether the paragraph's marker shows folded fields
123
+ * at all. When it does not, no capture is hidden.
124
+ *
125
+ * When it does, the captures it shows are the ones that open the paragraph:
126
+ * those ahead of the first thing the line shows, each field followed at most
127
+ * by its own tab. Text put in front of them was put in front of the body, not
128
+ * of the marker, so if the first capture no longer opens the paragraph, it
129
+ * and the captures that stand with it go back to the start. Every capture
130
+ * further in is on the line.
131
+ */
132
+ const planListNumberFold = (items, markerShowsFields) => {
133
+ const unmoved = items.map((_, index) => index);
134
+ const none = {
135
+ order: unmoved,
136
+ hidden: /* @__PURE__ */ new Set(),
137
+ suffix: void 0
138
+ };
139
+ const first = items.findIndex((item) => isCapture(item));
140
+ if (!markerShowsFields || first === -1) return none;
141
+ let order = unmoved;
142
+ if (items.slice(0, first).some((item) => item.kind === "shown")) {
143
+ let end = first + 1;
144
+ for (let index = first + 1; index < items.length; index += 1) {
145
+ const item = items[index];
146
+ if (item?.kind === "shown") break;
147
+ if (isCapture(item)) end = index + 1;
148
+ }
149
+ order = [
150
+ ...unmoved.slice(first, end),
151
+ ...unmoved.slice(0, first),
152
+ ...unmoved.slice(end)
153
+ ];
154
+ }
155
+ const hidden = /* @__PURE__ */ new Set();
156
+ const cached = [];
157
+ let fieldAwaitsTab = false;
158
+ for (const index of order) {
159
+ const item = items[index];
160
+ if (item?.kind === "hidden") continue;
161
+ if (item?.kind === "field") {
162
+ hidden.add(index);
163
+ if (item.cached) cached.push(item.cached);
164
+ fieldAwaitsTab = true;
165
+ continue;
166
+ }
167
+ if (item?.kind === "tab" && fieldAwaitsTab) {
168
+ hidden.add(index);
169
+ fieldAwaitsTab = false;
170
+ continue;
171
+ }
172
+ break;
173
+ }
174
+ return cached.length === 0 ? none : {
175
+ order,
176
+ hidden,
177
+ suffix: cached.join(" ")
178
+ };
179
+ };
180
+ /**
181
+ * What a paragraph's marker says about folded fields. It shows them after a
182
+ * tab its own level text does not have; a bullet shows only its glyph.
183
+ */
184
+ const listMarkerFoldState = ({ marker, template, isBullet, numbered }) => {
185
+ const tab = marker?.indexOf(" ") ?? -1;
186
+ if (!marker || !numbered || isBullet || !template || template.includes(" ") || tab === -1) return {
187
+ showsFields: false,
188
+ base: marker ?? ""
189
+ };
190
+ return {
191
+ showsFields: true,
192
+ base: marker.slice(0, tab)
193
+ };
194
+ };
195
+ /** The marker text for `state` showing `suffix`. */
196
+ const listMarkerWithFold = (state, suffix) => suffix === void 0 ? state.base : `${state.base}\t${suffix}`;
197
+ const foldItemOf = (content) => {
198
+ const folded = foldedListNumberOf(content);
199
+ if (folded) return folded.kind === "field" ? {
200
+ kind: "field",
201
+ cached: cachedListNumberText(folded.field)
202
+ } : { kind: "tab" };
203
+ return isZeroWidth(content) ? { kind: "hidden" } : { kind: "shown" };
204
+ };
205
+ /** The item a capture stands for, which shows on the line; any other item is itself. */
206
+ const unfoldedListNumberContent = (content) => {
207
+ const folded = foldedListNumberOf(content);
208
+ if (!folded) return content;
209
+ return folded.kind === "field" ? folded.field : folded.run;
210
+ };
211
+ /**
212
+ * The one definition of a tracked change for the fold: content inserted,
213
+ * deleted, or moved from or to a place under revision tracking.
214
+ */
215
+ const isTrackedChange = (content) => content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo";
216
+ /**
217
+ * `content` with every capture inside a tracked change replaced by the item
218
+ * it stands for. A tracked change is written with its own spellings (deleted
219
+ * text is `w:delText`, a deleted instruction `w:delInstrText`), which markup
220
+ * replayed as it was read does not have; the field and the run do.
221
+ */
222
+ const withTrackedCapturesShown = (content) => {
223
+ let changed = false;
224
+ const next = content.map((item) => {
225
+ if (!isTrackedChange(item)) return item;
226
+ if (!item.content.some((child) => foldedListNumberOf(child) !== void 0)) return item;
227
+ changed = true;
228
+ return {
229
+ ...item,
230
+ content: item.content.map((child) => {
231
+ const folded = foldedListNumberOf(child);
232
+ if (!folded) return child;
233
+ return structuredClone(folded.kind === "field" ? folded.field : folded.run);
234
+ })
235
+ };
236
+ });
237
+ return changed ? next : content;
238
+ };
239
+ /**
240
+ * Bring `paragraph` to the one form the fold allows: the captures its marker
241
+ * shows stand at its start, every other capture is the field or the tab it
242
+ * stood for, and the marker shows exactly the fields still hidden behind it.
243
+ * A capture under a tracked change is never hidden.
244
+ */
245
+ const normalizeFoldedListNumbers = (paragraph) => {
246
+ paragraph.content = withTrackedCapturesShown(paragraph.content);
247
+ const rendering = paragraph.listRendering;
248
+ const state = listMarkerFoldState({
249
+ marker: rendering?.marker,
250
+ template: rendering?.markerTemplate,
251
+ isBullet: rendering?.isBullet === true,
252
+ numbered: rendering !== void 0
253
+ });
254
+ const content = paragraph.content;
255
+ if (!state.showsFields && !content.some(isFoldedListNumberCapture)) return;
256
+ const plan = planListNumberFold(content.map(foldItemOf), state.showsFields);
257
+ const next = [];
258
+ for (const index of plan.order) {
259
+ const item = content[index];
260
+ if (item === void 0) continue;
261
+ next.push(plan.hidden.has(index) || !isFoldedListNumberCapture(item) ? item : structuredClone(unfoldedListNumberContent(item)));
262
+ }
263
+ paragraph.content = next;
264
+ if (rendering && state.showsFields) rendering.marker = listMarkerWithFold(state, plan.suffix);
265
+ };
266
+ //#endregion
267
+ export { foldListNumberFields, foldedListNumberOf, isFoldedListNumber, isFoldedListNumberCapture, isListNumberField, isListNumberGapMarker, isTabOnlyRun, normalizeFoldedListNumbers, planListNumberFold, unfoldedListNumberContent };
@@ -67,16 +67,6 @@ declare function parseFootnotes(footnotesXml: string | null, styles?: StyleMap |
67
67
  * @returns EndnoteMap with all endnotes
68
68
  */
69
69
  declare function parseEndnotes(endnotesXml: string | null, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, numbering?: NumberingMap | null, rels?: document_d_exports.RelationshipMap | null, media?: Map<string, document_d_exports.MediaFile> | null, context?: ParseContext, previews?: PreviewLedger): EndnoteMap;
70
- /**
71
- * Get plain text content of a footnote.
72
- *
73
- * Uses the accepted tracked-change view and recurses through every note block.
74
- */
75
- declare function getFootnoteText(footnote: document_d_exports.Footnote): string;
76
- /**
77
- * Get plain text content of an endnote.
78
- */
79
- declare function getEndnoteText(endnote: document_d_exports.Endnote): string;
80
70
  /**
81
71
  * Check if a footnote is a separator (not regular content)
82
72
  */
@@ -102,4 +92,4 @@ declare function mergeFootnoteMaps(...maps: FootnoteMap[]): FootnoteMap;
102
92
  */
103
93
  declare function mergeEndnoteMaps(...maps: EndnoteMap[]): EndnoteMap;
104
94
  //#endregion
105
- export { EndnoteMap, FootnoteMap, createEmptyEndnoteMap, createEmptyFootnoteMap, getEndnoteText, getFootnoteText, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
95
+ export { EndnoteMap, FootnoteMap, createEmptyEndnoteMap, createEmptyFootnoteMap, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
@@ -1,4 +1,3 @@
1
- import { blockPlainText } from "./blockPlainText.js";
2
1
  import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
3
2
  import { parseParagraph } from "./paragraphParser.js";
4
3
  import { standalonePreviewLedger } from "./previewBudget.js";
@@ -196,20 +195,6 @@ function createEndnoteMap(byId, endnotes) {
196
195
  };
197
196
  }
198
197
  /**
199
- * Get plain text content of a footnote.
200
- *
201
- * Uses the accepted tracked-change view and recurses through every note block.
202
- */
203
- function getFootnoteText(footnote) {
204
- return blockPlainText(footnote.content);
205
- }
206
- /**
207
- * Get plain text content of an endnote.
208
- */
209
- function getEndnoteText(endnote) {
210
- return blockPlainText(endnote.content);
211
- }
212
- /**
213
198
  * Check if a footnote is a separator (not regular content)
214
199
  */
215
200
  function isSeparatorFootnote(footnote) {
@@ -258,4 +243,4 @@ function mergeEndnoteMaps(...maps) {
258
243
  return createEndnoteMap(byId, endnotes);
259
244
  }
260
245
  //#endregion
261
- export { createEmptyEndnoteMap, createEmptyFootnoteMap, getEndnoteText, getFootnoteText, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
246
+ export { createEmptyEndnoteMap, createEmptyFootnoteMap, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
@@ -81,14 +81,6 @@ declare function createEmptyHeaderFooterMap(): HeaderFooterMap;
81
81
  * @returns HeaderFooterMap with all parsed headers/footers
82
82
  */
83
83
  declare function buildHeaderFooterMap(references: (document_d_exports.HeaderReference | document_d_exports.FooterReference)[], xmlContents: Map<string, string>, isHeader: boolean, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, numbering?: NumberingMap | null, rels?: document_d_exports.RelationshipMap | null, media?: Map<string, document_d_exports.MediaFile> | null): HeaderFooterMap;
84
- /**
85
- * Get plain text content of a header/footer.
86
- *
87
- * Shares one walk with the note stories: this used to read only text runs, so a
88
- * header's fields, hyperlinks, tabs and breaks were silently absent from its
89
- * text while the same paragraph in a footnote read in full.
90
- */
91
- declare function getHeaderFooterText(hf: document_d_exports.HeaderFooter): string;
92
84
  /**
93
85
  * Check if header/footer is empty (no content)
94
86
  */
@@ -129,4 +121,4 @@ declare function hasImages(hf: document_d_exports.HeaderFooter): boolean;
129
121
  */
130
122
  declare function hasTables(hf: document_d_exports.HeaderFooter): boolean;
131
123
  //#endregion
132
- export { HeaderFooterMap, buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage, getHeaderFooterText, getHeaderForPage, hasImages, hasPageNumberField, hasTables, headerFooterMapToTypeMap, isEmptyHeaderFooter, parseFooter, parseFooterReference, parseFooterReferences, parseHeader, parseHeaderFooter, parseHeaderReference, parseHeaderReferences };
124
+ export { HeaderFooterMap, buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage, getHeaderForPage, hasImages, hasPageNumberField, hasTables, headerFooterMapToTypeMap, isEmptyHeaderFooter, parseFooter, parseFooterReference, parseFooterReferences, parseHeader, parseHeaderFooter, parseHeaderReference, parseHeaderReferences };
@@ -1,5 +1,4 @@
1
1
  import { parseBlockContent } from "./blockContentParser.js";
2
- import { blockPlainText } from "./blockPlainText.js";
3
2
  import { parseFooterReference, parseFooterReferences, parseHeaderReference, parseHeaderReferences } from "./headerFooterRefParser.js";
4
3
  import { assignHeaderFooterVerbatimXml } from "./headerFooterVerbatim.js";
5
4
  import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
@@ -150,16 +149,6 @@ function buildHeaderFooterMap(references, xmlContents, isHeader, styles = null,
150
149
  return createHeaderFooterMap(byId);
151
150
  }
152
151
  /**
153
- * Get plain text content of a header/footer.
154
- *
155
- * Shares one walk with the note stories: this used to read only text runs, so a
156
- * header's fields, hyperlinks, tabs and breaks were silently absent from its
157
- * text while the same paragraph in a footnote read in full.
158
- */
159
- function getHeaderFooterText(hf) {
160
- return blockPlainText(hf.content);
161
- }
162
- /**
163
152
  * Check if header/footer is empty (no content)
164
153
  */
165
154
  function isEmptyHeaderFooter(hf) {
@@ -254,4 +243,4 @@ function hasTables(hf) {
254
243
  return false;
255
244
  }
256
245
  //#endregion
257
- export { buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage, getHeaderFooterText, getHeaderForPage, hasImages, hasPageNumberField, hasTables, headerFooterMapToTypeMap, isEmptyHeaderFooter, parseFooter, parseFooterReference, parseFooterReferences, parseHeader, parseHeaderFooter, parseHeaderReference, parseHeaderReferences };
246
+ export { buildHeaderFooterMap, createEmptyHeaderFooterMap, getFooterForPage, getHeaderForPage, hasImages, hasPageNumberField, hasTables, headerFooterMapToTypeMap, isEmptyHeaderFooter, parseFooter, parseFooterReference, parseFooterReferences, parseHeader, parseHeaderFooter, parseHeaderReference, parseHeaderReferences };
@@ -1,9 +1,47 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  //#region src/docx/headerFooterVerbatim.d.ts
3
+ type HeaderFooterSourceBaseline = {
4
+ type: "missing";
5
+ } | {
6
+ type: "mismatch";
7
+ } | {
8
+ type: "captured";
9
+ content: readonly document_d_exports.BlockContent[];
10
+ };
11
+ declare const captureHeaderFooterPackageBaselines: (document: document_d_exports.Document) => void;
12
+ /**
13
+ * Transfer body, header and footer capture handles across a trusted
14
+ * document graph clone. `structuredClone` drops symbol-keyed properties, so a
15
+ * clone would otherwise read an edited part as uncaptured ("missing") rather
16
+ * than as a mismatch against its source.
17
+ */
18
+ declare const copyHeaderFooterBaselineHandles: (target: document_d_exports.Document, source: document_d_exports.Document) => void;
19
+ /** Transfer the parsed package registry only across a trusted document graph clone. */
20
+ declare const copyHeaderFooterPackageBaselines: (target: document_d_exports.Document, source: document_d_exports.Document) => void;
21
+ declare const getHeaderFooterSourceBaseline: (hf: document_d_exports.HeaderFooter, originalBuffer?: ArrayBuffer) => HeaderFooterSourceBaseline;
22
+ declare const canReplayHeaderFooterBlocks: (hf: document_d_exports.HeaderFooter, baselineContent: readonly document_d_exports.BlockContent[]) => boolean;
3
23
  declare const getHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter) => string | undefined;
4
24
  declare const canReplayHeaderFooterVerbatim: (hf: document_d_exports.HeaderFooter) => boolean;
5
25
  declare const assignHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter, xml: string) => void;
6
26
  declare const refreshHeaderFooterVerbatimFingerprint: (hf: document_d_exports.HeaderFooter) => void;
7
27
  declare const clearHeaderFooterVerbatimXml: (hf: document_d_exports.HeaderFooter) => void;
28
+ /** Capture the body in the same trusted package registry as secondary stories. */
29
+ declare const captureDocumentSourceBaseline: (document: document_d_exports.Document, xml: string) => void;
30
+ declare const getDocumentSourceBaseline: (document: document_d_exports.Document) => {
31
+ type: "missing";
32
+ } | {
33
+ type: "mismatch";
34
+ } | {
35
+ type: "captured";
36
+ body: document_d_exports.Document["package"]["document"];
37
+ xml: string;
38
+ fingerprint: string;
39
+ resourceStyles: document_d_exports.Document["package"]["styles"];
40
+ resourceRelationships: document_d_exports.Document["package"]["relationships"];
41
+ resourceMedia: ReadonlyMap<string, {
42
+ data: ArrayBuffer;
43
+ mimeType: string;
44
+ }>;
45
+ };
8
46
  //#endregion
9
- export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, clearHeaderFooterVerbatimXml, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
47
+ export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterBlocks, canReplayHeaderFooterVerbatim, captureDocumentSourceBaseline, captureHeaderFooterPackageBaselines, clearHeaderFooterVerbatimXml, copyHeaderFooterBaselineHandles, copyHeaderFooterPackageBaselines, getDocumentSourceBaseline, getHeaderFooterSourceBaseline, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
@@ -1,5 +1,117 @@
1
+ import { canonicalJson } from "../utils/canonicalJson.js";
2
+ import { Result } from "better-result";
1
3
  //#region src/docx/headerFooterVerbatim.ts
4
+ const fingerprintBaselines = /* @__PURE__ */ new WeakMap();
5
+ const readFingerprint = (hf) => {
6
+ const fingerprint = hf.verbatimFingerprint;
7
+ if (!fingerprint) return void 0;
8
+ const cached = fingerprintBaselines.get(hf);
9
+ if (cached?.fingerprint === fingerprint) return cached.value;
10
+ const parsed = Result.try(() => JSON.parse(fingerprint));
11
+ const value = parsed.isOk() ? parsed.value : void 0;
12
+ fingerprintBaselines.set(hf, {
13
+ fingerprint,
14
+ value
15
+ });
16
+ return value;
17
+ };
18
+ const BASELINE_HANDLE = Symbol("package-source-baseline");
19
+ const contentBaselines = /* @__PURE__ */ new WeakMap();
20
+ const captureContentBaseline = (hf) => {
21
+ const fingerprint = hf.verbatimFingerprint;
22
+ if (fingerprint === void 0) return;
23
+ const handle = {};
24
+ const content = structuredClone(hf.content);
25
+ contentBaselines.set(handle, {
26
+ type: "headerFooter",
27
+ fingerprint,
28
+ xml: hf.verbatimXml,
29
+ contentFingerprint: canonicalJson(content),
30
+ content
31
+ });
32
+ Object.defineProperty(hf, BASELINE_HANDLE, {
33
+ value: handle,
34
+ enumerable: true,
35
+ configurable: true
36
+ });
37
+ };
38
+ const packageBaselines = /* @__PURE__ */ new WeakMap();
39
+ const captureHeaderFooterPackageBaselines = (document) => {
40
+ if (!document.originalBuffer) return;
41
+ const handles = /* @__PURE__ */ new Map();
42
+ for (const parts of [document.package.headers, document.package.footers]) for (const hf of parts?.values() ?? []) {
43
+ if (!(BASELINE_HANDLE in hf) || typeof hf[BASELINE_HANDLE] !== "object" || hf[BASELINE_HANDLE] === null || hf.verbatimFingerprint === void 0 || hf.verbatimXml === void 0) continue;
44
+ const bySource = handles.get(hf.verbatimFingerprint) ?? /* @__PURE__ */ new Map();
45
+ bySource.set(hf.verbatimXml, hf[BASELINE_HANDLE]);
46
+ handles.set(hf.verbatimFingerprint, bySource);
47
+ }
48
+ packageBaselines.set(document.originalBuffer, handles);
49
+ };
50
+ /**
51
+ * Transfer body, header and footer capture handles across a trusted
52
+ * document graph clone. `structuredClone` drops symbol-keyed properties, so a
53
+ * clone would otherwise read an edited part as uncaptured ("missing") rather
54
+ * than as a mismatch against its source.
55
+ */
56
+ const copyHeaderFooterBaselineHandles = (target, source) => {
57
+ const sourceBody = source.package.document;
58
+ if (BASELINE_HANDLE in sourceBody) Object.defineProperty(target.package.document, BASELINE_HANDLE, {
59
+ value: sourceBody[BASELINE_HANDLE],
60
+ enumerable: true,
61
+ configurable: true
62
+ });
63
+ for (const kind of ["headers", "footers"]) {
64
+ const targets = target.package[kind];
65
+ for (const [rId, sourcePart] of source.package[kind] ?? []) {
66
+ if (!(BASELINE_HANDLE in sourcePart)) continue;
67
+ const targetPart = targets?.get(rId);
68
+ if (!targetPart) continue;
69
+ Object.defineProperty(targetPart, BASELINE_HANDLE, {
70
+ value: sourcePart[BASELINE_HANDLE],
71
+ enumerable: true,
72
+ configurable: true
73
+ });
74
+ }
75
+ }
76
+ };
77
+ /** Transfer the parsed package registry only across a trusted document graph clone. */
78
+ const copyHeaderFooterPackageBaselines = (target, source) => {
79
+ if (!target.originalBuffer || !source.originalBuffer) return;
80
+ const baselines = packageBaselines.get(source.originalBuffer);
81
+ if (baselines) packageBaselines.set(target.originalBuffer, baselines);
82
+ };
83
+ const getHeaderFooterSourceBaseline = (hf, originalBuffer) => {
84
+ let handle;
85
+ if (BASELINE_HANDLE in hf) handle = hf[BASELINE_HANDLE];
86
+ else if (originalBuffer && hf.verbatimFingerprint !== void 0 && hf.verbatimXml !== void 0) handle = packageBaselines.get(originalBuffer)?.get(hf.verbatimFingerprint)?.get(hf.verbatimXml);
87
+ if (handle === void 0 && !(BASELINE_HANDLE in hf)) return { type: "missing" };
88
+ if (typeof handle !== "object" || handle === null) return { type: "mismatch" };
89
+ const baseline = contentBaselines.get(handle);
90
+ if (!baseline || baseline.type !== "headerFooter" || baseline.fingerprint !== hf.verbatimFingerprint || baseline.xml !== hf.verbatimXml || baseline.contentFingerprint !== canonicalJson(baseline.content)) return { type: "mismatch" };
91
+ return {
92
+ type: "captured",
93
+ content: baseline.content
94
+ };
95
+ };
96
+ const canReplayHeaderFooterBlocks = (hf, baselineContent) => {
97
+ if (hf.rawWatermarkXml !== void 0) {
98
+ const index = hf.watermarkBlockIndex;
99
+ if (index === void 0 || !Number.isInteger(index) || index < 0 || index >= baselineContent.length || baselineContent.length !== hf.content.length || canonicalJson(baselineContent.at(index)) !== canonicalJson(hf.content.at(index))) return false;
100
+ }
101
+ const baseline = readFingerprint(hf);
102
+ if (baseline === null || typeof baseline !== "object" || !("type" in baseline) || baseline.type !== hf.type) return false;
103
+ return canonicalJson({
104
+ watermark: "watermark" in baseline ? baseline.watermark : void 0,
105
+ watermarkBlockIndex: "watermarkBlockIndex" in baseline ? baseline.watermarkBlockIndex : void 0,
106
+ rawWatermarkXml: "rawWatermarkXml" in baseline ? baseline.rawWatermarkXml : void 0
107
+ }) === canonicalJson({
108
+ watermark: hf.watermark,
109
+ watermarkBlockIndex: hf.watermarkBlockIndex,
110
+ rawWatermarkXml: hf.rawWatermarkXml
111
+ });
112
+ };
2
113
  const headerFooterSerializationFingerprint = (hf) => JSON.stringify({
114
+ type: hf.type,
3
115
  content: hf.content,
4
116
  watermark: hf.watermark,
5
117
  watermarkBlockIndex: hf.watermarkBlockIndex,
@@ -9,22 +121,81 @@ const getHeaderFooterVerbatimXml = (hf) => hf.verbatimXml;
9
121
  const canReplayHeaderFooterVerbatim = (hf) => {
10
122
  const ext = hf;
11
123
  if (!ext.verbatimXml || !ext.verbatimFingerprint) return false;
12
- return ext.verbatimFingerprint === headerFooterSerializationFingerprint(hf);
124
+ return canonicalJson(readFingerprint(hf)) === canonicalJson({
125
+ type: hf.type,
126
+ content: hf.content,
127
+ watermark: hf.watermark,
128
+ watermarkBlockIndex: hf.watermarkBlockIndex,
129
+ rawWatermarkXml: hf.rawWatermarkXml
130
+ });
13
131
  };
14
132
  const assignHeaderFooterVerbatimXml = (hf, xml) => {
15
133
  const ext = hf;
16
134
  ext.verbatimXml = xml;
17
135
  ext.verbatimFingerprint = headerFooterSerializationFingerprint(hf);
136
+ captureContentBaseline(hf);
18
137
  };
19
138
  const refreshHeaderFooterVerbatimFingerprint = (hf) => {
20
139
  const ext = hf;
21
140
  if (!ext.verbatimXml) return;
22
141
  ext.verbatimFingerprint = headerFooterSerializationFingerprint(hf);
142
+ captureContentBaseline(hf);
23
143
  };
24
144
  const clearHeaderFooterVerbatimXml = (hf) => {
25
145
  const ext = hf;
26
146
  delete ext.verbatimXml;
27
147
  delete ext.verbatimFingerprint;
148
+ Reflect.deleteProperty(hf, BASELINE_HANDLE);
149
+ };
150
+ /** Capture the body in the same trusted package registry as secondary stories. */
151
+ const captureDocumentSourceBaseline = (document, xml) => {
152
+ const body = structuredClone(document.package.document);
153
+ const handle = {};
154
+ contentBaselines.set(handle, {
155
+ type: "body",
156
+ fingerprint: { type: "pending" },
157
+ xml,
158
+ body,
159
+ resourceStyles: structuredClone(document.package.styles),
160
+ resourceRelationships: structuredClone(document.package.relationships),
161
+ resourceMedia: new Map([...document.package.media ?? []].map(([path, media]) => [path, {
162
+ data: media.data,
163
+ mimeType: media.mimeType
164
+ }]))
165
+ });
166
+ Object.defineProperty(document.package.document, BASELINE_HANDLE, {
167
+ value: handle,
168
+ enumerable: true,
169
+ configurable: true
170
+ });
171
+ if (document.originalBuffer) {
172
+ const registry = packageBaselines.get(document.originalBuffer) ?? /* @__PURE__ */ new Map();
173
+ registry.set("word/document.xml", /* @__PURE__ */ new Map([["body", handle]]));
174
+ packageBaselines.set(document.originalBuffer, registry);
175
+ }
176
+ };
177
+ const getDocumentSourceBaseline = (document) => {
178
+ const body = document.package.document;
179
+ const handle = BASELINE_HANDLE in body ? body[BASELINE_HANDLE] : document.originalBuffer && packageBaselines.get(document.originalBuffer)?.get("word/document.xml")?.get("body");
180
+ if (handle === void 0) return { type: "missing" };
181
+ if (typeof handle !== "object" || handle === null) return { type: "mismatch" };
182
+ const baseline = contentBaselines.get(handle);
183
+ if (!baseline || baseline.type !== "body") return { type: "mismatch" };
184
+ const fingerprint = JSON.stringify(baseline.body);
185
+ if (baseline.fingerprint.type === "pending") baseline.fingerprint = {
186
+ type: "captured",
187
+ value: fingerprint
188
+ };
189
+ if (baseline.fingerprint.value !== fingerprint) return { type: "mismatch" };
190
+ return {
191
+ type: "captured",
192
+ body: baseline.body,
193
+ xml: baseline.xml,
194
+ fingerprint,
195
+ resourceStyles: baseline.resourceStyles,
196
+ resourceRelationships: baseline.resourceRelationships,
197
+ resourceMedia: baseline.resourceMedia
198
+ };
28
199
  };
29
200
  //#endregion
30
- export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, clearHeaderFooterVerbatimXml, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
201
+ export { assignHeaderFooterVerbatimXml, canReplayHeaderFooterBlocks, canReplayHeaderFooterVerbatim, captureDocumentSourceBaseline, captureHeaderFooterPackageBaselines, clearHeaderFooterVerbatimXml, copyHeaderFooterBaselineHandles, copyHeaderFooterPackageBaselines, getDocumentSourceBaseline, getHeaderFooterSourceBaseline, getHeaderFooterVerbatimXml, refreshHeaderFooterVerbatimFingerprint };
@@ -22,6 +22,18 @@ declare function resolveImageData(rId: string | undefined, rels: document_d_expo
22
22
  mimeType?: string;
23
23
  filename?: string;
24
24
  };
25
+ type ImageDerivedFactsOptions = {
26
+ id: string | undefined;
27
+ pictureNames: NonNullable<document_d_exports.Image["pictureNames"]>;
28
+ imageData: ReturnType<typeof resolveImageData>;
29
+ };
30
+ /** Facts the parser obtains from exported drawing markup and image relationships. */
31
+ declare const imageDerivedFactsOf: ({ id, pictureNames, imageData }: ImageDerivedFactsOptions) => {
32
+ filename?: string;
33
+ mimeType?: string;
34
+ pictureNames?: import("@stll/docx-core/model").NonVisualDrawingNames;
35
+ id?: string;
36
+ };
25
37
  /**
26
38
  * Parse a w:drawing element
27
39
  *
@@ -97,4 +109,4 @@ declare function getWrapDistancesPx(image: document_d_exports.Image): {
97
109
  */
98
110
  declare function needsTextWrapping(image: document_d_exports.Image): boolean;
99
111
  //#endregion
100
- export { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE, getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };
112
+ export { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE, getImageDimensionsPx, getImageHeightPx, getImageWidthPx, getWrapDistancesPx, hasAltText, imageDerivedFactsOf, isBehindText, isDecorativeImage, isFloatingImage, isInFrontOfText, isInlineImage, needsTextWrapping, parseDrawing, parseImage, resolveImageData };