@stll/folio-core 0.54.1 → 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 (251) hide show
  1. package/dist/ai-edits/apply.d.ts +1 -1
  2. package/dist/ai-edits/apply.js +40 -32
  3. package/dist/ai-edits/headless.d.ts +1 -2
  4. package/dist/ai-edits/headless.js +13 -27
  5. package/dist/ai-edits/read.d.ts +1 -0
  6. package/dist/ai-edits/read.js +7 -2
  7. package/dist/ai-edits/table-mutation-plan.d.ts +2 -1
  8. package/dist/ai-edits/table-mutation-plan.js +39 -1
  9. package/dist/ai-suggestions/apply.d.ts +1 -1
  10. package/dist/ai-suggestions/apply.js +3 -2
  11. package/dist/compare/compare.js +2 -1
  12. package/dist/compare/content-types.d.ts +3 -15
  13. package/dist/controller/canonicalComposition.d.ts +36 -0
  14. package/dist/controller/canonicalComposition.js +168 -0
  15. package/dist/controller/canonicalInput.d.ts +45 -0
  16. package/dist/controller/canonicalInput.js +338 -0
  17. package/dist/controller/canonicalOperations.d.ts +22 -0
  18. package/dist/controller/canonicalOperations.js +85 -0
  19. package/dist/controller/canonicalReview.d.ts +12 -0
  20. package/dist/controller/canonicalReview.js +19 -0
  21. package/dist/controller/canonicalSession.d.ts +149 -0
  22. package/dist/controller/canonicalSession.js +1038 -0
  23. package/dist/controller/canonicalStoryEditor.d.ts +34 -0
  24. package/dist/controller/canonicalStoryEditor.js +82 -0
  25. package/dist/controller/canonicalStructure.d.ts +16 -0
  26. package/dist/controller/canonicalStructure.js +269 -0
  27. package/dist/controller/folioEditor.d.ts +1 -1
  28. package/dist/controller/folioEditor.js +9 -0
  29. package/dist/controller/headerFooterEditorManager.d.ts +4 -0
  30. package/dist/controller/headerFooterEditorManager.js +71 -3
  31. package/dist/controller/hiddenEditorApi.d.ts +35 -0
  32. package/dist/controller/hiddenEditorApi.js +25 -8
  33. package/dist/controller/hiddenEditorManager.d.ts +11 -2
  34. package/dist/controller/hiddenEditorManager.js +456 -30
  35. package/dist/controller/layoutPipeline.d.ts +1 -1
  36. package/dist/controller/layoutPipeline.js +2 -0
  37. package/dist/controller/noteEditorManager.d.ts +4 -0
  38. package/dist/controller/noteEditorManager.js +113 -15
  39. package/dist/docx/attributeRemainder.js +1 -0
  40. package/dist/docx/bookmarkIds.d.ts +11 -0
  41. package/dist/docx/bookmarkIds.js +33 -0
  42. package/dist/docx/canonicalSessionInput.d.ts +11 -0
  43. package/dist/docx/canonicalSessionInput.js +27 -0
  44. package/dist/docx/canonicalStoryRepack.d.ts +10 -0
  45. package/dist/docx/canonicalStoryRepack.js +41 -0
  46. package/dist/docx/contentTypeRegistry.d.ts +8 -0
  47. package/dist/docx/contentTypeRegistry.js +64 -0
  48. package/dist/docx/documentParser.d.ts +14 -1
  49. package/dist/docx/documentParser.js +17 -4
  50. package/dist/docx/drawingIdNormalization.js +23 -8
  51. package/dist/docx/ensureParaIds.d.ts +12 -1
  52. package/dist/docx/ensureParaIds.js +173 -213
  53. package/dist/docx/foldedListNumberFields.d.ts +85 -0
  54. package/dist/docx/foldedListNumberFields.js +267 -0
  55. package/dist/docx/headerFooterVerbatim.d.ts +14 -1
  56. package/dist/docx/headerFooterVerbatim.js +95 -2
  57. package/dist/docx/listNumberingInstances.js +11 -9
  58. package/dist/docx/noteIds.d.ts +9 -0
  59. package/dist/docx/noteIds.js +17 -0
  60. package/dist/docx/noteReferenceMark.d.ts +3 -1
  61. package/dist/docx/noteReferenceMark.js +15 -14
  62. package/dist/docx/numberingIds.d.ts +14 -0
  63. package/dist/docx/numberingIds.js +16 -0
  64. package/dist/docx/numberingParser.d.ts +3 -1
  65. package/dist/docx/numberingParser.js +17 -3
  66. package/dist/docx/numericIdAllocator.d.ts +12 -0
  67. package/dist/docx/numericIdAllocator.js +33 -0
  68. package/dist/docx/numericIdNormalization.d.ts +16 -0
  69. package/dist/docx/numericIdNormalization.js +174 -0
  70. package/dist/docx/packageParts.d.ts +3 -1
  71. package/dist/docx/packageParts.js +65 -16
  72. package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
  73. package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
  74. package/dist/docx/paragraphParser.js +101 -53
  75. package/dist/docx/paragraphPropertySource.d.ts +15 -1
  76. package/dist/docx/paragraphPropertySource.js +76 -22
  77. package/dist/docx/paragraphTextBoxEnrichment.js +2 -1
  78. package/dist/docx/parser.js +19 -6
  79. package/dist/docx/rasterMime.d.ts +64 -0
  80. package/dist/docx/rasterMime.js +116 -0
  81. package/dist/docx/replyToComment.js +13 -6
  82. package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
  83. package/dist/docx/reviewHistoryNamespace.js +4 -0
  84. package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
  85. package/dist/docx/reviewResolutionProvenance.js +153 -0
  86. package/dist/docx/rezip.d.ts +7 -3
  87. package/dist/docx/rezip.js +121 -52
  88. package/dist/docx/runConsolidator.d.ts +2 -58
  89. package/dist/docx/runConsolidator.js +3 -175
  90. package/dist/docx/runParser.d.ts +2 -1
  91. package/dist/docx/runParser.js +156 -116
  92. package/dist/docx/saveDiagnostics.d.ts +11 -0
  93. package/dist/docx/saveDiagnostics.js +0 -0
  94. package/dist/docx/selectiveSave.d.ts +2 -1
  95. package/dist/docx/selectiveSave.js +14 -1
  96. package/dist/docx/selectiveXmlPatch.d.ts +16 -8
  97. package/dist/docx/selectiveXmlPatch.js +74 -2
  98. package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
  99. package/dist/docx/serializer/headerFooterSerializer.js +19 -11
  100. package/dist/docx/serializer/noteSerializer.d.ts +2 -2
  101. package/dist/docx/serializer/noteSerializer.js +24 -8
  102. package/dist/docx/serializer/paragraphSerializer.js +41 -4
  103. package/dist/docx/serializer/partNamespaces.js +6 -3
  104. package/dist/docx/serializer/runSerializer.js +8 -5
  105. package/dist/docx/serializer/trackedChangeAttributes.js +7 -1
  106. package/dist/docx/server/build.js +14 -3
  107. package/dist/docx/server/createBilingualDocument.js +10 -9
  108. package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
  109. package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
  110. package/dist/docx/settingsParser.d.ts +1 -2
  111. package/dist/docx/settingsParser.js +5 -6
  112. package/dist/docx/storyBlockReplay.d.ts +11 -0
  113. package/dist/docx/storyBlockReplay.js +367 -0
  114. package/dist/docx/streamingXmlParser.d.ts +31 -1
  115. package/dist/docx/streamingXmlParser.js +136 -21
  116. package/dist/docx/structuralXmlPatch.js +8 -1
  117. package/dist/docx/unzip.d.ts +3 -1
  118. package/dist/docx/unzip.js +36 -16
  119. package/dist/docx/verbatimCapture.d.ts +3 -1
  120. package/dist/docx/verbatimCapture.js +49 -6
  121. package/dist/i18n/messages/ar.gen.d.ts +5 -0
  122. package/dist/i18n/messages/ar.gen.js +656 -0
  123. package/dist/i18n/messages/cs.gen.d.ts +5 -0
  124. package/dist/i18n/messages/cs.gen.js +656 -0
  125. package/dist/i18n/messages/de.gen.d.ts +5 -0
  126. package/dist/i18n/messages/de.gen.js +656 -0
  127. package/dist/i18n/messages/en.gen.d.ts +5 -0
  128. package/dist/i18n/messages/en.gen.js +656 -0
  129. package/dist/i18n/messages/es.gen.d.ts +5 -0
  130. package/dist/i18n/messages/es.gen.js +656 -0
  131. package/dist/i18n/messages/et.gen.d.ts +5 -0
  132. package/dist/i18n/messages/et.gen.js +656 -0
  133. package/dist/i18n/messages/fr.gen.d.ts +5 -0
  134. package/dist/i18n/messages/fr.gen.js +656 -0
  135. package/dist/i18n/messages/he.gen.d.ts +5 -0
  136. package/dist/i18n/messages/he.gen.js +656 -0
  137. package/dist/i18n/messages/hi.gen.d.ts +5 -0
  138. package/dist/i18n/messages/hi.gen.js +656 -0
  139. package/dist/i18n/messages/hu.gen.d.ts +5 -0
  140. package/dist/i18n/messages/hu.gen.js +656 -0
  141. package/dist/i18n/messages/locales.d.ts +5 -0
  142. package/dist/i18n/messages/locales.js +22 -0
  143. package/dist/i18n/messages/lt.gen.d.ts +5 -0
  144. package/dist/i18n/messages/lt.gen.js +656 -0
  145. package/dist/i18n/messages/lv.gen.d.ts +5 -0
  146. package/dist/i18n/messages/lv.gen.js +656 -0
  147. package/dist/i18n/messages/pl.gen.d.ts +5 -0
  148. package/dist/i18n/messages/pl.gen.js +656 -0
  149. package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
  150. package/dist/i18n/messages/pt-BR.gen.js +656 -0
  151. package/dist/i18n/messages/sk.gen.d.ts +5 -0
  152. package/dist/i18n/messages/sk.gen.js +656 -0
  153. package/dist/i18n/messages/tr.gen.d.ts +5 -0
  154. package/dist/i18n/messages/tr.gen.js +656 -0
  155. package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
  156. package/dist/i18n/messages/zh-CN.gen.js +656 -0
  157. package/dist/i18n/messages.d.ts +2 -3
  158. package/dist/i18n/messages.js +1 -19
  159. package/dist/internal/noteMarkerAttrs.d.ts +8 -0
  160. package/dist/internal/noteMarkerAttrs.js +16 -0
  161. package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
  162. package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
  163. package/dist/internal/prosemirrorAttrBoundary.js +50 -0
  164. package/dist/layout-bridge/convert/fixedTableColumnWidths.d.ts +6 -0
  165. package/dist/layout-bridge/convert/fixedTableColumnWidths.js +23 -0
  166. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  167. package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
  168. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  169. package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
  170. package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
  171. package/dist/layout-bridge/convert/noteReferences.js +1 -6
  172. package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
  173. package/dist/layout-bridge/convert/tableConversion.js +4 -1
  174. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
  175. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
  176. package/dist/layout-painter/index.js +2 -5
  177. package/dist/managers/DocumentLoaderManager.d.ts +1 -0
  178. package/dist/managers/DocumentLoaderManager.js +8 -1
  179. package/dist/markdown/renderBlock.js +15 -1
  180. package/dist/markdown/renderParagraph.js +9 -13
  181. package/dist/markdown/renderRuns.js +3 -2
  182. package/dist/markdown/renderTable.js +2 -0
  183. package/dist/markdown/types.d.ts +3 -9
  184. package/dist/paged-layout/editorScrollRoot.d.ts +15 -0
  185. package/dist/paged-layout/editorScrollRoot.js +72 -0
  186. package/dist/paged-layout/scrollToPmPosition.js +8 -22
  187. package/dist/prosemirror/attrs/index.d.ts +2 -12
  188. package/dist/prosemirror/attrs/index.js +22 -48
  189. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
  190. package/dist/prosemirror/canonicalCommands.d.ts +97 -0
  191. package/dist/prosemirror/canonicalCommands.js +28 -0
  192. package/dist/prosemirror/commands/clearParagraphIndent.d.ts +6 -0
  193. package/dist/prosemirror/commands/clearParagraphIndent.js +25 -0
  194. package/dist/prosemirror/commands/pageBreak.js +15 -1
  195. package/dist/prosemirror/commentIdAllocator.d.ts +15 -22
  196. package/dist/prosemirror/commentIdAllocator.js +50 -25
  197. package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
  198. package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
  199. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
  200. package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
  201. package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -3
  202. package/dist/prosemirror/conversion/toProseDoc.js +51 -11
  203. package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
  204. package/dist/prosemirror/executeEditorCommand.js +26 -0
  205. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  206. package/dist/prosemirror/extensions/core/HistoryExtension.js +97 -5
  207. package/dist/prosemirror/extensions/core/ParagraphExtension.js +53 -20
  208. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +22 -28
  209. package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
  210. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
  211. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
  212. package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
  213. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  214. package/dist/prosemirror/extensions/marks/markUtils.js +70 -8
  215. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
  216. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
  217. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
  218. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +8 -6
  219. package/dist/prosemirror/listMarker.d.ts +1 -0
  220. package/dist/prosemirror/listMarker.js +16 -7
  221. package/dist/prosemirror/listNumbering.js +26 -5
  222. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  223. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  224. package/dist/prosemirror/markupViewNotes.js +3 -2
  225. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
  226. package/dist/prosemirror/noteReferenceReview.js +5 -3
  227. package/dist/prosemirror/plugins/revisionIds.d.ts +23 -19
  228. package/dist/prosemirror/plugins/revisionIds.js +110 -29
  229. package/dist/prosemirror/plugins/suggestionMode.d.ts +2 -2
  230. package/dist/prosemirror/plugins/suggestionMode.js +246 -42
  231. package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
  232. package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
  233. package/dist/prosemirror/runFormattingFromMarks.js +15 -1
  234. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
  235. package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
  236. package/dist/prosemirror/schema/marks.d.ts +2 -0
  237. package/dist/prosemirror/schema/nodes.d.ts +10 -2
  238. package/dist/prosemirror/storyListNumbering.js +11 -9
  239. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
  240. package/dist/prosemirror/textInput.d.ts +6 -1
  241. package/dist/prosemirror/textInput.js +14 -3
  242. package/dist/prosemirror/trackedRevisionPath.js +2 -1
  243. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
  244. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
  245. package/dist/prosemirror/utils/visualLineNavigation.js +6 -8
  246. package/dist/prosemirror/validation.js +4 -0
  247. package/dist/types/content.d.ts +2 -2
  248. package/dist/utils/createDocument.js +2 -2
  249. package/dist/utils/mergeDocumentContent.d.ts +2 -2
  250. package/dist/utils/mergeDocumentContent.js +11 -8
  251. package/package.json +14 -2
@@ -8,24 +8,26 @@ import { DANGLING_COMMENT_REFERENCE_WARNING, UNBALANCED_COMMENT_RANGE_WARNING, n
8
8
  import { detectDocxConformanceClass } from "./conformance.js";
9
9
  import { parseCoreProperties } from "./corePropertiesParser.js";
10
10
  import { countDanglingRelationshipReferences } from "./danglingRelationshipReferences.js";
11
- import { extractAllTemplateVariables, parseDocumentBody } from "./documentParser.js";
11
+ import { extractAllTemplateVariables, parseDocumentBody, parseDocumentBodyTree } from "./documentParser.js";
12
12
  import { normalizeDrawingIds } from "./drawingIdNormalization.js";
13
13
  import { DocxEncryptionError } from "./encryption/errors.js";
14
14
  import { parseFontTable } from "./fontTableParser.js";
15
15
  import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
16
16
  import { parseFooter, parseHeader } from "./headerFooterParser.js";
17
17
  import { DANGLING_FOOTER_REFERENCE_WARNING, DANGLING_HEADER_REFERENCE_WARNING, assignHeaderFooterRoles, normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
18
- import { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, refreshHeaderFooterVerbatimFingerprint } from "./headerFooterVerbatim.js";
18
+ import { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, captureHeaderFooterPackageBaselines, refreshHeaderFooterVerbatimFingerprint } from "./headerFooterVerbatim.js";
19
19
  import { extractMetafileRaster, isMetafileMimeType } from "./metafileRaster.js";
20
20
  import { renderEmfSvg } from "./metafileSvg.js";
21
21
  import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
22
22
  import { parseNumbering } from "./numberingParser.js";
23
23
  import { UNNUMBERED_PARAGRAPH_WARNING, UNNUMBERED_STYLE_WARNING, normalizeNumberingReferences, normalizeStyleNumberingReferences } from "./numberingReferenceNormalization.js";
24
+ import { normalizeRawDocxNumericIds } from "./numericIdNormalization.js";
24
25
  import { countOpaqueRevisionWrappers } from "./opaqueCarrier.js";
25
26
  import { assignDocumentParagraphPropertySourceContract } from "./paragraphPropertySource.js";
26
27
  import { createParseWarningCollector } from "./parseContext.js";
27
28
  import { formatParseWarnings } from "./parseWarningMessage.js";
28
29
  import { createPackagePreviewBudget } from "./previewBudget.js";
30
+ import { detectRasterMimeType } from "./rasterMime.js";
29
31
  import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
30
32
  import { normalizeRenderedPageBreakHints } from "./renderedPageBreakNormalization.js";
31
33
  import { parseSettings } from "./settingsParser.js";
@@ -33,7 +35,7 @@ import { parseStylesPackage } from "./styleParser.js";
33
35
  import { applyThemeFontLang, parseTheme } from "./themeParser.js";
34
36
  import { UNBALANCED_MOVE_RANGE_WARNING, normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
35
37
  import { getEntryUncompressedSize, getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
36
- import { getAttribute, getChildElements, getLocalName, parseXmlDocument } from "./xmlParser.js";
38
+ import { getAttribute, getChildElements, getLocalName, parseXml, parseXmlDocument } from "./xmlParser.js";
37
39
  import { FOLIO_XML_RESOURCE_LIMITS } from "./xmlResourceLimits.js";
38
40
  import { TaggedError, panic } from "better-result";
39
41
  import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
@@ -184,13 +186,14 @@ async function parseDocxWithPreviewBudget(input, options, previewBudget) {
184
186
  try {
185
187
  const timeStage = (_name, fn) => fn();
186
188
  const timeStageAsync = async (_name, fn) => await fn();
187
- const paragraphPropertySourceDigest = sha256Hex(buffer);
188
189
  onProgress("Extracting DOCX...", 0);
189
190
  const raw = await timeStageAsync("unzip", () => unzipDocx(buffer, {
190
191
  ...unzipLimits,
191
192
  password,
192
193
  extractAllXml: false
193
194
  }));
195
+ const repairedDocumentTree = await normalizeRawDocxNumericIds(raw);
196
+ const paragraphPropertySourceDigest = sha256Hex(raw.originalBuffer);
194
197
  if (raw.wasEncrypted) parseContext.warn({ code: PARSE_WARNING_CODES.packageDecrypted });
195
198
  for (const message of raw.warnings) parseContext.warn({
196
199
  code: PARSE_WARNING_CODES.packageArchive,
@@ -227,7 +230,16 @@ async function parseDocxWithPreviewBudget(input, options, previewBudget) {
227
230
  onProgress("Parsing document body...", 40);
228
231
  let documentBody = { content: [] };
229
232
  timeStage("documentBody", () => {
230
- if (raw.documentXml) documentBody = parseDocumentBody(raw.documentXml, styles, theme, numbering, rels, media, parseContext.scoped({ part: "word/document.xml" }), previews.ledger);
233
+ if (raw.documentXml) documentBody = parseDocumentBodyTree({
234
+ doc: repairedDocumentTree ?? parseXml(raw.documentXml),
235
+ styles,
236
+ theme,
237
+ numbering,
238
+ rels,
239
+ media,
240
+ context: parseContext.scoped({ part: "word/document.xml" }),
241
+ previews: previews.ledger
242
+ });
231
243
  else parseContext.warn({ code: PARSE_WARNING_CODES.documentPartMissing });
232
244
  });
233
245
  onProgress("Parsed document body", 55);
@@ -461,6 +473,7 @@ async function parseDocxWithPreviewBudget(input, options, previewBudget) {
461
473
  document.warnings = formatParseWarnings(parseWarnings);
462
474
  }
463
475
  onProgress("Complete", 100);
476
+ captureHeaderFooterPackageBaselines(document);
464
477
  return document;
465
478
  } catch (error) {
466
479
  if (error instanceof DocxEncryptionError) throw error;
@@ -507,7 +520,7 @@ async function buildMediaMap(raw, rels) {
507
520
  let remainingEmfPreviewBytes = MAX_PACKAGE_EMF_PREVIEW_BYTES;
508
521
  for (const [path, data] of raw.media.entries()) {
509
522
  const filename = path.split("/").pop() || path;
510
- const mimeType = getMediaMimeType(path);
523
+ const mimeType = detectRasterMimeType(data) ?? getMediaMimeType(path);
511
524
  const isReferenced = referenced.has(path.toLowerCase());
512
525
  if (isReferenced && isTiffMimeType(mimeType) && remainingTiffPixels > 0) {
513
526
  const converted = await convertTiffToPngDataUrl(data, remainingTiffPixels);
@@ -0,0 +1,64 @@
1
+ //#region src/docx/rasterMime.d.ts
2
+ declare const RASTER_SIGNATURES: readonly [{
3
+ readonly mimeType: "image/png";
4
+ readonly chunks: readonly [{
5
+ readonly offset: 0;
6
+ readonly bytes: readonly [137, 80, 78, 71];
7
+ }];
8
+ }, {
9
+ readonly mimeType: "image/jpeg";
10
+ readonly chunks: readonly [{
11
+ readonly offset: 0;
12
+ readonly bytes: readonly [255, 216];
13
+ }];
14
+ }, {
15
+ readonly mimeType: "image/gif";
16
+ readonly chunks: readonly [{
17
+ readonly offset: 0;
18
+ readonly bytes: readonly [71, 73, 70, 56];
19
+ }];
20
+ }, {
21
+ readonly mimeType: "image/bmp";
22
+ readonly chunks: readonly [{
23
+ readonly offset: 0;
24
+ readonly bytes: readonly [66, 77];
25
+ }];
26
+ }, {
27
+ readonly mimeType: "image/webp";
28
+ readonly chunks: readonly [{
29
+ readonly offset: 0;
30
+ readonly bytes: readonly [82, 73, 70, 70];
31
+ }, {
32
+ readonly offset: 8;
33
+ readonly bytes: readonly [87, 69, 66, 80];
34
+ }];
35
+ }, {
36
+ readonly mimeType: "image/tiff";
37
+ readonly chunks: readonly [{
38
+ readonly offset: 0;
39
+ readonly bytes: readonly [73, 73, 42, 0];
40
+ }];
41
+ }, {
42
+ readonly mimeType: "image/tiff";
43
+ readonly chunks: readonly [{
44
+ readonly offset: 0;
45
+ readonly bytes: readonly [77, 77, 0, 42];
46
+ }];
47
+ }, {
48
+ readonly mimeType: "image/tiff";
49
+ readonly chunks: readonly [{
50
+ readonly offset: 0;
51
+ readonly bytes: readonly [73, 73, 43, 0];
52
+ }];
53
+ }, {
54
+ readonly mimeType: "image/tiff";
55
+ readonly chunks: readonly [{
56
+ readonly offset: 0;
57
+ readonly bytes: readonly [77, 77, 0, 43];
58
+ }];
59
+ }];
60
+ type RasterMimeType = (typeof RASTER_SIGNATURES)[number]["mimeType"];
61
+ declare const RASTER_MIME_TYPES: ReadonlySet<string>;
62
+ declare const detectRasterMimeType: (data: ArrayBuffer) => RasterMimeType | undefined;
63
+ //#endregion
64
+ export { RASTER_MIME_TYPES, RasterMimeType, detectRasterMimeType };
@@ -0,0 +1,116 @@
1
+ //#region src/docx/rasterMime.ts
2
+ const RASTER_SIGNATURES = [
3
+ {
4
+ mimeType: "image/png",
5
+ chunks: [{
6
+ offset: 0,
7
+ bytes: [
8
+ 137,
9
+ 80,
10
+ 78,
11
+ 71
12
+ ]
13
+ }]
14
+ },
15
+ {
16
+ mimeType: "image/jpeg",
17
+ chunks: [{
18
+ offset: 0,
19
+ bytes: [255, 216]
20
+ }]
21
+ },
22
+ {
23
+ mimeType: "image/gif",
24
+ chunks: [{
25
+ offset: 0,
26
+ bytes: [
27
+ 71,
28
+ 73,
29
+ 70,
30
+ 56
31
+ ]
32
+ }]
33
+ },
34
+ {
35
+ mimeType: "image/bmp",
36
+ chunks: [{
37
+ offset: 0,
38
+ bytes: [66, 77]
39
+ }]
40
+ },
41
+ {
42
+ mimeType: "image/webp",
43
+ chunks: [{
44
+ offset: 0,
45
+ bytes: [
46
+ 82,
47
+ 73,
48
+ 70,
49
+ 70
50
+ ]
51
+ }, {
52
+ offset: 8,
53
+ bytes: [
54
+ 87,
55
+ 69,
56
+ 66,
57
+ 80
58
+ ]
59
+ }]
60
+ },
61
+ {
62
+ mimeType: "image/tiff",
63
+ chunks: [{
64
+ offset: 0,
65
+ bytes: [
66
+ 73,
67
+ 73,
68
+ 42,
69
+ 0
70
+ ]
71
+ }]
72
+ },
73
+ {
74
+ mimeType: "image/tiff",
75
+ chunks: [{
76
+ offset: 0,
77
+ bytes: [
78
+ 77,
79
+ 77,
80
+ 0,
81
+ 42
82
+ ]
83
+ }]
84
+ },
85
+ {
86
+ mimeType: "image/tiff",
87
+ chunks: [{
88
+ offset: 0,
89
+ bytes: [
90
+ 73,
91
+ 73,
92
+ 43,
93
+ 0
94
+ ]
95
+ }]
96
+ },
97
+ {
98
+ mimeType: "image/tiff",
99
+ chunks: [{
100
+ offset: 0,
101
+ bytes: [
102
+ 77,
103
+ 77,
104
+ 0,
105
+ 43
106
+ ]
107
+ }]
108
+ }
109
+ ];
110
+ const RASTER_MIME_TYPES = new Set(RASTER_SIGNATURES.map(({ mimeType }) => mimeType));
111
+ const detectRasterMimeType = (data) => {
112
+ const bytes = new Uint8Array(data);
113
+ return RASTER_SIGNATURES.find(({ chunks }) => chunks.every(({ offset, bytes: signature }) => signature.every((byte, index) => bytes[offset + index] === byte)))?.mimeType;
114
+ };
115
+ //#endregion
116
+ export { RASTER_MIME_TYPES, detectRasterMimeType };
@@ -1,10 +1,16 @@
1
+ import { allocateCommentId, seedCommentIdAbove } from "../prosemirror/commentIdAllocator.js";
1
2
  import { generateHexId } from "../utils/hexId.js";
2
3
  //#region src/docx/replyToComment.ts
3
- const nextCommentId = (comments) => {
4
- let max = 0;
5
- for (const comment of comments) if (comment.id > max) max = comment.id;
6
- return max + 1;
7
- };
4
+ /**
5
+ * Create a threaded reply to an existing comment.
6
+ *
7
+ * Produces a new `Comment` whose `parentId` points at the target comment and
8
+ * whose last paragraph carries a fresh `w14:paraId`, and guarantees the parent
9
+ * has a paraId too — the two ids Word uses to link a reply to its thread in
10
+ * `commentsExtended.xml` (`w15:paraId` / `w15:paraIdParent`). The reply's
11
+ * `document.xml` range markers are synthesized at save time by
12
+ * {@link applyReplyThreadMarkers}, so no anchor work is needed here.
13
+ */
8
14
  const usedParaIds = (comments) => {
9
15
  const ids = /* @__PURE__ */ new Set();
10
16
  for (const comment of comments) for (const paragraph of comment.content) if (paragraph.paraId) ids.add(paragraph.paraId.toUpperCase());
@@ -32,6 +38,7 @@ const createReply = (comments, parentCommentId, input) => {
32
38
  const threadRootId = parent.parentId ?? parent.id;
33
39
  const rootLastParagraph = ((comments.find((comment) => comment.id === threadRootId) ?? parent).content ?? []).at(-1);
34
40
  if (!rootLastParagraph) return null;
41
+ for (const { id } of comments) seedCommentIdAbove(id);
35
42
  const used = usedParaIds(comments);
36
43
  if (!rootLastParagraph.paraId) rootLastParagraph.paraId = freshParaId(used);
37
44
  const replyParagraph = {
@@ -48,7 +55,7 @@ const createReply = (comments, parentCommentId, input) => {
48
55
  }]
49
56
  };
50
57
  return {
51
- id: nextCommentId(comments),
58
+ id: allocateCommentId(),
52
59
  author: input.author,
53
60
  date: input.date ?? (/* @__PURE__ */ new Date()).toISOString(),
54
61
  parentId: threadRootId,
@@ -0,0 +1,4 @@
1
+ //#region src/docx/reviewHistoryNamespace.d.ts
2
+ declare const FOLIO_REVIEW_HISTORY_NAMESPACE = "urn:stella:folio:review-history:1";
3
+ //#endregion
4
+ export { FOLIO_REVIEW_HISTORY_NAMESPACE };
@@ -0,0 +1,4 @@
1
+ //#region src/docx/reviewHistoryNamespace.ts
2
+ const FOLIO_REVIEW_HISTORY_NAMESPACE = "urn:stella:folio:review-history:1";
3
+ //#endregion
4
+ export { FOLIO_REVIEW_HISTORY_NAMESPACE };
@@ -0,0 +1,25 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { XmlElement } from "./xmlParser.js";
3
+ //#region src/docx/reviewResolutionProvenance.d.ts
4
+ type ResolutionJoins = NonNullable<document_d_exports.Insertion["resolutionJoins"]>;
5
+ type BoundaryJoins = NonNullable<document_d_exports.RunPropertyChange["boundaryJoins"]>;
6
+ declare const isResolutionJoins: (value: unknown) => value is ResolutionJoins;
7
+ declare const isParagraphMarkResolutionJoin: (value: unknown) => value is NonNullable<document_d_exports.ParagraphMarkChange["resolutionJoin"]>;
8
+ declare const isBoundaryJoins: (value: unknown) => value is BoundaryJoins;
9
+ declare const ReviewResolutionProvenanceError_base: import("better-result").TaggedErrorClass<"ReviewResolutionProvenanceError">;
10
+ declare class ReviewResolutionProvenanceError extends ReviewResolutionProvenanceError_base<{
11
+ message: string;
12
+ attribute: string;
13
+ reason: "invalid" | "unsupportedVersion" | "unrepresentable";
14
+ }> {}
15
+ declare const parseResolutionJoins: (node: XmlElement) => ResolutionJoins | undefined;
16
+ declare const parseBoundaryJoins: (node: XmlElement) => BoundaryJoins | undefined;
17
+ declare const serializeResolutionJoins: (value: document_d_exports.Insertion["resolutionJoins"]) => string;
18
+ declare const serializeBoundaryJoins: (value: document_d_exports.RunPropertyChange["boundaryJoins"]) => string;
19
+ /** Null carries an owned undefined depth; a missing attribute carries no field. */
20
+ declare const parseParagraphMarkResolutionJoin: (node: XmlElement) => Pick<document_d_exports.ParagraphMarkChange, "resolutionJoin">;
21
+ declare const serializeParagraphMarkResolutionJoin: (mark: document_d_exports.ParagraphMarkChange) => string;
22
+ /** Captured paragraph properties compose the same envelope into a parsed XML element. */
23
+ declare const paragraphMarkResolutionJoinAttributes: (mark: document_d_exports.ParagraphMarkChange) => Record<string, string>;
24
+ //#endregion
25
+ export { ReviewResolutionProvenanceError, isBoundaryJoins, isParagraphMarkResolutionJoin, isResolutionJoins, paragraphMarkResolutionJoinAttributes, parseBoundaryJoins, parseParagraphMarkResolutionJoin, parseResolutionJoins, serializeBoundaryJoins, serializeParagraphMarkResolutionJoin, serializeResolutionJoins };
@@ -0,0 +1,153 @@
1
+ import { FOLIO_REVIEW_HISTORY_NAMESPACE } from "./reviewHistoryNamespace.js";
2
+ import { getAttributeByNamespaceUri } from "./xmlParser.js";
3
+ import { Result, TaggedError } from "better-result";
4
+ import { escapeXmlAttribute } from "@stll/docx-core";
5
+ import { MAX_REVISION_ID } from "@stll/docx-core/model";
6
+ //#region src/docx/reviewResolutionProvenance.ts
7
+ const NAMESPACES = /* @__PURE__ */ new Set([FOLIO_REVIEW_HISTORY_NAMESPACE]);
8
+ const VERSION = 1;
9
+ const MAX_ATTRIBUTE_LENGTH = 32768;
10
+ const SLOT_FIELDS = {
11
+ space: true,
12
+ id: true
13
+ };
14
+ const RETAINED_FIELDS = {
15
+ depth: true,
16
+ source: true,
17
+ target: true
18
+ };
19
+ const JOIN_FIELDS = {
20
+ before: true,
21
+ after: true,
22
+ remove: true,
23
+ retainedAfter: true,
24
+ deferredRemove: true,
25
+ acceptance: true
26
+ };
27
+ const ACCEPTANCE_POLICIES = { "merge-plain-runs": true };
28
+ const PARAGRAPH_MARK_FIELDS = {
29
+ kind: { type: "ooxml" },
30
+ info: { type: "ooxml" },
31
+ resolutionJoin: {
32
+ type: "private",
33
+ attribute: "resolutionJoin"
34
+ }
35
+ };
36
+ const DEFERRED_REMOVAL_FIELDS = {
37
+ depth: true,
38
+ blockers: true
39
+ };
40
+ const record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
41
+ const natural = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
42
+ const slots = (value) => Array.isArray(value) && value.every((slot) => record(slot) && Object.keys(slot).every((key) => Object.hasOwn(SLOT_FIELDS, key)) && (slot["space"] === "revision" || slot["space"] === "control") && natural(slot["id"]) && slot["id"] <= MAX_REVISION_ID);
43
+ const retained = (value) => Array.isArray(value) && value.every((item) => {
44
+ if (!record(item)) return false;
45
+ const source = item["source"];
46
+ const target = item["target"];
47
+ return Object.keys(item).every((key) => Object.hasOwn(RETAINED_FIELDS, key)) && natural(item["depth"]) && slots(source) && slots(target) && source.length === target.length && source.every((slot, index) => slot.space === target.at(index)?.space);
48
+ });
49
+ const deferredRemoval = (value) => {
50
+ if (!record(value) || Object.keys(value).some((key) => !Object.hasOwn(DEFERRED_REMOVAL_FIELDS, key))) return false;
51
+ const depth = value["depth"];
52
+ const blockers = value["blockers"];
53
+ return natural(depth) && depth <= MAX_REVISION_ID && Array.isArray(blockers) && blockers.length > 0 && !blockers.includes(void 0) && new Set(blockers).size === blockers.length && blockers.every((blocker) => natural(blocker) && blocker <= MAX_REVISION_ID);
54
+ };
55
+ const deferredRemovals = (value) => {
56
+ if (!Array.isArray(value) || value.length === 0 || value.includes(void 0) || !value.every(deferredRemoval)) return false;
57
+ const groups = value.map(({ depth, blockers }) => JSON.stringify({
58
+ depth,
59
+ blockers
60
+ }));
61
+ return new Set(groups).size === groups.length;
62
+ };
63
+ const isResolutionJoins = (value) => record(value) && Object.keys(value).every((key) => Object.hasOwn(JOIN_FIELDS, key)) && natural(value["before"]) && natural(value["after"]) && natural(value["remove"]) && (!Object.hasOwn(value, "acceptance") || typeof value["acceptance"] === "string" && Object.hasOwn(ACCEPTANCE_POLICIES, value["acceptance"])) && (value["retainedAfter"] === void 0 || retained(value["retainedAfter"])) && (!Object.hasOwn(value, "deferredRemove") || deferredRemovals(value["deferredRemove"]));
64
+ const isParagraphMarkResolutionJoin = (value) => natural(value) && value <= MAX_REVISION_ID;
65
+ const isEncodedParagraphMarkResolutionJoin = (value) => value === null || isParagraphMarkResolutionJoin(value);
66
+ const isBoundaryJoins = (value) => Array.isArray(value) && value.length <= 2 && new Set(value).size === value.length && value.every((side) => side === "before" || side === "after");
67
+ var ReviewResolutionProvenanceError = class extends TaggedError("ReviewResolutionProvenanceError") {};
68
+ const parseAttribute = ({ node, attribute, valid }) => {
69
+ const encoded = getAttributeByNamespaceUri(node, NAMESPACES, attribute);
70
+ if (encoded === null) return void 0;
71
+ const failed = (reason = "invalid") => new ReviewResolutionProvenanceError({
72
+ attribute,
73
+ message: `Invalid or unsupported ${attribute} review provenance.`,
74
+ reason
75
+ });
76
+ if (encoded.length > MAX_ATTRIBUTE_LENGTH) throw failed();
77
+ const parsed = Result.try({
78
+ try: () => JSON.parse(encoded),
79
+ catch: () => failed()
80
+ });
81
+ if (parsed.isErr()) throw parsed.error;
82
+ const decoded = parsed.value;
83
+ if (!record(decoded) || Object.keys(decoded).some((key) => key !== "version" && key !== "value")) throw failed();
84
+ const value = decoded["value"];
85
+ if (!valid(value)) throw failed();
86
+ if (decoded["version"] !== VERSION) throw failed("unsupportedVersion");
87
+ return value;
88
+ };
89
+ const encodeAttribute = ({ attribute, value, valid }) => {
90
+ if (value === void 0) return void 0;
91
+ if (!valid(value)) throw new ReviewResolutionProvenanceError({
92
+ attribute,
93
+ reason: "invalid",
94
+ message: `Invalid or oversized ${attribute} review provenance.`
95
+ });
96
+ const encoded = JSON.stringify({
97
+ version: VERSION,
98
+ value
99
+ });
100
+ if (encoded.length > MAX_ATTRIBUTE_LENGTH) throw new ReviewResolutionProvenanceError({
101
+ attribute,
102
+ reason: "invalid",
103
+ message: `Oversized ${attribute} review provenance.`
104
+ });
105
+ return encoded;
106
+ };
107
+ const serializeAttribute = (options) => {
108
+ const encoded = encodeAttribute(options);
109
+ return encoded === void 0 ? "" : ` folio:${options.attribute}="${escapeXmlAttribute(encoded)}"`;
110
+ };
111
+ const parseResolutionJoins = (node) => parseAttribute({
112
+ node,
113
+ attribute: "resolutionJoins",
114
+ valid: isResolutionJoins
115
+ });
116
+ const parseBoundaryJoins = (node) => parseAttribute({
117
+ node,
118
+ attribute: "boundaryJoins",
119
+ valid: isBoundaryJoins
120
+ });
121
+ const serializeResolutionJoins = (value) => serializeAttribute({
122
+ attribute: "resolutionJoins",
123
+ value,
124
+ valid: isResolutionJoins
125
+ });
126
+ const serializeBoundaryJoins = (value) => serializeAttribute({
127
+ attribute: "boundaryJoins",
128
+ value,
129
+ valid: isBoundaryJoins
130
+ });
131
+ /** Null carries an owned undefined depth; a missing attribute carries no field. */
132
+ const parseParagraphMarkResolutionJoin = (node) => {
133
+ const value = parseAttribute({
134
+ node,
135
+ attribute: PARAGRAPH_MARK_FIELDS.resolutionJoin.attribute,
136
+ valid: isEncodedParagraphMarkResolutionJoin
137
+ });
138
+ return value === void 0 ? {} : { resolutionJoin: value === null ? void 0 : value };
139
+ };
140
+ const paragraphMarkResolutionJoinOptions = (mark) => ({
141
+ attribute: PARAGRAPH_MARK_FIELDS.resolutionJoin.attribute,
142
+ value: Object.hasOwn(mark, "resolutionJoin") ? mark.resolutionJoin ?? null : void 0,
143
+ valid: isEncodedParagraphMarkResolutionJoin
144
+ });
145
+ const serializeParagraphMarkResolutionJoin = (mark) => serializeAttribute(paragraphMarkResolutionJoinOptions(mark));
146
+ /** Captured paragraph properties compose the same envelope into a parsed XML element. */
147
+ const paragraphMarkResolutionJoinAttributes = (mark) => {
148
+ const options = paragraphMarkResolutionJoinOptions(mark);
149
+ const encoded = encodeAttribute(options);
150
+ return encoded === void 0 ? {} : { [`folio:${options.attribute}`]: encoded };
151
+ };
152
+ //#endregion
153
+ export { ReviewResolutionProvenanceError, isBoundaryJoins, isParagraphMarkResolutionJoin, isResolutionJoins, paragraphMarkResolutionJoinAttributes, parseBoundaryJoins, parseParagraphMarkResolutionJoin, parseResolutionJoins, serializeBoundaryJoins, serializeParagraphMarkResolutionJoin, serializeResolutionJoins };
@@ -1,4 +1,5 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { SaveDiagnosticOptions } from "./saveDiagnostics.js";
2
3
  import { BlockContent, Hyperlink } from "../types/content.js";
3
4
  import { RawDocxContent } from "./unzip.js";
4
5
  import JSZip from "jszip";
@@ -46,7 +47,7 @@ declare const hasUnmaterializedInlineResources: (blocks: BlockContent[]) => bool
46
47
  /**
47
48
  * Options for repacking DOCX
48
49
  */
49
- type RepackOptions = {
50
+ type RepackOptions = SaveDiagnosticOptions & {
50
51
  /** Compression level (0-9, default: 6) */
51
52
  compressionLevel?: number;
52
53
  /** Whether to update modification date in docProps/core.xml */
@@ -185,7 +186,10 @@ declare function hasModelDrivenPictureWatermark(doc: document_d_exports.Document
185
186
  * `sourceZip` supplies each part as it stands before the save so the rebuilt
186
187
  * root can keep any prefix binding only the source document declared.
187
188
  */
188
- declare function collectHeaderFooterUpdates(doc: document_d_exports.Document, sourceZip: JSZip): Promise<Map<string, string>>;
189
+ type CollectHeaderFooterUpdatesOptions = SaveDiagnosticOptions & {
190
+ sourceZip: JSZip;
191
+ };
192
+ declare function collectHeaderFooterUpdates(doc: document_d_exports.Document, { sourceZip, onDiagnostic }: CollectHeaderFooterUpdatesOptions): Promise<Map<string, string>>;
189
193
  /** `word/Footnotes.xml` -> `word/_rels/Footnotes.xml.rels` (casing preserved). */
190
194
  declare function notePartRelsPath(partPath: string): string;
191
195
  /** Update existing core-property values without synthesizing absent metadata. */
@@ -219,7 +223,7 @@ declare function isDocxBuffer(buffer: ArrayBuffer): boolean;
219
223
  * ignored for a document that carries a source package, which keeps the
220
224
  * properties that package already states.
221
225
  */
222
- type DocumentPropertiesOptions = {
226
+ type DocumentPropertiesOptions = SaveDiagnosticOptions & {
223
227
  /** `dc:creator` in `docProps/core.xml`. Omitted when absent. */
224
228
  creator?: string;
225
229
  /** `Application` in `docProps/app.xml`. Omitted, with `AppVersion`, when absent. */