@stll/folio-core 0.59.0 → 0.61.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 (226) hide show
  1. package/README.md +23 -1
  2. package/dist/ai-edits/apply.js +139 -32
  3. package/dist/ai-edits/headless.d.ts +3 -0
  4. package/dist/ai-edits/headless.js +57 -63
  5. package/dist/ai-edits/note-story-inventory.d.ts +7 -0
  6. package/dist/ai-edits/note-story-inventory.js +11 -0
  7. package/dist/ai-edits/read.js +16 -9
  8. package/dist/ai-edits/revisionStretches.js +52 -1
  9. package/dist/ai-edits/table-row-column-mutations.js +6 -1
  10. package/dist/compare/reproducible-package.js +2 -1
  11. package/dist/compare/verification.js +1 -0
  12. package/dist/compat/eigenpal.d.ts +4 -2
  13. package/dist/compat/eigenpal.js +2 -2
  14. package/dist/controller/canonicalClipboard.js +2 -1
  15. package/dist/controller/canonicalListRendering.d.ts +4 -6
  16. package/dist/controller/canonicalListRendering.js +3 -157
  17. package/dist/controller/canonicalSession.js +3 -2
  18. package/dist/controller/canonicalStructure.js +10 -7
  19. package/dist/controller/fontReadiness.js +1 -1
  20. package/dist/controller/headerFooterEditorManager.d.ts +1 -0
  21. package/dist/controller/headerFooterEditorManager.js +11 -0
  22. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  23. package/dist/controller/hiddenEditorManager.js +3 -1
  24. package/dist/controller/layoutPipeline.d.ts +3 -1
  25. package/dist/controller/layoutPipeline.js +19 -4
  26. package/dist/controller/layoutSession.d.ts +4 -1
  27. package/dist/display-list/build/fontTable.js +7 -5
  28. package/dist/display-list/build/furniture.d.ts +1 -0
  29. package/dist/display-list/build/furniture.js +1 -0
  30. package/dist/display-list/build/imagePrimitives.js +3 -6
  31. package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
  32. package/dist/display-list/build/watermarkPrimitives.js +9 -3
  33. package/dist/display-list/editor/pageRenderer.js +1 -0
  34. package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
  35. package/dist/docx/bookmarkIdNormalization.js +100 -0
  36. package/dist/docx/bookmarkParser.js +4 -2
  37. package/dist/docx/canonicalStoryRepack.js +3 -2
  38. package/dist/docx/commentTextParagraph.d.ts +6 -0
  39. package/dist/docx/commentTextParagraph.js +15 -0
  40. package/dist/docx/conformance.js +6 -1
  41. package/dist/docx/diagramPreview.js +2 -1
  42. package/dist/docx/documentParser.d.ts +13 -1
  43. package/dist/docx/documentParser.js +1 -1
  44. package/dist/docx/encryption/compoundFile.d.ts +0 -8
  45. package/dist/docx/encryption/compoundFile.js +2 -1
  46. package/dist/docx/encryption/cryptoBytes.d.ts +2 -2
  47. package/dist/docx/encryption/cryptoBytes.js +3 -18
  48. package/dist/docx/encryption/encryptionInfo.d.ts +0 -5
  49. package/dist/docx/encryption/encryptionInfo.js +2 -1
  50. package/dist/docx/ensureParaIds.js +2 -1
  51. package/dist/docx/groupDrawingParser.js +6 -1
  52. package/dist/docx/importedIdCollisions.d.ts +136 -0
  53. package/dist/docx/importedIdCollisions.js +215 -0
  54. package/dist/docx/listModelNormalization.d.ts +10 -0
  55. package/dist/docx/listModelNormalization.js +166 -0
  56. package/dist/docx/metadataPrivacy.js +3 -2
  57. package/dist/docx/metafileRaster.js +2 -1
  58. package/dist/docx/numberingParser.js +2 -2
  59. package/dist/docx/packageParts.js +6 -5
  60. package/dist/docx/paragraphParser.js +6 -4
  61. package/dist/docx/paragraphPropertySource.js +1 -2
  62. package/dist/docx/parseContext.d.ts +2 -1
  63. package/dist/docx/parseContext.js +1 -0
  64. package/dist/docx/parseWarningMessage.js +1 -0
  65. package/dist/docx/parser.js +10 -5
  66. package/dist/docx/preservedRunContent.js +11 -2
  67. package/dist/docx/relsParser.js +1 -1
  68. package/dist/docx/removeHeaderFooterParts.js +8 -7
  69. package/dist/docx/replyToComment.js +3 -13
  70. package/dist/docx/rezip.js +90 -90
  71. package/dist/docx/runParser.js +12 -6
  72. package/dist/docx/runPropertyPresence.d.ts +11 -0
  73. package/dist/docx/runPropertyPresence.js +14 -0
  74. package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
  75. package/dist/docx/selectedXmlIdentityScan.js +36 -0
  76. package/dist/docx/selectiveSave.js +19 -17
  77. package/dist/docx/selectiveXmlPatch.js +44 -52
  78. package/dist/docx/serializer/commentSerializer.d.ts +3 -1
  79. package/dist/docx/serializer/commentSerializer.js +11 -2
  80. package/dist/docx/serializer/runSerializer.js +5 -4
  81. package/dist/docx/serializer/tableSerializer.js +2 -1
  82. package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
  83. package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
  84. package/dist/docx/server/applyDocxXmlPatchProposal.js +2 -2
  85. package/dist/docx/server/boundedArchive.js +2 -1
  86. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +2 -1
  87. package/dist/docx/server/inspectDocxPackage.js +5 -1
  88. package/dist/docx/server/validateDocxConformance.js +2 -1
  89. package/dist/docx/tableParser.js +7 -4
  90. package/dist/docx/tableRowPropertyPresence.d.ts +9 -0
  91. package/dist/docx/tableRowPropertyPresence.js +15 -0
  92. package/dist/docx/unzip.js +2 -1
  93. package/dist/docx/xmlEncoding.js +6 -5
  94. package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
  95. package/dist/fonts/embeddedFontFingerprint.js +18 -0
  96. package/dist/fonts/embeddedFonts.d.ts +1 -1
  97. package/dist/fonts/embeddedFonts.js +1 -1
  98. package/dist/fonts/fontsourceFaces.js +2 -1
  99. package/dist/fonts/headlessMeasure.js +0 -0
  100. package/dist/fonts/sfnt/parse.js +6 -9
  101. package/dist/fonts/sfnt/subset.js +2 -1
  102. package/dist/fonts/sfnt/tables.js +2 -3
  103. package/dist/fonts/sfnt/woff.js +2 -1
  104. package/dist/headless-layout.js +1 -0
  105. package/dist/index.d.ts +4 -2
  106. package/dist/index.js +2 -2
  107. package/dist/internal/revisionResolutionInline.d.ts +2 -1
  108. package/dist/internal/revisionResolutionInline.js +22 -1
  109. package/dist/internal/wholeStoryRevisionResolution.js +24 -7
  110. package/dist/layout-bridge/convert/flowConversionShared.d.ts +4 -0
  111. package/dist/layout-bridge/convert/footnoteLayout.d.ts +5 -1
  112. package/dist/layout-bridge/convert/footnoteLayout.js +16 -3
  113. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +6 -0
  114. package/dist/layout-bridge/convert/headerFooterLayout.js +13 -14
  115. package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
  116. package/dist/layout-bridge/convert/paragraphRuns.js +2 -1
  117. package/dist/layout-bridge/convert/toFlowBlocks.js +25 -1
  118. package/dist/layout-engine/measure/cache.js +39 -7
  119. package/dist/layout-engine/measure/crossRunWords.js +12 -2
  120. package/dist/layout-engine/measure/lineTypography.js +1 -0
  121. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  122. package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
  123. package/dist/layout-engine/measure/measureContainer.js +3 -4
  124. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
  125. package/dist/layout-engine/measure/measureHelpers.js +21 -18
  126. package/dist/layout-engine/measure/measureParagraph.js +2 -0
  127. package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
  128. package/dist/layout-engine/types.d.ts +4 -1
  129. package/dist/layout-painter/renderPage.d.ts +1 -0
  130. package/dist/layout-painter/renderPage.js +11 -3
  131. package/dist/layout-painter/renderParagraph.js +13 -3
  132. package/dist/layout-painter/renderWatermark.d.ts +1 -0
  133. package/dist/layout-painter/renderWatermark.js +7 -3
  134. package/dist/managers/AutoSaveManager.js +2 -1
  135. package/dist/managers/EditorModeManager.d.ts +10 -1
  136. package/dist/managers/EditorModeManager.js +15 -1
  137. package/dist/managers/TableSelectionManager.d.ts +1 -1
  138. package/dist/managers/autoSaveCodec.js +2 -6
  139. package/dist/managers/editorShortcuts.d.ts +2 -1
  140. package/dist/managers/editorShortcuts.js +2 -1
  141. package/dist/managers/reviewDisplayMode.d.ts +8 -0
  142. package/dist/managers/reviewDisplayMode.js +15 -0
  143. package/dist/paged-layout/pageText.d.ts +11 -2
  144. package/dist/paged-layout/pageText.js +8 -3
  145. package/dist/pdf/fonts.js +5 -14
  146. package/dist/pdf/images.js +3 -2
  147. package/dist/pdf/objects.d.ts +0 -11
  148. package/dist/pdf/objects.js +7 -9
  149. package/dist/pdf/writePdf.js +2 -1
  150. package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
  151. package/dist/prosemirror/canonicalSelectionRange.js +9 -3
  152. package/dist/prosemirror/commands/comments.js +51 -13
  153. package/dist/prosemirror/containerFinalParagraph.d.ts +8 -8
  154. package/dist/prosemirror/containerFinalParagraph.js +8 -8
  155. package/dist/prosemirror/conversion/fromProseDoc.js +9 -4
  156. package/dist/prosemirror/conversion/toProseDoc.js +4 -4
  157. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
  158. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
  159. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
  160. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
  161. package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
  162. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
  163. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
  164. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
  165. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
  166. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
  167. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
  168. package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
  169. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +16 -2
  170. package/dist/prosemirror/findReplaceSelection.d.ts +11 -1
  171. package/dist/prosemirror/findReplaceSelection.js +15 -1
  172. package/dist/prosemirror/markupViewProjection.d.ts +10 -1
  173. package/dist/prosemirror/markupViewProjection.js +21 -3
  174. package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
  175. package/dist/prosemirror/pluginKeyOwner.js +35 -0
  176. package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
  177. package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
  178. package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
  179. package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
  180. package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
  181. package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
  182. package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
  183. package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
  184. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
  185. package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
  186. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
  187. package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
  188. package/dist/prosemirror/plugins/documentNumbering.js +5 -3
  189. package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
  190. package/dist/prosemirror/plugins/documentStyleState.js +2 -2
  191. package/dist/prosemirror/plugins/documentStyles.js +1 -1
  192. package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
  193. package/dist/prosemirror/plugins/selectionTracker.js +4 -3
  194. package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
  195. package/dist/prosemirror/plugins/suggestionMode.js +4 -3
  196. package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
  197. package/dist/prosemirror/plugins/templateDirectives.js +19 -4
  198. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
  199. package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
  200. package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
  201. package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
  202. package/dist/prosemirror/plugins/transactionInvariants.js +29 -4
  203. package/dist/prosemirror/replacedAnnotations.d.ts +15 -1
  204. package/dist/prosemirror/replacedAnnotations.js +71 -12
  205. package/dist/prosemirror/runFormattingReconciliation.d.ts +3 -1
  206. package/dist/prosemirror/runFormattingReconciliation.js +10 -2
  207. package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +5 -7
  208. package/dist/prosemirror/runIdentityAcrossRevisions.js +66 -38
  209. package/dist/prosemirror/runPropertyChangeResolution.js +13 -1
  210. package/dist/utils/base64.d.ts +1 -31
  211. package/dist/utils/base64.js +19 -33
  212. package/dist/utils/clipboard.js +5 -4
  213. package/dist/utils/colorResolver.js +11 -2
  214. package/dist/utils/findReplace.d.ts +5 -0
  215. package/dist/utils/fontLoader.d.ts +2 -2
  216. package/dist/utils/fontLoader.js +2 -7
  217. package/dist/utils/fontResolver.d.ts +7 -3
  218. package/dist/utils/fontResolver.js +6 -8
  219. package/dist/utils/replaceText.js +21 -4
  220. package/dist/utils/sliceText.d.ts +2 -0
  221. package/dist/utils/sliceText.js +2 -0
  222. package/dist/utils/textEncoding.d.ts +2 -0
  223. package/dist/utils/textEncoding.js +2 -0
  224. package/dist/utils/tiffConverter.d.ts +0 -9
  225. package/dist/utils/tiffConverter.js +2 -4
  226. package/package.json +73 -31
@@ -5,7 +5,6 @@ import { parseParagraphProperties } from "./paragraphProperties.js";
5
5
  import { visitDocxParagraphs } from "./paragraphTraversal.js";
6
6
  import { parseXmlDocument } from "./xmlParser.js";
7
7
  import { TaggedError, panic } from "better-result";
8
- import { PluginKey } from "prosemirror-state";
9
8
  //#region src/docx/paragraphPropertySource.ts
10
9
  const paragraphPropertySourceEmissionFingerprint = Symbol("paragraphPropertySourceEmissionFingerprint");
11
10
  const paragraphPropertySourceIndentationBaseline = Symbol("paragraphPropertySourceIndentationBaseline");
@@ -793,7 +792,7 @@ const createProseParagraphWithPropertySource = (nodeType, sourceParagraph, optio
793
792
  linkProseParagraphPropertySource(paragraph, sourceParagraph);
794
793
  return paragraph;
795
794
  };
796
- const paragraphPropertySourceTransfersKey = new PluginKey("paragraphPropertySourceTransfers");
795
+ const paragraphPropertySourceTransfersKey = "stll.folio.meta.paragraphPropertySourceTransfers";
797
796
  /** Join adjacent paragraphs when revision semantics deliberately select the right owner. */
798
797
  const joinProseParagraphsWithRightPropertySource = ({ attrs, pos, transaction }) => {
799
798
  const $pos = transaction.doc.resolve(pos);
@@ -1,8 +1,9 @@
1
- import { ParseWarning, ParseWarningCode } from "@stll/docx-core/model";
1
+ import { ImportedIdCollisionKind, ParseWarning, ParseWarningCode } from "@stll/docx-core/model";
2
2
  //#region src/docx/parseContext.d.ts
3
3
  /** What a call site states; the collector supplies the rest. */
4
4
  type ParseWarningReport = {
5
5
  code: ParseWarningCode;
6
+ identityKind?: ImportedIdCollisionKind;
6
7
  /** The element as written, prefix included. */
7
8
  element?: string;
8
9
  /** The best position this part can name, e.g. `style "Heading1"`. */
@@ -30,6 +30,7 @@ const createParseWarningCollector = (part = PACKAGE_PART) => {
30
30
  retainedByCode.set(report.code, kept + 1);
31
31
  retained.push({
32
32
  code: report.code,
33
+ ...report.identityKind === void 0 ? {} : { identityKind: report.identityKind },
33
34
  location: {
34
35
  ...location,
35
36
  ...report.element === void 0 ? {} : { element: report.element },
@@ -22,6 +22,7 @@ const PARSE_WARNING_MESSAGES = {
22
22
  [PARSE_WARNING_CODES.documentPartMissing]: () => "No document.xml found in DOCX",
23
23
  [PARSE_WARNING_CODES.documentModelIssue]: (warning) => warning.detail ?? "The document model reported an issue.",
24
24
  [PARSE_WARNING_CODES.duplicateCommentId]: (warning) => `Dropped ${plural(warning.count, "comment")} repeating a w:id another comment already defines.`,
25
+ [PARSE_WARNING_CODES.duplicateImportedId]: (warning) => `Repeated imported identity${quoted(warning.value)}${where(warning)}: ${warning.detail ?? "multiple definitions share an identity."}`,
25
26
  [PARSE_WARNING_CODES.missingCommentId]: (warning) => `Dropped ${plural(warning.count, "comment")} with no readable w:id.`,
26
27
  [PARSE_WARNING_CODES.duplicateNoteId]: (warning) => `Dropped ${plural(warning.count, "note")} repeating a w:id another note already defines.`,
27
28
  [PARSE_WARNING_CODES.danglingCommentReference]: (warning) => `Removed ${plural(warning.count, "dangling comment reference marker")} whose comments.xml entries are missing.`,
@@ -1,7 +1,9 @@
1
1
  import { toArrayBuffer } from "../utils/docxInput.js";
2
2
  import { loadFontsWithMapping } from "../utils/fontLoader.js";
3
+ import { decodeText, encodeUtf8 } from "../utils/textEncoding.js";
3
4
  import { MAX_PACKAGE_TIFF_PIXELS, convertTiffToPngDataUrl, isTiffMimeType } from "../utils/tiffConverter.js";
4
5
  import { ALT_CHUNK_PLAIN_TEXT_LIMIT_BYTES, getAltChunkRelationshipId, isAltChunkMarkup } from "./altChunk.js";
6
+ import { normalizeBookmarkIdsInXmlParts } from "./bookmarkIdNormalization.js";
5
7
  import { DUPLICATE_COMMENT_ID_WARNING, normalizeCommentIds } from "./commentIdNormalization.js";
6
8
  import { parseComments } from "./commentParser.js";
7
9
  import { DANGLING_COMMENT_REFERENCE_WARNING, UNBALANCED_COMMENT_RANGE_WARNING, normalizeCommentReferences } from "./commentReferenceNormalization.js";
@@ -16,6 +18,7 @@ import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
16
18
  import { parseFooter, parseHeader } from "./headerFooterParser.js";
17
19
  import { DANGLING_FOOTER_REFERENCE_WARNING, DANGLING_HEADER_REFERENCE_WARNING, assignHeaderFooterRoles, normalizeHeaderFooterReferences } from "./headerFooterReferenceNormalization.js";
18
20
  import { assignHeaderFooterVerbatimXml, canReplayHeaderFooterVerbatim, captureDocumentSourceBaseline, captureHeaderFooterPackageBaselines, refreshHeaderFooterVerbatimFingerprint } from "./headerFooterVerbatim.js";
21
+ import { diagnoseImportedIdCollisions } from "./importedIdCollisions.js";
19
22
  import { extractMetafileRaster, isMetafileMimeType } from "./metafileRaster.js";
20
23
  import { renderEmfSvg } from "./metafileSvg.js";
21
24
  import { DocxModelValidationError, formatDocumentModelIssues, validateFolioDocumentModel } from "./modelValidation.js";
@@ -34,7 +37,7 @@ import { parseSettings } from "./settingsParser.js";
34
37
  import { parseStylesPackage } from "./styleParser.js";
35
38
  import { applyThemeFontLang, parseTheme } from "./themeParser.js";
36
39
  import { UNBALANCED_MOVE_RANGE_WARNING, normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
37
- import { getEntryUncompressedSize, getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
40
+ import { getEntryUncompressedSize, getMediaMimeType, mediaToDataUrl, replaceRawDocxXmlParts, unzipDocx } from "./unzip.js";
38
41
  import { getAttribute, getChildElements, getLocalName, parseXml, parseXmlDocument } from "./xmlParser.js";
39
42
  import { FOLIO_XML_RESOURCE_LIMITS } from "./xmlResourceLimits.js";
40
43
  import { TaggedError, panic } from "better-result";
@@ -120,7 +123,7 @@ const extractAltChunkPlainText = async (xml, context) => {
120
123
  if (bytes.byteLength > context.budget.remainingBytes) return;
121
124
  context.budget.remainingBytes -= bytes.byteLength;
122
125
  try {
123
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
126
+ return decodeText(bytes, { fatal: true });
124
127
  } catch {
125
128
  return;
126
129
  }
@@ -192,6 +195,8 @@ async function parseDocxWithPreviewBudget(input, options, previewBudget) {
192
195
  password,
193
196
  extractAllXml: false
194
197
  }));
198
+ diagnoseImportedIdCollisions(raw.allXml, parseContext);
199
+ await replaceRawDocxXmlParts(raw, normalizeBookmarkIdsInXmlParts(raw.allXml));
195
200
  const repairedDocumentTree = await normalizeRawDocxNumericIds(raw);
196
201
  const paragraphPropertySourceDigest = sha256Hex(raw.originalBuffer);
197
202
  if (raw.wasEncrypted) parseContext.warn({ code: PARSE_WARNING_CODES.packageDecrypted });
@@ -556,7 +561,7 @@ async function buildMediaMap(raw, rels) {
556
561
  }
557
562
  const emfSvg = isReferenced && mimeType === EMF_MIME_TYPE && remainingEmfPreviewBytes > 0 ? renderEmfSvg(data) : null;
558
563
  if (emfSvg) {
559
- const svgBytes = new TextEncoder().encode(emfSvg);
564
+ const svgBytes = encodeUtf8(emfSvg);
560
565
  if (svgBytes.byteLength <= remainingEmfPreviewBytes) {
561
566
  remainingEmfPreviewBytes -= svgBytes.byteLength;
562
567
  const mediaFile = {
@@ -585,8 +590,8 @@ async function buildMediaMap(raw, rels) {
585
590
  if (normalizedPath !== path) media.set(normalizedPath, mediaFile);
586
591
  }
587
592
  for (const [path, xml] of raw.allXml.entries()) {
588
- if (!/^word\/diagrams\/[^/]+\.xml$/iu.test(path) || new TextEncoder().encode(xml).byteLength > FOLIO_XML_RESOURCE_LIMITS.maxBytes) continue;
589
- const data = new TextEncoder().encode(xml).buffer;
593
+ if (!/^word\/diagrams\/[^/]+\.xml$/iu.test(path) || encodeUtf8(xml).byteLength > FOLIO_XML_RESOURCE_LIMITS.maxBytes) continue;
594
+ const data = encodeUtf8(xml).buffer;
590
595
  const file = {
591
596
  path,
592
597
  filename: path.split("/").pop() ?? path,
@@ -1,3 +1,4 @@
1
+ import { sliceText } from "../utils/sliceText.js";
1
2
  import { captureVerbatimXml } from "./verbatimCapture.js";
2
3
  import { findChildrenByLocalName, getChildElements, getLocalName, getTextContent } from "./xmlParser.js";
3
4
  //#region src/docx/preservedRunContent.ts
@@ -31,7 +32,11 @@ const preservedRunChildText = (element) => {
31
32
  if (sources === void 0) return "";
32
33
  const parts = [];
33
34
  for (const localName of sources) for (const source of findChildrenByLocalName(element, localName)) collectTextContent(source, parts);
34
- return parts.join("").slice(0, MAX_PRESERVED_TEXT_LENGTH);
35
+ return sliceText({
36
+ text: parts.join(""),
37
+ units: "codeUnits",
38
+ end: MAX_PRESERVED_TEXT_LENGTH
39
+ });
35
40
  };
36
41
  /**
37
42
  * Capture one unmodelled run child.
@@ -90,7 +95,11 @@ const preserveInlineChild = (element) => {
90
95
  return {
91
96
  type: "preservedInline",
92
97
  xml: captureVerbatimXml(element),
93
- text: parts.join("").slice(0, MAX_PRESERVED_TEXT_LENGTH)
98
+ text: sliceText({
99
+ text: parts.join(""),
100
+ units: "codeUnits",
101
+ end: MAX_PRESERVED_TEXT_LENGTH
102
+ })
94
103
  };
95
104
  };
96
105
  //#endregion
@@ -86,7 +86,7 @@ function parseRelationships(relsXml) {
86
86
  };
87
87
  if (targetMode === "External") relationship.targetMode = "External";
88
88
  else if (targetMode === "Internal") relationship.targetMode = "Internal";
89
- map.set(id, relationship);
89
+ if (!map.has(id)) map.set(id, relationship);
90
90
  }
91
91
  return map;
92
92
  }
@@ -1,3 +1,4 @@
1
+ import { decodeText, encodeUtf8 } from "../utils/textEncoding.js";
1
2
  import { isUnsafePackagePath } from "./packageParts.js";
2
3
  import { parseRelationships, resolveRelativePath } from "./relsParser.js";
3
4
  import { captureVerbatimXml } from "./verbatimCapture.js";
@@ -18,7 +19,7 @@ const removeResolvedHeaderFooterParts = async ({ document, zip, removedReference
18
19
  if (removedReferences.length === 0) return;
19
20
  const relsFile = zip.file(DOCUMENT_RELS_PATH);
20
21
  if (!relsFile) return panic("A resolved header/footer part has no document relationships");
21
- const relsXml = await relsFile.async("text");
22
+ const relsXml = await relsFile.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
22
23
  const relationships = parseRelationships(relsXml);
23
24
  const removedIds = /* @__PURE__ */ new Set();
24
25
  const candidates = /* @__PURE__ */ new Set();
@@ -39,7 +40,7 @@ const removeResolvedHeaderFooterParts = async ({ document, zip, removedReference
39
40
  }
40
41
  for (const file of Object.values(zip.files)) {
41
42
  if (file.dir || !file.name.endsWith(".rels") || file.name === DOCUMENT_RELS_PATH) continue;
42
- const otherRelationships = parseRelationships(await file.async("text"));
43
+ const otherRelationships = parseRelationships(await file.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true })));
43
44
  for (const relationship of otherRelationships.values()) if (relationship.targetMode !== "External") candidates.delete(resolveRelativePath(file.name, relationship.target));
44
45
  }
45
46
  const retiredMedia = /* @__PURE__ */ new Set();
@@ -48,7 +49,7 @@ const removeResolvedHeaderFooterParts = async ({ document, zip, removedReference
48
49
  const relsPath = `${path.slice(0, slash + 1)}_rels/${path.slice(slash + 1)}.rels`;
49
50
  const partRels = zip.file(relsPath);
50
51
  if (!partRels) continue;
51
- for (const relationship of parseRelationships(await partRels.async("text")).values()) {
52
+ for (const relationship of parseRelationships(await partRels.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }))).values()) {
52
53
  if (!officeRelationshipHasType(relationship.type, "image") || relationship.targetMode === "External") continue;
53
54
  const mediaPath = resolveRelativePath(relsPath, relationship.target);
54
55
  if (!isUnsafePackagePath(mediaPath) && mediaPath.startsWith("word/media/")) retiredMedia.add(mediaPath);
@@ -58,7 +59,7 @@ const removeResolvedHeaderFooterParts = async ({ document, zip, removedReference
58
59
  writeZipPart({
59
60
  zip,
60
61
  path: DOCUMENT_RELS_PATH,
61
- data: withoutChildren(relsXml, (child) => getNamespaceUri(child) === OOXML_NS.pr && getLocalName(child.name) === "Relationship" && removedIds.has(getAttribute(child, null, "Id") ?? "")),
62
+ data: encodeUtf8(withoutChildren(relsXml, (child) => getNamespaceUri(child) === OOXML_NS.pr && getLocalName(child.name) === "Relationship" && removedIds.has(getAttribute(child, null, "Id") ?? ""))),
62
63
  options: {
63
64
  compression: "DEFLATE",
64
65
  compressionOptions
@@ -75,7 +76,7 @@ const removeResolvedHeaderFooterParts = async ({ document, zip, removedReference
75
76
  }
76
77
  for (const file of Object.values(zip.files)) {
77
78
  if (file.dir || !file.name.endsWith(".rels")) continue;
78
- for (const relationship of parseRelationships(await file.async("text")).values()) if (relationship.targetMode !== "External") retiredMedia.delete(resolveRelativePath(file.name, relationship.target));
79
+ for (const relationship of parseRelationships(await file.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }))).values()) if (relationship.targetMode !== "External") retiredMedia.delete(resolveRelativePath(file.name, relationship.target));
79
80
  }
80
81
  for (const path of retiredMedia) {
81
82
  zip.remove(path);
@@ -83,11 +84,11 @@ const removeResolvedHeaderFooterParts = async ({ document, zip, removedReference
83
84
  }
84
85
  const contentTypes = zip.file("[Content_Types].xml");
85
86
  if (!contentTypes) return panic("The package has no content types");
86
- const contentTypesXml = await contentTypes.async("text");
87
+ const contentTypesXml = await contentTypes.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
87
88
  writeZipPart({
88
89
  zip,
89
90
  path: "[Content_Types].xml",
90
- data: withoutChildren(contentTypesXml, (child) => getNamespaceUri(child) === OOXML_NS.ct && getLocalName(child.name) === "Override" && candidates.has((getAttribute(child, null, "PartName") ?? "").replace(/^\//u, ""))),
91
+ data: encodeUtf8(withoutChildren(contentTypesXml, (child) => getNamespaceUri(child) === OOXML_NS.ct && getLocalName(child.name) === "Override" && candidates.has((getAttribute(child, null, "PartName") ?? "").replace(/^\//u, "")))),
91
92
  options: {
92
93
  compression: "DEFLATE",
93
94
  compressionOptions
@@ -1,5 +1,6 @@
1
1
  import { allocateCommentId, seedCommentIdAbove } from "../prosemirror/commentIdAllocator.js";
2
2
  import { generateHexId } from "../utils/hexId.js";
3
+ import { commentTextParagraph } from "./commentTextParagraph.js";
3
4
  //#region src/docx/replyToComment.ts
4
5
  /**
5
6
  * Create a threaded reply to an existing comment.
@@ -41,19 +42,8 @@ const createReply = (comments, parentCommentId, input) => {
41
42
  for (const { id } of comments) seedCommentIdAbove(id);
42
43
  const used = usedParaIds(comments);
43
44
  if (!rootLastParagraph.paraId) rootLastParagraph.paraId = freshParaId(used);
44
- const replyParagraph = {
45
- type: "paragraph",
46
- formatting: {},
47
- paraId: freshParaId(used),
48
- content: [{
49
- type: "run",
50
- formatting: {},
51
- content: [{
52
- type: "text",
53
- text: input.text
54
- }]
55
- }]
56
- };
45
+ const replyParagraph = commentTextParagraph(input.text);
46
+ replyParagraph.paraId = freshParaId(used);
57
47
  return {
58
48
  id: allocateCommentId(),
59
49
  author: input.author,