@stll/folio-core 0.54.2 → 0.55.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 (199) hide show
  1. package/dist/ai-edits/apply.js +22 -1
  2. package/dist/ai-edits/headless.js +1 -0
  3. package/dist/compare/content-types.d.ts +3 -15
  4. package/dist/controller/canonicalComposition.d.ts +36 -0
  5. package/dist/controller/canonicalComposition.js +168 -0
  6. package/dist/controller/canonicalInput.d.ts +45 -0
  7. package/dist/controller/canonicalInput.js +338 -0
  8. package/dist/controller/canonicalOperations.d.ts +22 -0
  9. package/dist/controller/canonicalOperations.js +85 -0
  10. package/dist/controller/canonicalReview.d.ts +12 -0
  11. package/dist/controller/canonicalReview.js +19 -0
  12. package/dist/controller/canonicalSession.d.ts +149 -0
  13. package/dist/controller/canonicalSession.js +1038 -0
  14. package/dist/controller/canonicalStoryEditor.d.ts +34 -0
  15. package/dist/controller/canonicalStoryEditor.js +82 -0
  16. package/dist/controller/canonicalStructure.d.ts +16 -0
  17. package/dist/controller/canonicalStructure.js +269 -0
  18. package/dist/controller/folioEditor.d.ts +1 -1
  19. package/dist/controller/folioEditor.js +9 -0
  20. package/dist/controller/headerFooterEditorManager.d.ts +4 -0
  21. package/dist/controller/headerFooterEditorManager.js +71 -3
  22. package/dist/controller/hiddenEditorApi.d.ts +35 -0
  23. package/dist/controller/hiddenEditorApi.js +25 -8
  24. package/dist/controller/hiddenEditorManager.d.ts +11 -2
  25. package/dist/controller/hiddenEditorManager.js +456 -30
  26. package/dist/controller/layoutPipeline.d.ts +1 -1
  27. package/dist/controller/layoutPipeline.js +2 -0
  28. package/dist/controller/noteEditorManager.d.ts +4 -0
  29. package/dist/controller/noteEditorManager.js +113 -15
  30. package/dist/docx/attributeRemainder.js +1 -0
  31. package/dist/docx/canonicalSessionInput.d.ts +11 -0
  32. package/dist/docx/canonicalSessionInput.js +27 -0
  33. package/dist/docx/canonicalStoryRepack.d.ts +10 -0
  34. package/dist/docx/canonicalStoryRepack.js +41 -0
  35. package/dist/docx/contentTypeRegistry.d.ts +8 -0
  36. package/dist/docx/contentTypeRegistry.js +64 -0
  37. package/dist/docx/ensureParaIds.d.ts +7 -1
  38. package/dist/docx/ensureParaIds.js +163 -211
  39. package/dist/docx/foldedListNumberFields.d.ts +85 -0
  40. package/dist/docx/foldedListNumberFields.js +267 -0
  41. package/dist/docx/headerFooterVerbatim.d.ts +14 -1
  42. package/dist/docx/headerFooterVerbatim.js +95 -2
  43. package/dist/docx/noteIds.d.ts +5 -0
  44. package/dist/docx/noteIds.js +6 -2
  45. package/dist/docx/noteReferenceMark.d.ts +3 -1
  46. package/dist/docx/noteReferenceMark.js +15 -14
  47. package/dist/docx/numberingParser.d.ts +3 -1
  48. package/dist/docx/numberingParser.js +17 -3
  49. package/dist/docx/packageParts.d.ts +3 -1
  50. package/dist/docx/packageParts.js +65 -16
  51. package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
  52. package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
  53. package/dist/docx/paragraphParser.js +101 -53
  54. package/dist/docx/paragraphPropertySource.d.ts +15 -1
  55. package/dist/docx/paragraphPropertySource.js +76 -22
  56. package/dist/docx/parser.js +2 -1
  57. package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
  58. package/dist/docx/reviewHistoryNamespace.js +4 -0
  59. package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
  60. package/dist/docx/reviewResolutionProvenance.js +153 -0
  61. package/dist/docx/rezip.d.ts +7 -3
  62. package/dist/docx/rezip.js +107 -45
  63. package/dist/docx/runConsolidator.d.ts +2 -58
  64. package/dist/docx/runConsolidator.js +3 -175
  65. package/dist/docx/runParser.d.ts +2 -1
  66. package/dist/docx/runParser.js +156 -116
  67. package/dist/docx/saveDiagnostics.d.ts +11 -0
  68. package/dist/docx/saveDiagnostics.js +0 -0
  69. package/dist/docx/selectiveSave.d.ts +2 -1
  70. package/dist/docx/selectiveSave.js +4 -1
  71. package/dist/docx/selectiveXmlPatch.d.ts +16 -8
  72. package/dist/docx/selectiveXmlPatch.js +74 -2
  73. package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
  74. package/dist/docx/serializer/headerFooterSerializer.js +19 -11
  75. package/dist/docx/serializer/noteSerializer.d.ts +2 -2
  76. package/dist/docx/serializer/noteSerializer.js +24 -8
  77. package/dist/docx/serializer/paragraphSerializer.js +41 -4
  78. package/dist/docx/serializer/partNamespaces.js +2 -1
  79. package/dist/docx/serializer/runSerializer.js +3 -1
  80. package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
  81. package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
  82. package/dist/docx/settingsParser.d.ts +1 -2
  83. package/dist/docx/settingsParser.js +5 -6
  84. package/dist/docx/storyBlockReplay.d.ts +11 -0
  85. package/dist/docx/storyBlockReplay.js +367 -0
  86. package/dist/docx/streamingXmlParser.d.ts +22 -1
  87. package/dist/docx/streamingXmlParser.js +49 -3
  88. package/dist/docx/structuralXmlPatch.js +8 -1
  89. package/dist/docx/verbatimCapture.d.ts +3 -1
  90. package/dist/docx/verbatimCapture.js +49 -6
  91. package/dist/i18n/messages/ar.gen.d.ts +5 -0
  92. package/dist/i18n/messages/ar.gen.js +656 -0
  93. package/dist/i18n/messages/cs.gen.d.ts +5 -0
  94. package/dist/i18n/messages/cs.gen.js +656 -0
  95. package/dist/i18n/messages/de.gen.d.ts +5 -0
  96. package/dist/i18n/messages/de.gen.js +656 -0
  97. package/dist/i18n/messages/en.gen.d.ts +5 -0
  98. package/dist/i18n/messages/en.gen.js +656 -0
  99. package/dist/i18n/messages/es.gen.d.ts +5 -0
  100. package/dist/i18n/messages/es.gen.js +656 -0
  101. package/dist/i18n/messages/et.gen.d.ts +5 -0
  102. package/dist/i18n/messages/et.gen.js +656 -0
  103. package/dist/i18n/messages/fr.gen.d.ts +5 -0
  104. package/dist/i18n/messages/fr.gen.js +656 -0
  105. package/dist/i18n/messages/he.gen.d.ts +5 -0
  106. package/dist/i18n/messages/he.gen.js +656 -0
  107. package/dist/i18n/messages/hi.gen.d.ts +5 -0
  108. package/dist/i18n/messages/hi.gen.js +656 -0
  109. package/dist/i18n/messages/hu.gen.d.ts +5 -0
  110. package/dist/i18n/messages/hu.gen.js +656 -0
  111. package/dist/i18n/messages/locales.d.ts +5 -0
  112. package/dist/i18n/messages/locales.js +22 -0
  113. package/dist/i18n/messages/lt.gen.d.ts +5 -0
  114. package/dist/i18n/messages/lt.gen.js +656 -0
  115. package/dist/i18n/messages/lv.gen.d.ts +5 -0
  116. package/dist/i18n/messages/lv.gen.js +656 -0
  117. package/dist/i18n/messages/pl.gen.d.ts +5 -0
  118. package/dist/i18n/messages/pl.gen.js +656 -0
  119. package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
  120. package/dist/i18n/messages/pt-BR.gen.js +656 -0
  121. package/dist/i18n/messages/sk.gen.d.ts +5 -0
  122. package/dist/i18n/messages/sk.gen.js +656 -0
  123. package/dist/i18n/messages/tr.gen.d.ts +5 -0
  124. package/dist/i18n/messages/tr.gen.js +656 -0
  125. package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
  126. package/dist/i18n/messages/zh-CN.gen.js +656 -0
  127. package/dist/i18n/messages.d.ts +2 -3
  128. package/dist/i18n/messages.js +1 -19
  129. package/dist/internal/noteMarkerAttrs.d.ts +8 -0
  130. package/dist/internal/noteMarkerAttrs.js +16 -0
  131. package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
  132. package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
  133. package/dist/internal/prosemirrorAttrBoundary.js +50 -0
  134. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  135. package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
  136. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  137. package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
  138. package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
  139. package/dist/layout-bridge/convert/noteReferences.js +1 -6
  140. package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
  141. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
  142. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
  143. package/dist/managers/DocumentLoaderManager.d.ts +1 -0
  144. package/dist/managers/DocumentLoaderManager.js +8 -1
  145. package/dist/markdown/renderBlock.js +15 -1
  146. package/dist/markdown/renderParagraph.js +9 -13
  147. package/dist/markdown/renderRuns.js +3 -2
  148. package/dist/markdown/renderTable.js +2 -0
  149. package/dist/markdown/types.d.ts +3 -9
  150. package/dist/prosemirror/attrs/index.d.ts +2 -12
  151. package/dist/prosemirror/attrs/index.js +22 -48
  152. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
  153. package/dist/prosemirror/canonicalCommands.d.ts +97 -0
  154. package/dist/prosemirror/canonicalCommands.js +28 -0
  155. package/dist/prosemirror/commands/pageBreak.js +15 -1
  156. package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
  157. package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
  158. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
  159. package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
  160. package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -3
  161. package/dist/prosemirror/conversion/toProseDoc.js +51 -11
  162. package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
  163. package/dist/prosemirror/executeEditorCommand.js +26 -0
  164. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  165. package/dist/prosemirror/extensions/core/ParagraphExtension.js +50 -19
  166. package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
  167. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
  168. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
  169. package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
  170. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  171. package/dist/prosemirror/extensions/marks/markUtils.js +70 -8
  172. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
  173. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
  174. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
  175. package/dist/prosemirror/listMarker.d.ts +1 -0
  176. package/dist/prosemirror/listMarker.js +16 -7
  177. package/dist/prosemirror/listNumbering.js +26 -5
  178. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  179. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  180. package/dist/prosemirror/markupViewNotes.js +3 -2
  181. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
  182. package/dist/prosemirror/noteReferenceReview.js +5 -3
  183. package/dist/prosemirror/plugins/suggestionMode.js +50 -2
  184. package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
  185. package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
  186. package/dist/prosemirror/runFormattingFromMarks.js +15 -1
  187. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
  188. package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
  189. package/dist/prosemirror/schema/marks.d.ts +2 -0
  190. package/dist/prosemirror/schema/nodes.d.ts +10 -2
  191. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
  192. package/dist/prosemirror/textInput.js +5 -1
  193. package/dist/prosemirror/trackedRevisionPath.js +2 -1
  194. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
  195. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
  196. package/dist/prosemirror/validation.js +4 -0
  197. package/dist/types/content.d.ts +2 -2
  198. package/dist/utils/createDocument.js +2 -2
  199. package/package.json +14 -2
@@ -1,9 +1,11 @@
1
+ import { hasNoteReferenceMark } from "../noteReferenceMark.js";
1
2
  import { serializeBlockCustomXml } from "./blockCustomXmlSerializer.js";
2
3
  import { serializeBlockSdt } from "./blockSdtSerializer.js";
3
4
  import { serializeBookmarkMarker } from "./markupRangeAttributes.js";
4
5
  import { serializeParagraph } from "./paragraphSerializer.js";
5
6
  import { serializePartElement } from "./partNamespaces.js";
6
7
  import { serializeTable } from "./tableSerializer.js";
8
+ import { noteUsesCustomMark } from "@stll/docx-core/ops";
7
9
  //#region src/docx/serializer/noteSerializer.ts
8
10
  const NOTE_BASELINE_PREFIXES = [
9
11
  "wpc",
@@ -66,8 +68,9 @@ const NOTE_SEPARATOR_BODY = "<w:p><w:pPr><w:spacing w:after=\"0\" w:line=\"240\"
66
68
  function serializeRequiredNoteSeparators(elementName) {
67
69
  return `<w:${elementName} w:type="separator" w:id="-1">${NOTE_SEPARATOR_BODY}<w:r><w:separator/></w:r></w:p></w:${elementName}><w:${elementName} w:type="continuationSeparator" w:id="0">${NOTE_SEPARATOR_BODY}<w:r><w:continuationSeparator/></w:r></w:p></w:${elementName}>`;
68
70
  }
69
- function insertNoteReferenceMark(xml, elementName) {
70
- if (new RegExp(`<(?:[\\w.-]+:)?${elementName}Ref[\\s/>]`, "u").test(xml)) return xml;
71
+ function insertNoteReferenceMark({ xml, elementName, note, customMark }) {
72
+ if (customMark) return xml;
73
+ if (hasNoteReferenceMark(elementName, note.content)) return xml;
71
74
  const paragraphOpen = /<w:p(?=[\s>])[^>]*>/u.exec(xml);
72
75
  if (!paragraphOpen) return `${`<w:p><w:r><w:rPr><w:rStyle w:val="${elementName === "footnote" ? "FootnoteReference" : "EndnoteReference"}"/></w:rPr><w:${elementName}Ref/></w:r></w:p>`}${xml}`;
73
76
  const paragraphStart = paragraphOpen.index + paragraphOpen[0].length;
@@ -77,8 +80,13 @@ function insertNoteReferenceMark(xml, elementName) {
77
80
  const referenceRun = `<w:r><w:rPr><w:rStyle w:val="${elementName === "footnote" ? "FootnoteReference" : "EndnoteReference"}"/></w:rPr><w:${elementName}Ref/></w:r>`;
78
81
  return `${xml.slice(0, insertAt)}${referenceRun}${xml.slice(insertAt)}`;
79
82
  }
80
- function serializeNewNotePart(elementName, notes) {
81
- const serializedNotes = notes.map((note) => insertNoteReferenceMark(serializeNote(elementName, note), elementName)).join("");
83
+ function serializeNewNotePart({ elementName, notes, document }) {
84
+ const serializedNotes = notes.map((note) => insertNoteReferenceMark({
85
+ xml: serializeNote(elementName, note),
86
+ elementName,
87
+ note,
88
+ customMark: document ? noteUsesCustomMark(document, note) : false
89
+ })).join("");
82
90
  return serializeNotePart(elementName, serializeRequiredNoteSeparators(elementName) + serializedNotes);
83
91
  }
84
92
  /**
@@ -101,13 +109,21 @@ function serializeEndnotes(endnotes) {
101
109
  }
102
110
  /** Serialize a brand-new footnote part, including Word's required separators
103
111
  * and the automatic reference mark at the start of every normal note. */
104
- function serializeNewFootnotesPart(footnotes) {
105
- return serializeNewNotePart("footnote", footnotes);
112
+ function serializeNewFootnotesPart(footnotes, document) {
113
+ return serializeNewNotePart({
114
+ elementName: "footnote",
115
+ notes: footnotes,
116
+ ...document ? { document } : {}
117
+ });
106
118
  }
107
119
  /** Serialize a brand-new endnote part, including Word's required separators
108
120
  * and the automatic reference mark at the start of every normal note. */
109
- function serializeNewEndnotesPart(endnotes) {
110
- return serializeNewNotePart("endnote", endnotes);
121
+ function serializeNewEndnotesPart(endnotes, document) {
122
+ return serializeNewNotePart({
123
+ elementName: "endnote",
124
+ notes: endnotes,
125
+ ...document ? { document } : {}
126
+ });
111
127
  }
112
128
  //#endregion
113
129
  export { serializeEndnotes, serializeFootnotes, serializeNewEndnotesPart, serializeNewFootnotesPart };
@@ -2,7 +2,9 @@ import { modelParagraphFormattingEmission, serializeParagraphPropertySet } from
2
2
  import { serializePreservedAttributes } from "../attributeRemainder.js";
3
3
  import { CONTAINER_CHILDREN } from "../containerChildren.gen.js";
4
4
  import { fieldStateAttributes } from "../fieldState.js";
5
+ import { serializeEmptyMarkProperties } from "../paragraphMarkPropertyPresence.js";
5
6
  import { getParagraphPropertySource, paragraphPropertySourceMatchesEmission } from "../paragraphPropertySource.js";
7
+ import { ReviewResolutionProvenanceError, paragraphMarkResolutionJoinAttributes, serializeParagraphMarkResolutionJoin, serializeResolutionJoins } from "../reviewResolutionProvenance.js";
6
8
  import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
7
9
  import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
8
10
  import { captureVerbatimXml, createCapturedXmlSanitizer } from "../verbatimCapture.js";
@@ -20,11 +22,22 @@ import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
20
22
  import { SEQUENCE_CHILDREN } from "@stll/docx-core/schema";
21
23
  //#region src/docx/serializer/paragraphSerializer.ts
22
24
  /**
25
+ * Paragraph Serializer - Serialize paragraphs to OOXML XML
26
+ *
27
+ * Converts Paragraph objects back to <w:p> XML format for DOCX files.
28
+ * Handles all paragraph properties and child content (runs, hyperlinks, fields, bookmarks).
29
+ *
30
+ * OOXML Reference:
31
+ * - Paragraph: w:p
32
+ * - Paragraph properties: w:pPr
33
+ * - Runs, hyperlinks, bookmarks, fields as child elements
34
+ */
35
+ /**
23
36
  * Serialize paragraph formatting properties to w:pPr XML
24
37
  */
25
38
  function serializeParagraphMarkChange(mark) {
26
39
  const attrs = serializeTrackedChangeAttributes(mark.info);
27
- return `<w:${mark.kind} ${attrs}/>`;
40
+ return `<w:${mark.kind} ${attrs}${serializeParagraphMarkResolutionJoin(mark)}/>`;
28
41
  }
29
42
  const RESERVED_PARAGRAPH_PROPERTY_CHILDREN = /* @__PURE__ */ new Set(["pPrChange", "sectPr"]);
30
43
  /**
@@ -212,7 +225,10 @@ const withTrailingParagraphPropertyChildren = (sourceXml, children) => {
212
225
  const withParagraphMarkChange = (sourceXml, mark) => {
213
226
  const root = parseXml(sourceXml, OOXML_NAMESPACE_SCOPE).elements?.at(0);
214
227
  if (!root || root.type !== "element") panic("A validated paragraph-property capture could not be parsed for composition");
215
- const attributes = trackedChangeAttributeRecord(mark.info);
228
+ const attributes = {
229
+ ...trackedChangeAttributeRecord(mark.info),
230
+ ...paragraphMarkResolutionJoinAttributes(mark)
231
+ };
216
232
  const markElement = cloneElement(root, {
217
233
  name: `w:${mark.kind}`,
218
234
  attributes,
@@ -339,6 +355,20 @@ function serializeComplexField(field) {
339
355
  parts.push(`<w:r>${rPrXml}<w:fldChar w:fldCharType="end"/></w:r>`);
340
356
  return parts.join("");
341
357
  }
358
+ var UnrepresentableTrackedCaptureError = class extends TaggedError("UnrepresentableTrackedCaptureError") {};
359
+ /**
360
+ * Preserved markup inside a removal. Markup captured from a removal already
361
+ * spells its text as deleted text. Markup captured outside one and put under
362
+ * a removal afterwards does not: plain runs are respelled here, as a deleted
363
+ * run is. A folded list-number capture that cannot be respelled is refused,
364
+ * rather than written as live text inside the removal.
365
+ */
366
+ function serializeRemovedPreservedInline(item) {
367
+ if (!/<w:(?:t|instrText)[\s>]/u.test(item.xml)) return item.xml;
368
+ if (/^<w:r[\s>]/u.test(item.xml) && !/<w:(?:drawing|pict|object)\b|<mc:AlternateContent\b/u.test(item.xml)) return rewriteRunTextAsDeleted(item.xml);
369
+ if (item.foldedListNumber) throw new UnrepresentableTrackedCaptureError({ message: "A folded list-number field holds markup that cannot be written as deleted content." });
370
+ return item.xml;
371
+ }
342
372
  var UnrepresentableTrackedSimpleFieldError = class extends TaggedError("UnrepresentableTrackedSimpleFieldError") {};
343
373
  /** A revision can contain run-level field characters, but not `w:fldSimple`. */
344
374
  function serializeTrackedSimpleField(field) {
@@ -429,7 +459,12 @@ function trackedChangeTag(change) {
429
459
  }
430
460
  }
431
461
  function serializeTrackedChange(tag, change) {
432
- const attrs = serializeTrackedChangeAttributes(change.info);
462
+ if (change.resolutionJoins !== void 0 && change.content.some((item) => item.type === "hyperlink")) throw new ReviewResolutionProvenanceError({
463
+ attribute: "resolutionJoins",
464
+ reason: "unrepresentable",
465
+ message: "Tracked-resolution provenance cannot be repartitioned across serialized hyperlinks."
466
+ });
467
+ const attrs = serializeTrackedChangeAttributes(change.info) + serializeResolutionJoins(change.resolutionJoins);
433
468
  const disposition = tag === "del" || tag === "moveFrom" ? "removed" : "kept";
434
469
  const serializeContentRun = (run) => serializeInlineRun(run, disposition);
435
470
  const serializeWrappedItem = (item) => {
@@ -451,7 +486,7 @@ function serializeTrackedChange(tag, change) {
451
486
  case "moveFromRangeEnd": return `<w:moveFromRangeEnd ${markupRangeAttributes(item).join(" ")}/>`;
452
487
  case "moveToRangeStart": return serializeMoveRangeStart("moveToRangeStart", item);
453
488
  case "moveToRangeEnd": return `<w:moveToRangeEnd ${markupRangeAttributes(item).join(" ")}/>`;
454
- case "preservedInline": return item.xml;
489
+ case "preservedInline": return disposition === "removed" ? serializeRemovedPreservedInline(item) : item.xml;
455
490
  case "inlineWrapper":
456
491
  case "inlineSdt": return serializeParagraphContent(item, disposition);
457
492
  default: return item;
@@ -574,6 +609,8 @@ function serializeParagraph(paragraph) {
574
609
  if (paragraph.paraId) attrs.push(`w14:paraId="${escapeXmlAttribute(paragraph.paraId)}"`);
575
610
  if (paragraph.textId) attrs.push(`w14:textId="${escapeXmlAttribute(paragraph.textId)}"`);
576
611
  if (paragraph.reviewCarrier) attrs.push(`folio:reviewCarrier="${paragraph.reviewCarrier}"`);
612
+ const emptyMarkProperties = serializeEmptyMarkProperties(paragraph);
613
+ if (emptyMarkProperties !== void 0) attrs.push(emptyMarkProperties);
577
614
  const written = serializePreservedAttributes(attrs, paragraph.preservedAttributes);
578
615
  const attrsStr = written.length > 0 ? ` ${written.join(" ")}` : "";
579
616
  parts.push(serializeParagraphFormattingWithOptions(paragraph.formatting, {
@@ -1,3 +1,4 @@
1
+ import { FOLIO_REVIEW_HISTORY_NAMESPACE } from "../reviewHistoryNamespace.js";
1
2
  import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
2
3
  import { TaggedError } from "better-result";
3
4
  import { assertValidOoxmlNumericIds, escapeXmlAttribute } from "@stll/docx-core";
@@ -144,7 +145,7 @@ const OOXML_NAMESPACES = {
144
145
  ignorable: true
145
146
  },
146
147
  folio: {
147
- uri: "urn:stella:folio:review-history:1",
148
+ uri: FOLIO_REVIEW_HISTORY_NAMESPACE,
148
149
  ignorable: true
149
150
  },
150
151
  wpg: {
@@ -7,6 +7,7 @@ import { serializeGraphicFrameLocks } from "../graphicFrameLocks.js";
7
7
  import { DECORATIVE_EXTENSION_URI, DECORATIVE_NAMESPACE } from "../imageParser.js";
8
8
  import { canReplayEditableImageRawXml } from "../imageRawXml.js";
9
9
  import { serializeNonVisualDrawingNames } from "../nonVisualDrawingProps.js";
10
+ import { serializeBoundaryJoins } from "../reviewResolutionProvenance.js";
10
11
  import { runHoldsPayload } from "../runPayload.js";
11
12
  import { replayableShapeAlternateContent } from "../shapeAlternateContent.js";
12
13
  import { requiredWrapPolygon, serializeWrapPolygon } from "../wrapPolygon.js";
@@ -51,7 +52,7 @@ function getUniqueId(id) {
51
52
  }
52
53
  function serializeRunPropertyChange(change) {
53
54
  const previousRPrXml = serializeTextFormatting(change.previousFormatting) || "<w:rPr/>";
54
- return `<w:rPrChange ${serializeTrackedChangeAttributes(change.info)}>${previousRPrXml}</w:rPrChange>`;
55
+ return `<w:rPrChange ${serializeTrackedChangeAttributes(change.info)}${serializeBoundaryJoins(change.boundaryJoins)}>${previousRPrXml}</w:rPrChange>`;
55
56
  }
56
57
  function serializeRunProperties(formatting, propertyChanges) {
57
58
  const propertyChange = getSingularRunPropertyChange(propertyChanges);
@@ -537,6 +538,7 @@ function serializeRunContent(content) {
537
538
  case "symbol": return serializeSymbolContent(content);
538
539
  case "footnoteRef":
539
540
  case "endnoteRef": return serializeNoteReference(content);
541
+ case "noteMarker": return content.kind === "footnote" ? "<w:footnoteRef/>" : "<w:endnoteRef/>";
540
542
  case "fieldChar": return serializeFieldChar(content);
541
543
  case "instrText": return serializeInstrText(content);
542
544
  case "softHyphen": return serializeSoftHyphen(content);
@@ -0,0 +1,5 @@
1
+ //#region src/docx/settingsHeaderFooterUpdate.d.ts
2
+ /** Null means the source is malformed or outside the supported namespace profiles. */
3
+ declare const updateEvenAndOddHeaders: (xml: string, enabled: boolean | undefined) => string | null;
4
+ //#endregion
5
+ export { updateEvenAndOddHeaders };
@@ -0,0 +1,90 @@
1
+ import { spliceXml } from "./selectiveXmlPatch.js";
2
+ import { WORDPROCESSINGML_NAMESPACE_URIS, getChildElements, getLocalName, getNamespaceUri, parseXmlDocument } from "./xmlParser.js";
3
+ import { panic } from "better-result";
4
+ import { SETTINGS_CHILDREN } from "@stll/docx-core/schema";
5
+ //#region src/docx/settingsHeaderFooterUpdate.ts
6
+ /** Preserve producer settings while updating the document-wide header/footer switch. */
7
+ const XML_TOKEN = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<\?[\s\S]*?\?>|<(?:"[^"]*"|'[^']*'|[^'">])*>/gu;
8
+ const SETTINGS_CHILD_ORDINALS = new Map(SETTINGS_CHILDREN.map((name, index) => [name, index]));
9
+ const EVEN_AND_ODD_HEADERS_ORDER = SETTINGS_CHILD_ORDINALS.get("evenAndOddHeaders");
10
+ /** Null means the source is malformed or outside the supported namespace profiles. */
11
+ const updateEvenAndOddHeaders = (xml, enabled) => {
12
+ const root = parseXmlDocument(xml);
13
+ if (!root || getLocalName(root.name) !== "settings" || !WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(root) ?? "")) return null;
14
+ const children = getChildElements(root);
15
+ const spans = [];
16
+ const stack = [];
17
+ let childIndex = 0;
18
+ let childStart = -1;
19
+ let rootEnd = -1;
20
+ let rootOpenEnd = -1;
21
+ let selfClosingRootStart = -1;
22
+ let firstFollowingChildStart = -1;
23
+ if (EVEN_AND_ODD_HEADERS_ORDER === void 0) panic("Generated CT_Settings schema does not define evenAndOddHeaders");
24
+ for (const token of xml.matchAll(XML_TOKEN)) {
25
+ const tag = token[0];
26
+ if (tag.startsWith("<!") || tag.startsWith("<?")) continue;
27
+ const closing = tag.startsWith("</");
28
+ const name = tag.slice(closing ? 2 : 1).split(/[\s/>]/u).at(0);
29
+ if (!name) return null;
30
+ if (closing) {
31
+ if (stack.pop() !== name) return null;
32
+ if (stack.length === 1) {
33
+ const child = children[childIndex++];
34
+ if (!child || childStart < 0) return null;
35
+ if (getLocalName(child.name) === "evenAndOddHeaders" && WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(child) ?? "")) spans.push({
36
+ start: childStart,
37
+ end: token.index + tag.length,
38
+ newXml: ""
39
+ });
40
+ childStart = -1;
41
+ }
42
+ if (stack.length === 0) rootEnd = token.index;
43
+ continue;
44
+ }
45
+ if (stack.length === 0) {
46
+ rootOpenEnd = token.index + tag.length;
47
+ if (tag.endsWith("/>")) selfClosingRootStart = token.index;
48
+ }
49
+ if (stack.length === 1) {
50
+ const child = children[childIndex];
51
+ if (child?.name !== name) return null;
52
+ if (firstFollowingChildStart < 0 && WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(child) ?? "") && (SETTINGS_CHILD_ORDINALS.get(getLocalName(child.name)) ?? -1) > EVEN_AND_ODD_HEADERS_ORDER) firstFollowingChildStart = token.index;
53
+ childStart = token.index;
54
+ if (tag.endsWith("/>")) {
55
+ childIndex += 1;
56
+ if (getLocalName(child.name) === "evenAndOddHeaders" && WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(child) ?? "")) spans.push({
57
+ start: token.index,
58
+ end: token.index + tag.length,
59
+ newXml: ""
60
+ });
61
+ childStart = -1;
62
+ }
63
+ }
64
+ if (!tag.endsWith("/>")) stack.push(name);
65
+ }
66
+ if (stack.length !== 0 || childIndex !== children.length) return null;
67
+ const flag = enabled === void 0 ? "" : `<folioW:evenAndOddHeaders xmlns:folioW="${getNamespaceUri(root)}"${enabled ? "" : " folioW:val=\"0\""}/>`;
68
+ if (selfClosingRootStart >= 0) {
69
+ if (!flag) return xml;
70
+ return spliceXml(xml, [{
71
+ start: rootOpenEnd - 2,
72
+ end: rootOpenEnd,
73
+ newXml: `>${flag}</${root.name}>`
74
+ }]);
75
+ }
76
+ if (rootEnd < 0) return null;
77
+ const existingFlag = spans.at(0);
78
+ if (flag && existingFlag) existingFlag.newXml = flag;
79
+ else if (flag) {
80
+ const insertAt = firstFollowingChildStart >= 0 ? firstFollowingChildStart : rootEnd;
81
+ spans.push({
82
+ start: insertAt,
83
+ end: insertAt,
84
+ newXml: flag
85
+ });
86
+ }
87
+ return spliceXml(xml, spans);
88
+ };
89
+ //#endregion
90
+ export { updateEvenAndOddHeaders };
@@ -1,7 +1,6 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { DEFAULT_TAB_STOP_TWIPS } from "@stll/docx-core/model";
2
3
  //#region src/docx/settingsParser.d.ts
3
- /** OOXML default per §17.6.13 when `w:defaultTabStop` is absent. */
4
- declare const DEFAULT_TAB_STOP_TWIPS = 720;
5
4
  declare function parseSettings(xml: string | null): document_d_exports.DocumentSettings;
6
5
  //#endregion
7
6
  export { DEFAULT_TAB_STOP_TWIPS, parseSettings };
@@ -1,8 +1,7 @@
1
1
  import { parseEndnoteProperties } from "./notePropertiesParser.js";
2
2
  import { WORDPROCESSINGML_NAMESPACE_URIS, findChild, findChildByNamespaceUri, findChildren, getAttribute, parseBooleanElement, parseXmlDocument } from "./xmlParser.js";
3
+ import { DEFAULT_TAB_STOP_TWIPS, DEFAULT_TAB_STOP_TWIPS as DEFAULT_TAB_STOP_TWIPS$1 } from "@stll/docx-core/model";
3
4
  //#region src/docx/settingsParser.ts
4
- /** OOXML default per §17.6.13 when `w:defaultTabStop` is absent. */
5
- const DEFAULT_TAB_STOP_TWIPS = 720;
6
5
  /**
7
6
  * Sanity cap on `w:defaultTabStop`. Word's maximum margin is ~22 inches
8
7
  * (31 680 twips); anything past that is corruption or a hostile input and
@@ -111,13 +110,13 @@ function parseKinsokuOverride(root, name) {
111
110
  };
112
111
  }
113
112
  function parseDefaultTabStop(root) {
114
- if (!root) return 720;
113
+ if (!root) return DEFAULT_TAB_STOP_TWIPS$1;
115
114
  const el = findChild(root, "w", "defaultTabStop");
116
- if (!el) return 720;
115
+ if (!el) return DEFAULT_TAB_STOP_TWIPS$1;
117
116
  const raw = getAttribute(el, "w", "val");
118
- if (raw === null) return 720;
117
+ if (raw === null) return DEFAULT_TAB_STOP_TWIPS$1;
119
118
  const parsed = Number.parseInt(raw, 10);
120
- if (!Number.isFinite(parsed) || parsed < MIN_TAB_STOP_TWIPS || parsed > MAX_TAB_STOP_TWIPS) return 720;
119
+ if (!Number.isFinite(parsed) || parsed < MIN_TAB_STOP_TWIPS || parsed > MAX_TAB_STOP_TWIPS) return DEFAULT_TAB_STOP_TWIPS$1;
121
120
  return parsed;
122
121
  }
123
122
  //#endregion
@@ -0,0 +1,11 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ //#region src/docx/storyBlockReplay.d.ts
3
+ type StoryBlockReplayOptions = {
4
+ sourceXml: string;
5
+ baselineContent: readonly document_d_exports.BlockContent[];
6
+ currentContent: readonly document_d_exports.BlockContent[];
7
+ serializedXml: string;
8
+ };
9
+ declare const buildStoryBlockReplay: (options: StoryBlockReplayOptions) => string | null;
10
+ //#endregion
11
+ export { buildStoryBlockReplay };