@stll/folio-core 0.44.0 → 0.46.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 (263) hide show
  1. package/dist/ai-edits/__fixtures__/paragraphs.js +2 -2
  2. package/dist/ai-edits/apply.js +59 -19
  3. package/dist/ai-edits/headless.js +2 -1
  4. package/dist/compare/compare.js +2 -5
  5. package/dist/compare/content-alignment.js +78 -53
  6. package/dist/compare/inline-atoms.js +34 -20
  7. package/dist/compare/scenario.js +2 -5
  8. package/dist/compare/types.d.ts +9 -1
  9. package/dist/compare/types.js +12 -1
  10. package/dist/compat/eigenpal.d.ts +2 -1
  11. package/dist/compat/eigenpal.js +2 -1
  12. package/dist/content-controls/checkboxDisplay.d.ts +11 -0
  13. package/dist/content-controls/checkboxDisplay.js +40 -0
  14. package/dist/content-controls/findContentControls.js +3 -1
  15. package/dist/content-controls/mutateContentControls.js +21 -4
  16. package/dist/controller/contentControlWidgetController.d.ts +1 -0
  17. package/dist/controller/contentControlWidgetController.js +3 -0
  18. package/dist/controller/hiddenEditorApi.js +3 -1
  19. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  20. package/dist/controller/hiddenEditorManager.js +6 -3
  21. package/dist/display-list/build/buildDisplayList.js +20 -1
  22. package/dist/display-list/build/imagePrimitives.d.ts +1 -1
  23. package/dist/display-list/build/imagePrimitives.js +3 -1
  24. package/dist/display-list/build/paragraphPrimitives.js +21 -2
  25. package/dist/display-list/dom/renderDisplayListToDom.js +18 -10
  26. package/dist/display-list/types.d.ts +17 -0
  27. package/dist/document-operations.js +14 -3
  28. package/dist/docx/attributeRemainder.d.ts +43 -0
  29. package/dist/docx/attributeRemainder.js +65 -0
  30. package/dist/docx/blockContentParser.d.ts +1 -1
  31. package/dist/docx/blockContentParser.js +87 -63
  32. package/dist/docx/blockPlainText.d.ts +3 -4
  33. package/dist/docx/blockPlainText.js +1 -0
  34. package/dist/docx/bookmarkPlacement.js +2 -0
  35. package/dist/docx/borderParser.js +5 -5
  36. package/dist/docx/commentAnchorIndex.d.ts +30 -0
  37. package/dist/docx/commentAnchorIndex.js +50 -0
  38. package/dist/docx/commentParser.d.ts +1 -1
  39. package/dist/docx/commentParser.js +78 -50
  40. package/dist/docx/commentRangeIntegrity.d.ts +16 -1
  41. package/dist/docx/commentRangeIntegrity.js +42 -1
  42. package/dist/docx/commentRangeJoin.d.ts +9 -0
  43. package/dist/docx/commentRangeJoin.js +33 -0
  44. package/dist/docx/commentReferenceCompletion.d.ts +9 -0
  45. package/dist/docx/commentReferenceCompletion.js +47 -0
  46. package/dist/docx/commentReferenceNormalization.js +1 -0
  47. package/dist/docx/commentReplyMarkers.js +11 -19
  48. package/dist/docx/commentThreadKey.d.ts +18 -0
  49. package/dist/docx/commentThreadKey.js +22 -0
  50. package/dist/docx/compatibility.js +1 -0
  51. package/dist/docx/containerChildren.d.ts +111 -0
  52. package/dist/docx/containerChildren.gen.d.ts +28 -0
  53. package/dist/docx/containerChildren.gen.js +246 -0
  54. package/dist/docx/containerChildren.js +103 -0
  55. package/dist/docx/diagramPreview.js +87 -27
  56. package/dist/docx/documentParser.d.ts +1 -1
  57. package/dist/docx/documentParser.js +3 -3
  58. package/dist/docx/ensureParaIds.js +17 -7
  59. package/dist/docx/fieldParser.d.ts +1 -1
  60. package/dist/docx/fieldParser.js +4 -4
  61. package/dist/docx/fieldState.d.ts +26 -0
  62. package/dist/docx/fieldState.js +53 -0
  63. package/dist/docx/footnoteParser.d.ts +1 -1
  64. package/dist/docx/graphicFrameLocks.d.ts +16 -4
  65. package/dist/docx/graphicFrameLocks.js +19 -6
  66. package/dist/docx/groupDrawingParser.js +3 -3
  67. package/dist/docx/headerFooterParser.js +1 -1
  68. package/dist/docx/headerFooterReferenceNormalization.js +1 -0
  69. package/dist/docx/hyperlinkParser.d.ts +27 -8
  70. package/dist/docx/hyperlinkParser.js +78 -20
  71. package/dist/docx/imageParser.d.ts +9 -1
  72. package/dist/docx/imageParser.js +91 -20
  73. package/dist/docx/imageRawXml.d.ts +14 -1
  74. package/dist/docx/imageRawXml.js +30 -6
  75. package/dist/docx/inlineWrapperContent.d.ts +85 -0
  76. package/dist/docx/inlineWrapperContent.js +84 -0
  77. package/dist/docx/mathToMathml.js +12 -14
  78. package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
  79. package/dist/docx/nonVisualDrawingProps.js +46 -0
  80. package/dist/docx/normalizeBaseDirection.js +10 -1
  81. package/dist/docx/paraIdAttribute.d.ts +21 -0
  82. package/dist/docx/paraIdAttribute.js +64 -0
  83. package/dist/docx/paragraphParser.d.ts +1 -1
  84. package/dist/docx/paragraphParser.js +277 -168
  85. package/dist/docx/paragraphPropertySource.js +5 -1
  86. package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
  87. package/dist/docx/paragraphTextBoxEnrichment.js +9 -52
  88. package/dist/docx/paragraphTraversal.js +7 -4
  89. package/dist/docx/parseWarningMessage.js +2 -1
  90. package/dist/docx/parser.js +2 -2
  91. package/dist/docx/preservedRunContent.d.ts +32 -0
  92. package/dist/docx/preservedRunContent.js +86 -0
  93. package/dist/docx/previewBudget.d.ts +64 -0
  94. package/dist/docx/previewBudget.js +88 -0
  95. package/dist/docx/renderedPageBreakNormalization.js +2 -4
  96. package/dist/docx/revisionIdNormalization.js +17 -5
  97. package/dist/docx/rezip.js +91 -36
  98. package/dist/docx/runParser.d.ts +1 -1
  99. package/dist/docx/runParser.js +16 -12
  100. package/dist/docx/sdtPropertiesPatch.js +24 -18
  101. package/dist/docx/sectionParser.js +8 -1
  102. package/dist/docx/sectionReferenceHistory.js +2 -2
  103. package/dist/docx/selectiveSave.js +6 -6
  104. package/dist/docx/selectiveXmlPatch.d.ts +46 -2
  105. package/dist/docx/selectiveXmlPatch.js +86 -39
  106. package/dist/docx/serializer/blockSdtSerializer.js +38 -26
  107. package/dist/docx/serializer/borderSerializer.d.ts +1 -1
  108. package/dist/docx/serializer/borderSerializer.js +15 -14
  109. package/dist/docx/serializer/commentSerializer.d.ts +41 -16
  110. package/dist/docx/serializer/commentSerializer.js +87 -92
  111. package/dist/docx/serializer/documentSerializer.js +8 -11
  112. package/dist/docx/serializer/fontTableSerializer.js +6 -6
  113. package/dist/docx/serializer/headerFooterSerializer.js +12 -14
  114. package/dist/docx/serializer/markupRangeAttributes.js +2 -2
  115. package/dist/docx/serializer/noteSerializer.js +8 -8
  116. package/dist/docx/serializer/numberingSerializer.js +7 -6
  117. package/dist/docx/serializer/paragraphSerializer.js +93 -72
  118. package/dist/docx/serializer/partNamespaces.js +2 -2
  119. package/dist/docx/serializer/runSerializer.js +73 -44
  120. package/dist/docx/serializer/sectionPropertiesSerializer.js +19 -14
  121. package/dist/docx/serializer/settingsSerializer.js +4 -3
  122. package/dist/docx/serializer/stylesSerializer.js +6 -6
  123. package/dist/docx/serializer/tableSerializer.js +28 -17
  124. package/dist/docx/serializer/textFormattingSerializer.js +29 -28
  125. package/dist/docx/serializer/themeSerializer.js +6 -6
  126. package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
  127. package/dist/docx/serializer/xmlUtils.d.ts +1 -2
  128. package/dist/docx/serializer/xmlUtils.js +1 -13
  129. package/dist/docx/server/boundedArchive.d.ts +12 -0
  130. package/dist/docx/server/boundedArchive.js +20 -1
  131. package/dist/docx/server/createBilingualDocument.js +3 -1
  132. package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
  133. package/dist/docx/server/materializeYjsDocx.js +9 -1
  134. package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
  135. package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
  136. package/dist/docx/server/validateDocxConformance.js +22 -1
  137. package/dist/docx/shapeParser.js +12 -10
  138. package/dist/docx/tableParser.d.ts +1 -1
  139. package/dist/docx/tableParser.js +206 -85
  140. package/dist/docx/textBoxParser.d.ts +25 -2
  141. package/dist/docx/textBoxParser.js +59 -4
  142. package/dist/docx/unzip.d.ts +23 -0
  143. package/dist/docx/unzip.js +37 -26
  144. package/dist/docx/verbatimCapture.js +1 -1
  145. package/dist/docx/vmlImageParser.d.ts +17 -1
  146. package/dist/docx/vmlImageParser.js +20 -3
  147. package/dist/docx/vmlPreview.d.ts +1 -3
  148. package/dist/docx/vmlPreview.js +2 -30
  149. package/dist/docx/xmlEncoding.d.ts +5 -0
  150. package/dist/docx/xmlEncoding.js +12 -0
  151. package/dist/docx/xmlParser.d.ts +26 -2
  152. package/dist/docx/xmlParser.js +70 -27
  153. package/dist/docx/xmlResourceLimits.d.ts +89 -9
  154. package/dist/docx/xmlResourceLimits.js +105 -24
  155. package/dist/headless-layout.js +10 -1
  156. package/dist/index.d.ts +2 -1
  157. package/dist/index.js +2 -1
  158. package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
  159. package/dist/internal/paragraphFormattingSerialization.js +3 -2
  160. package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
  161. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  162. package/dist/layout-engine/measure/tableCellFloating.js +2 -0
  163. package/dist/layout-engine/types.d.ts +23 -1
  164. package/dist/layout-painter/renderImage.d.ts +5 -1
  165. package/dist/layout-painter/renderImage.js +14 -6
  166. package/dist/layout-painter/renderPage.d.ts +2 -0
  167. package/dist/layout-painter/renderPage.js +4 -0
  168. package/dist/layout-painter/renderParagraph.d.ts +13 -1
  169. package/dist/layout-painter/renderParagraph.js +26 -6
  170. package/dist/managers/autoSaveCodec.d.ts +9 -1
  171. package/dist/managers/autoSaveCodec.js +14 -12
  172. package/dist/markdown/images.js +1 -4
  173. package/dist/markdown/renderBlock.js +1 -0
  174. package/dist/markdown/renderRuns.d.ts +1 -1
  175. package/dist/markdown/renderRuns.js +28 -5
  176. package/dist/markdown/renderTable.js +22 -5
  177. package/dist/markdown/trailers.js +4 -1
  178. package/dist/pdf/images.js +142 -6
  179. package/dist/prosemirror/attrs/index.d.ts +14 -3
  180. package/dist/prosemirror/attrs/index.js +224 -2
  181. package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
  182. package/dist/prosemirror/authoredTransformAttrs.js +64 -0
  183. package/dist/prosemirror/commands/contentControls.js +10 -2
  184. package/dist/prosemirror/commands/image.d.ts +9 -2
  185. package/dist/prosemirror/commands/image.js +43 -28
  186. package/dist/prosemirror/commands/pageBreak.js +1 -1
  187. package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
  188. package/dist/prosemirror/commentReferenceAttrs.js +33 -0
  189. package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
  190. package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
  191. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  192. package/dist/prosemirror/conversion/fromProseDoc.js +338 -99
  193. package/dist/prosemirror/conversion/index.d.ts +2 -2
  194. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
  195. package/dist/prosemirror/conversion/toProseDoc.js +551 -327
  196. package/dist/prosemirror/extensions/StarterKit.js +8 -58
  197. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  198. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
  199. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
  200. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
  201. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
  202. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
  203. package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
  204. package/dist/prosemirror/extensions/markRegistry.js +75 -0
  205. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
  206. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
  207. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
  208. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  209. package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
  210. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
  211. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
  212. package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
  213. package/dist/prosemirror/extensions/nodes/ImageExtension.js +20 -0
  214. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
  215. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
  216. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
  217. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
  218. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +10 -2
  219. package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
  220. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +13 -5
  221. package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
  222. package/dist/prosemirror/inlineWrapperStack.js +75 -0
  223. package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
  224. package/dist/prosemirror/pageBreakRunProjection.js +19 -9
  225. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +6 -3
  226. package/dist/prosemirror/paragraphFormattingProvenance.js +12 -3
  227. package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
  228. package/dist/prosemirror/replacedAnnotations.js +165 -0
  229. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
  230. package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
  231. package/dist/prosemirror/schema/index.d.ts +3 -3
  232. package/dist/prosemirror/schema/marks.d.ts +25 -1
  233. package/dist/prosemirror/schema/nodes.d.ts +139 -3
  234. package/dist/prosemirror/schema/nodes.js +16 -1
  235. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
  236. package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
  237. package/dist/prosemirror/validation.js +16 -2
  238. package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
  239. package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
  240. package/dist/prosemirror/zeroWidthAnchors.js +2 -0
  241. package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
  242. package/dist/render-dom/commentAnchorAttributes.js +54 -0
  243. package/dist/server.d.ts +3 -1
  244. package/dist/server.js +3 -1
  245. package/dist/types/content.d.ts +2 -2
  246. package/dist/utils/base64.d.ts +36 -0
  247. package/dist/utils/base64.js +40 -0
  248. package/dist/utils/clipboard.d.ts +9 -1
  249. package/dist/utils/clipboard.js +29 -2
  250. package/dist/utils/findReplace.js +1 -1
  251. package/dist/utils/imageLuminance.d.ts +15 -0
  252. package/dist/utils/imageLuminance.js +32 -0
  253. package/dist/utils/mergeDocumentContent.js +7 -17
  254. package/dist/utils/replaceText.js +1 -0
  255. package/dist/utils/units.d.ts +10 -1
  256. package/dist/utils/units.js +12 -1
  257. package/dist/utils/urlSecurity.d.ts +8 -2
  258. package/dist/utils/urlSecurity.js +21 -3
  259. package/package.json +2 -2
  260. package/dist/docx/blockRangeMarkers.d.ts +0 -36
  261. package/dist/docx/blockRangeMarkers.js +0 -59
  262. package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
  263. package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
@@ -262,10 +262,11 @@ const invalidTableCellParagraphSourcePayload = (classification, path) => {
262
262
  const tableCellBlockTraversalByType = {
263
263
  blockSdt: "blockSdt",
264
264
  paragraph: "paragraph",
265
+ preservedBlock: "leaf",
265
266
  table: "table"
266
267
  };
267
268
  const tableCellParagraphContentTraversalByType = {
268
- bidiWrapper: "content",
269
+ inlineWrapper: "content",
269
270
  bookmarkEnd: "leaf",
270
271
  bookmarkStart: "leaf",
271
272
  commentRangeEnd: "leaf",
@@ -283,6 +284,7 @@ const tableCellParagraphContentTraversalByType = {
283
284
  moveTo: "content",
284
285
  moveToRangeEnd: "leaf",
285
286
  moveToRangeStart: "leaf",
287
+ preservedInline: "leaf",
286
288
  run: "run",
287
289
  simpleField: "content"
288
290
  };
@@ -294,6 +296,7 @@ const tableCellRunContentTraversalByType = {
294
296
  footnoteRef: "leaf",
295
297
  instrText: "leaf",
296
298
  noBreakHyphen: "leaf",
299
+ preservedXml: "leaf",
297
300
  renderedPageBreak: "leaf",
298
301
  shape: "shape",
299
302
  softHyphen: "leaf",
@@ -453,6 +456,7 @@ function visitDecodedTableCellBlock(value, path, context) {
453
456
  for (const [index, child] of content.entries()) visitDecodedTableCellBlock(child, `${path}.content[${index}]`, context);
454
457
  return;
455
458
  }
459
+ case "leaf": return;
456
460
  default: return traversal;
457
461
  }
458
462
  }
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { NumberingMap } from "./numberingParser.js";
3
- import { StyleMap } from "./styleParser.js";
4
3
  import { XmlElement } from "./xmlParser.js";
4
+ import { StyleMap } from "./styleParser.js";
5
5
  import { TableParserFn } from "./textBoxParser.js";
6
6
  //#region src/docx/paragraphTextBoxEnrichment.d.ts
7
7
  declare const enrichParagraphTextBoxes: (paragraph: document_d_exports.Paragraph, paraXml: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, numbering: NumberingMap | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, parseTable: TableParserFn) => void;
@@ -1,6 +1,7 @@
1
1
  import { pixelsToEmu } from "../utils/units.js";
2
2
  import { parseParagraph } from "./paragraphParser.js";
3
- import { getTextBoxContentElement, isTextBoxDrawing, parseTextBox, parseTextBoxContent } from "./textBoxParser.js";
3
+ import { getTextBoxContentElement, parseTextBox, parseTextBoxContent, scanRunForTextBoxDrawings } from "./textBoxParser.js";
4
+ import { isVmlPictParsedByRunParser } from "./vmlImageParser.js";
4
5
  import { findDeep, getAttribute, getChildElements, getLocalName } from "./xmlParser.js";
5
6
  //#region src/docx/paragraphTextBoxEnrichment.ts
6
7
  const VML_HORIZONTAL_RELATIVES = /* @__PURE__ */ new Set([
@@ -182,7 +183,10 @@ const enrichTextBoxRuns = ({ content, xmlChildren, styles, theme, numbering, rel
182
183
  if (parsedIndex < content.length && parsedContent?.type !== "run") parsedIndex += 1;
183
184
  continue;
184
185
  }
185
- const { textBoxDrawings, vmlTextBoxes, hasNonTextBoxContent } = scanRunForTextBoxDrawings(xmlChild);
186
+ const { textBoxDrawings, vmlTextBoxes, hasNonTextBoxContent } = scanRunForTextBoxDrawings({
187
+ xmlRun: xmlChild,
188
+ claimedByRunParser: (pictElement) => isVmlPictParsedByRunParser(pictElement, rels, media)
189
+ });
186
190
  const parsedRun = parsedContent?.type === "run" ? parsedContent : void 0;
187
191
  const targetRun = parsedRun ?? (hasNonTextBoxContent ? lastConsumedRun : void 0);
188
192
  const targetRunMatchesXml = targetRun !== void 0 && (hasNonTextBoxContent || parsedRun?.content.length === 0);
@@ -198,6 +202,9 @@ const enrichTextBoxRuns = ({ content, xmlChildren, styles, theme, numbering, rel
198
202
  type: "shape",
199
203
  shapeType: "textBox",
200
204
  size: textBox.size,
205
+ ...textBox.name !== void 0 ? { name: textBox.name } : {},
206
+ ...textBox.alt !== void 0 ? { alt: textBox.alt } : {},
207
+ ...textBox.title !== void 0 ? { title: textBox.title } : {},
201
208
  ...textBox.position !== void 0 ? { position: textBox.position } : {},
202
209
  ...textBox.wrap !== void 0 ? { wrap: textBox.wrap } : {},
203
210
  ...textBox.fill !== void 0 ? { fill: textBox.fill } : {},
@@ -251,56 +258,6 @@ const enrichTextBoxRuns = ({ content, xmlChildren, styles, theme, numbering, rel
251
258
  }
252
259
  }
253
260
  };
254
- const scanRunForTextBoxDrawings = (xmlRun) => {
255
- const textBoxDrawings = [];
256
- const vmlTextBoxes = [];
257
- let hasNonTextBoxContent = false;
258
- const visitDrawing = (drawingEl) => {
259
- if (isTextBoxDrawing(drawingEl)) {
260
- textBoxDrawings.push(drawingEl);
261
- return;
262
- }
263
- hasNonTextBoxContent = true;
264
- };
265
- for (const el of getChildElements(xmlRun)) {
266
- const name = getLocalName(el.name ?? "");
267
- if (name === "rPr") continue;
268
- if (name === "drawing") {
269
- visitDrawing(el);
270
- continue;
271
- }
272
- if (name === "pict") {
273
- if (findDeep(el, "v", "textbox")) if (findDeep(el, "v", "imagedata")) hasNonTextBoxContent = true;
274
- else vmlTextBoxes.push(el);
275
- else hasNonTextBoxContent = true;
276
- continue;
277
- }
278
- if (name === "AlternateContent") {
279
- const branches = getChildElements(el);
280
- const choice = branches.find((branch) => getLocalName(branch.name ?? "") === "Choice");
281
- const fallback = branches.find((branch) => getLocalName(branch.name ?? "") === "Fallback");
282
- const tryBranch = (branch) => {
283
- if (!branch) return false;
284
- let found = false;
285
- for (const innerEl of getChildElements(branch)) if (getLocalName(innerEl.name ?? "") === "drawing") {
286
- visitDrawing(innerEl);
287
- found = true;
288
- }
289
- return found;
290
- };
291
- let foundInBranch = tryBranch(choice);
292
- if (!foundInBranch) foundInBranch = tryBranch(fallback);
293
- if (!foundInBranch) hasNonTextBoxContent = true;
294
- continue;
295
- }
296
- hasNonTextBoxContent = true;
297
- }
298
- return {
299
- textBoxDrawings,
300
- vmlTextBoxes,
301
- hasNonTextBoxContent
302
- };
303
- };
304
261
  const parseVmlTextBoxShape = (pictEl, styles, theme, numbering, rels, media, parseTable) => {
305
262
  const shapeEl = findDeep(pictEl, "v", "shape");
306
263
  const textBoxEl = shapeEl ? findDeep(shapeEl, "v", "textbox") : null;
@@ -16,7 +16,7 @@ const visitParagraphRuns = (paragraph, visit) => {
16
16
  case "moveFrom":
17
17
  case "moveTo":
18
18
  case "inlineSdt":
19
- case "bidiWrapper":
19
+ case "inlineWrapper":
20
20
  for (const child of content.content) visitParagraphContent(child);
21
21
  return;
22
22
  case "complexField":
@@ -32,7 +32,8 @@ const visitParagraphRuns = (paragraph, visit) => {
32
32
  case "moveFromRangeEnd":
33
33
  case "moveToRangeStart":
34
34
  case "moveToRangeEnd":
35
- case "mathEquation": return;
35
+ case "mathEquation":
36
+ case "preservedInline": return;
36
37
  default: return content;
37
38
  }
38
39
  };
@@ -69,7 +70,7 @@ const visitInlineContentSlots = (paragraph, visit) => {
69
70
  case "deletion":
70
71
  case "moveFrom":
71
72
  case "moveTo":
72
- case "bidiWrapper":
73
+ case "inlineWrapper":
73
74
  visitContent(item.content);
74
75
  break;
75
76
  case "run":
@@ -83,7 +84,8 @@ const visitInlineContentSlots = (paragraph, visit) => {
83
84
  case "moveFromRangeEnd":
84
85
  case "moveToRangeStart":
85
86
  case "moveToRangeEnd":
86
- case "mathEquation": break;
87
+ case "mathEquation":
88
+ case "preservedInline": break;
87
89
  default: panic(`Unsupported paragraph content: ${JSON.stringify(item)}`);
88
90
  }
89
91
  }
@@ -145,6 +147,7 @@ const visitDocxParagraphs = ({ documentBody, headers, footers, footnotes, endnot
145
147
  visitTable(block);
146
148
  return;
147
149
  }
150
+ if (block.type === "preservedBlock") return;
148
151
  visitBlocks(block.content);
149
152
  };
150
153
  const visitBlocks = (blocks) => {
@@ -36,7 +36,8 @@ const PARSE_WARNING_MESSAGES = {
36
36
  [PARSE_WARNING_CODES.unrecognisedOnOffValue]: (warning) => `Ignored on/off value${quoted(warning.value)}${where(warning)}; ST_OnOff is 1, 0, true, false, on or off.`,
37
37
  [PARSE_WARNING_CODES.borderWithoutValue]: (warning) => `Read a border with no w:val${where(warning)} as having no border style.`,
38
38
  [PARSE_WARNING_CODES.styleSetDuplicateStyleId]: (warning) => `Dropped a style repeating the id${quoted(warning.value)} another style in the set already defines.`,
39
- [PARSE_WARNING_CODES.styleSetInitialStyleMissing]: (warning) => `The style set names initial paragraph style${quoted(warning.value)}, which it does not contain; used the set's default instead${where(warning)}.`
39
+ [PARSE_WARNING_CODES.styleSetInitialStyleMissing]: (warning) => `The style set names initial paragraph style${quoted(warning.value)}, which it does not contain; used the set's default instead${where(warning)}.`,
40
+ [PARSE_WARNING_CODES.pageBreakProjectionApproximated]: (warning) => `${warning.detail ?? "An explicit page break is laid out approximately"}${where(warning)}.`
40
41
  };
41
42
  const formatParseWarning = (warning) => PARSE_WARNING_MESSAGES[warning.code](warning);
42
43
  const formatParseWarnings = (warnings) => warnings.map(formatParseWarning);
@@ -23,6 +23,7 @@ import { UNNUMBERED_PARAGRAPH_WARNING, UNNUMBERED_STYLE_WARNING, normalizeNumber
23
23
  import { assignDocumentParagraphPropertySourceContract } from "./paragraphPropertySource.js";
24
24
  import { createParseWarningCollector } from "./parseContext.js";
25
25
  import { formatParseWarnings } from "./parseWarningMessage.js";
26
+ import { enforcePackagePreviewBudget } from "./previewBudget.js";
26
27
  import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
27
28
  import { normalizeRenderedPageBreakHints } from "./renderedPageBreakNormalization.js";
28
29
  import { parseSettings } from "./settingsParser.js";
@@ -30,7 +31,6 @@ import { parseStylesPackage } from "./styleParser.js";
30
31
  import { applyThemeFontLang, parseTheme } from "./themeParser.js";
31
32
  import { UNBALANCED_MOVE_RANGE_WARNING, normalizeTrackedMoveRanges } from "./trackedMoveRangeNormalization.js";
32
33
  import { getMediaMimeType, mediaToDataUrl, unzipDocx } from "./unzip.js";
33
- import { enforcePackageVmlPreviewBudget } from "./vmlPreview.js";
34
34
  import { FOLIO_XML_RESOURCE_LIMITS } from "./xmlResourceLimits.js";
35
35
  import { TaggedError } from "better-result";
36
36
  import { PARSE_WARNING_CODES } from "@stll/docx-core/model";
@@ -281,7 +281,7 @@ async function parseDocx(input, options = {}) {
281
281
  ...requiredFonts.length > 0 ? { requiredFonts } : {}
282
282
  };
283
283
  assignDocumentParagraphPropertySourceContract(document, await paragraphPropertySourceDigest);
284
- enforcePackageVmlPreviewBudget(document.package);
284
+ enforcePackagePreviewBudget(document.package);
285
285
  const validation = validateFolioDocumentModel(document);
286
286
  const parsedCompleteModel = parseHeadersFooters && parseNotes;
287
287
  if (!validation.valid && parsedCompleteModel) throw new DocxModelValidationError("Parsed DOCX produced an invalid document model", validation.issues);
@@ -0,0 +1,32 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { XmlElement } from "./xmlParser.js";
3
+ //#region src/docx/preservedRunContent.d.ts
4
+ /**
5
+ * The visible text a preserved run child contributes, or `""` when it shows
6
+ * nothing. Unknown markup contributes nothing on purpose: guessing at the text
7
+ * of an element folio has never seen would put invented words in a document.
8
+ */
9
+ declare const preservedRunChildText: (element: XmlElement) => string;
10
+ /**
11
+ * Capture one unmodelled run child.
12
+ *
13
+ * `captureVerbatimXml` materialises exactly the namespace bindings the
14
+ * fragment's own prefixes need and leaves the canonical ones to the rebuilt
15
+ * root, so ordinary `w:` markup comes back byte for byte while a foreign
16
+ * prefix still arrives bound. Copying the whole root scope onto the fragment
17
+ * instead would rewrite every capture with declarations it does not use.
18
+ */
19
+ declare const preserveRunChild: (element: XmlElement) => document_d_exports.PreservedXmlContent;
20
+ /**
21
+ * One capture from the shared dispatcher's sink, as a member of the
22
+ * container's own inline union.
23
+ *
24
+ * The sink holds markup the schema does not declare for the container at all,
25
+ * so nothing is known about it beyond its bytes: `text` is empty because a
26
+ * name folio has never seen shows nothing folio can read.
27
+ */
28
+ declare const preservedInlineCapture: (xml: string) => document_d_exports.PreservedInline;
29
+ /** Capture one unmodelled inline child of a paragraph or an inline wrapper. */
30
+ declare const preserveInlineChild: (element: XmlElement) => document_d_exports.PreservedInline;
31
+ //#endregion
32
+ export { preserveInlineChild, preserveRunChild, preservedInlineCapture, preservedRunChildText };
@@ -0,0 +1,86 @@
1
+ import { captureVerbatimXml } from "./verbatimCapture.js";
2
+ import { findChildrenByLocalName, getChildElements, getLocalName, getTextContent } from "./xmlParser.js";
3
+ //#region src/docx/preservedRunContent.ts
4
+ /**
5
+ * Where a preserved run child hides text a reader sees, by local name: the
6
+ * child elements whose `w:t` descendants are on the line rather than above,
7
+ * beside, or nowhere.
8
+ *
9
+ * `w:ruby` is the whole list today. Its `w:rt` is the annotation printed above
10
+ * the base and is not the sentence's text; its `w:rubyBase` is.
11
+ */
12
+ const VISIBLE_TEXT_CHILDREN = /* @__PURE__ */ new Map([["ruby", ["rubyBase"]]]);
13
+ /** Cap on the text one preserved child contributes, mirroring `w:t` handling. */
14
+ const MAX_PRESERVED_TEXT_LENGTH = 1e5;
15
+ const collectTextContent = (element, into) => {
16
+ for (const child of getChildElements(element)) {
17
+ if (getLocalName(child.name) === "t") {
18
+ into.push(getTextContent(child));
19
+ continue;
20
+ }
21
+ collectTextContent(child, into);
22
+ }
23
+ };
24
+ /**
25
+ * The visible text a preserved run child contributes, or `""` when it shows
26
+ * nothing. Unknown markup contributes nothing on purpose: guessing at the text
27
+ * of an element folio has never seen would put invented words in a document.
28
+ */
29
+ const preservedRunChildText = (element) => {
30
+ const sources = VISIBLE_TEXT_CHILDREN.get(getLocalName(element.name));
31
+ if (sources === void 0) return "";
32
+ const parts = [];
33
+ 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
+ };
36
+ /**
37
+ * Capture one unmodelled run child.
38
+ *
39
+ * `captureVerbatimXml` materialises exactly the namespace bindings the
40
+ * fragment's own prefixes need and leaves the canonical ones to the rebuilt
41
+ * root, so ordinary `w:` markup comes back byte for byte while a foreign
42
+ * prefix still arrives bound. Copying the whole root scope onto the fragment
43
+ * instead would rewrite every capture with declarations it does not use.
44
+ */
45
+ const preserveRunChild = (element) => ({
46
+ type: "preservedXml",
47
+ xml: captureVerbatimXml(element),
48
+ text: preservedRunChildText(element)
49
+ });
50
+ /**
51
+ * Where an unmodelled *inline* child hides text a reader sees, by local name.
52
+ *
53
+ * `w:customXml` and `w:smartTag` are transparent wrappers (ECMA-376 §17.5.1,
54
+ * §17.5.1.9): their content is ordinary inline content, so their `w:t`
55
+ * descendants are on the line. Every other inline child folio captures —
56
+ * `w:permStart`, `w:proofErr` and the custom-XML revision ranges — is an
57
+ * empty marker, and an element folio has never seen contributes nothing on
58
+ * purpose, because guessing at its text would put invented words in a
59
+ * document.
60
+ */
61
+ const VISIBLE_TEXT_INLINE_CHILDREN = /* @__PURE__ */ new Set(["customXml", "smartTag"]);
62
+ /**
63
+ * One capture from the shared dispatcher's sink, as a member of the
64
+ * container's own inline union.
65
+ *
66
+ * The sink holds markup the schema does not declare for the container at all,
67
+ * so nothing is known about it beyond its bytes: `text` is empty because a
68
+ * name folio has never seen shows nothing folio can read.
69
+ */
70
+ const preservedInlineCapture = (xml) => ({
71
+ type: "preservedInline",
72
+ xml,
73
+ text: ""
74
+ });
75
+ /** Capture one unmodelled inline child of a paragraph or an inline wrapper. */
76
+ const preserveInlineChild = (element) => {
77
+ const parts = [];
78
+ if (VISIBLE_TEXT_INLINE_CHILDREN.has(getLocalName(element.name))) collectTextContent(element, parts);
79
+ return {
80
+ type: "preservedInline",
81
+ xml: captureVerbatimXml(element),
82
+ text: parts.join("").slice(0, MAX_PRESERVED_TEXT_LENGTH)
83
+ };
84
+ };
85
+ //#endregion
86
+ export { preserveInlineChild, preserveRunChild, preservedInlineCapture, preservedRunChildText };
@@ -0,0 +1,64 @@
1
+ //#region src/docx/previewBudget.d.ts
2
+ /**
3
+ * Every synthetic preview a parse attaches to the model, and the budget each
4
+ * one answers to.
5
+ *
6
+ * A preview is not document content. It is a drawing folio makes up so a shape
7
+ * it cannot project still occupies the page, and the package round-trips from
8
+ * its preserved XML whether the preview exists or not. So a preview is the one
9
+ * thing in the model that may be dropped, and a package that would retain more
10
+ * of it than it is worth has it dropped rather than being refused.
11
+ *
12
+ * Producer and budget have to agree on what a preview looks like. They used to
13
+ * agree by coincidence: the VML producer wrote its filename as a literal and
14
+ * the budget recognized it as a constant in another file, so renaming one
15
+ * would have stopped the other charging for it without anything failing. The
16
+ * table below is that agreement written once, and a producer builds its image
17
+ * out of the entry the budget matches against.
18
+ */
19
+ declare const VML_PREVIEW_DATA_URL_PREFIX = "data:image/svg+xml;charset=utf-8,";
20
+ declare const PREVIEW_KINDS: {
21
+ /** A VML shape folio renders rather than projects (`v:shape`, `v:rect`, ...). */
22
+ readonly vmlShape: {
23
+ readonly mimeType: "image/svg+xml";
24
+ readonly filename: "vml-shape-preview.svg";
25
+ readonly srcPrefix: "data:image/svg+xml;charset=utf-8,";
26
+ readonly maxPackageCharacters: number;
27
+ };
28
+ /**
29
+ * A SmartArt diagram: its extent filled with one flat rectangle per shape.
30
+ *
31
+ * A raster rather than a vector because the display list decodes only base64
32
+ * PNG and JPEG, so a vector preview would be missing from every display-list
33
+ * backend (PDF among them) while still showing in the DOM. That is what
34
+ * makes this preview expensive: one of them is 7.3 MB of data URL whatever
35
+ * the package weighs, because its cost follows the extent the author chose
36
+ * rather than anything the drawing contains.
37
+ *
38
+ * Across the public corpus, the fifty packages that produce one retain a
39
+ * median of 7.3 MB and a maximum of 51.3 MB (ten previews, from a package
40
+ * under a megabyte). The cap is set above that maximum: it refuses no
41
+ * legitimate file in the corpus while bounding what had no bound at all, and
42
+ * it is a ceiling rather than a fix. The fix is for the preview to be a
43
+ * descriptor the renderer rasterizes, which needs the display-list contract
44
+ * to carry one.
45
+ */
46
+ readonly smartArt: {
47
+ readonly mimeType: "image/png";
48
+ readonly filename: "smartart-preview.png";
49
+ readonly srcPrefix: "data:image/png;base64,";
50
+ readonly maxPackageCharacters: number;
51
+ };
52
+ };
53
+ type PreviewKindName = keyof typeof PREVIEW_KINDS;
54
+ /** Per-kind allowances for one package, defaulting to the table's caps. */
55
+ type PreviewBudgetOverrides = Partial<Record<PreviewKindName, number>>;
56
+ /**
57
+ * Charge every generated preview in the model against its kind's allowance and
58
+ * drop the `src` of those past it. Dropping leaves the image in place with its
59
+ * size and wrap, so the page still reserves the space the drawing occupies,
60
+ * and never touches the preserved XML the package saves from.
61
+ */
62
+ declare const enforcePackagePreviewBudget: (root: unknown, overrides?: PreviewBudgetOverrides) => void;
63
+ //#endregion
64
+ export { PREVIEW_KINDS, PreviewBudgetOverrides, VML_PREVIEW_DATA_URL_PREFIX, enforcePackagePreviewBudget };
@@ -0,0 +1,88 @@
1
+ //#region src/docx/previewBudget.ts
2
+ const VML_PREVIEW_DATA_URL_PREFIX = "data:image/svg+xml;charset=utf-8,";
3
+ const MEBIBYTE = 1024 * 1024;
4
+ const PREVIEW_KINDS = {
5
+ /** A VML shape folio renders rather than projects (`v:shape`, `v:rect`, ...). */
6
+ vmlShape: {
7
+ mimeType: "image/svg+xml",
8
+ filename: "vml-shape-preview.svg",
9
+ srcPrefix: VML_PREVIEW_DATA_URL_PREFIX,
10
+ maxPackageCharacters: 8 * MEBIBYTE
11
+ },
12
+ /**
13
+ * A SmartArt diagram: its extent filled with one flat rectangle per shape.
14
+ *
15
+ * A raster rather than a vector because the display list decodes only base64
16
+ * PNG and JPEG, so a vector preview would be missing from every display-list
17
+ * backend (PDF among them) while still showing in the DOM. That is what
18
+ * makes this preview expensive: one of them is 7.3 MB of data URL whatever
19
+ * the package weighs, because its cost follows the extent the author chose
20
+ * rather than anything the drawing contains.
21
+ *
22
+ * Across the public corpus, the fifty packages that produce one retain a
23
+ * median of 7.3 MB and a maximum of 51.3 MB (ten previews, from a package
24
+ * under a megabyte). The cap is set above that maximum: it refuses no
25
+ * legitimate file in the corpus while bounding what had no bound at all, and
26
+ * it is a ceiling rather than a fix. The fix is for the preview to be a
27
+ * descriptor the renderer rasterizes, which needs the display-list contract
28
+ * to carry one.
29
+ */
30
+ smartArt: {
31
+ mimeType: "image/png",
32
+ filename: "smartart-preview.png",
33
+ srcPrefix: "data:image/png;base64,",
34
+ maxPackageCharacters: 64 * MEBIBYTE
35
+ }
36
+ };
37
+ const KIND_NAMES = Object.keys(PREVIEW_KINDS);
38
+ /**
39
+ * The kind a model image was generated as, or `undefined` for one the package
40
+ * actually carries. A generated preview has no relationship behind it, so
41
+ * `rId` is empty; the filename and data-URL prefix name which producer made it.
42
+ */
43
+ const previewKindOf = (value) => {
44
+ if (!("type" in value) || value.type !== "image" || !("rId" in value) || value.rId !== "" || !("src" in value) || typeof value.src !== "string" || !("mimeType" in value) || !("filename" in value)) return;
45
+ const { src, mimeType, filename } = value;
46
+ return KIND_NAMES.find((name) => {
47
+ const kind = PREVIEW_KINDS[name];
48
+ return mimeType === kind.mimeType && filename === kind.filename && src.startsWith(kind.srcPrefix);
49
+ });
50
+ };
51
+ /**
52
+ * Charge every generated preview in the model against its kind's allowance and
53
+ * drop the `src` of those past it. Dropping leaves the image in place with its
54
+ * size and wrap, so the page still reserves the space the drawing occupies,
55
+ * and never touches the preserved XML the package saves from.
56
+ */
57
+ const enforcePackagePreviewBudget = (root, overrides = {}) => {
58
+ const remaining = new Map(KIND_NAMES.map((name) => [name, Math.max(0, overrides[name] ?? PREVIEW_KINDS[name].maxPackageCharacters)]));
59
+ const visited = /* @__PURE__ */ new WeakSet();
60
+ const visit = (value) => {
61
+ if (value === null || typeof value !== "object" || visited.has(value)) return;
62
+ visited.add(value);
63
+ if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return;
64
+ if (value instanceof Map) {
65
+ for (const child of value.values()) visit(child);
66
+ return;
67
+ }
68
+ if (Array.isArray(value)) {
69
+ for (const child of value) visit(child);
70
+ return;
71
+ }
72
+ const kind = previewKindOf(value);
73
+ if (kind !== void 0) {
74
+ const image = value;
75
+ const length = image.src.length;
76
+ const left = remaining.get(kind);
77
+ if (length <= left) remaining.set(kind, left - length);
78
+ else {
79
+ remaining.set(kind, 0);
80
+ delete image.src;
81
+ }
82
+ }
83
+ for (const child of Object.values(value)) visit(child);
84
+ };
85
+ visit(root);
86
+ };
87
+ //#endregion
88
+ export { PREVIEW_KINDS, VML_PREVIEW_DATA_URL_PREFIX, enforcePackagePreviewBudget };
@@ -37,9 +37,7 @@ const scanHyperlink = (hyperlink, scan) => {
37
37
  };
38
38
  const scanInlineContent = (content, scan) => {
39
39
  for (const child of content) {
40
- let result;
41
- if (child.type === "run") result = scanRun(child, scan);
42
- else if (child.type === "hyperlink") result = scanHyperlink(child, scan);
40
+ const result = scanParagraphContent(child, scan);
43
41
  if (result !== void 0) return result;
44
42
  }
45
43
  };
@@ -48,7 +46,7 @@ const scanParagraphContent = (content, scan) => {
48
46
  if (content.type === "hyperlink") return scanHyperlink(content, scan);
49
47
  if (content.type === "simpleField") return scanInlineContent(content.content, scan);
50
48
  if (content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo") return scanInlineContent(content.content, scan);
51
- if (content.type === "inlineSdt") {
49
+ if (content.type === "inlineSdt" || content.type === "inlineWrapper") {
52
50
  for (const child of content.content) {
53
51
  const result = scanParagraphContent(child, scan);
54
52
  if (result !== void 0) return result;
@@ -117,7 +117,10 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
117
117
  const occurrencesByPath = /* @__PURE__ */ new Map();
118
118
  const reserved = /* @__PURE__ */ new Set();
119
119
  for (const [path, xml] of candidates) {
120
- assertXmlResourceLimits(xml);
120
+ assertXmlResourceLimits({
121
+ xml,
122
+ partPath: path
123
+ });
121
124
  const ids = [];
122
125
  if (rewriteStreamingXmlDecimalAttributes(xml, (element) => {
123
126
  const identified = identifiedElement(element);
@@ -127,7 +130,9 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
127
130
  return null;
128
131
  }).status === "unsupported") throw new XmlResourceLimitError({
129
132
  message: `Revision-id normalization could not safely scan ${path}`,
130
- limit: "syntax"
133
+ limit: "syntax",
134
+ observed: 0,
135
+ allowed: 0
131
136
  });
132
137
  occurrencesByPath.set(path, ids);
133
138
  }
@@ -137,14 +142,19 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
137
142
  else firstSeen.add(id);
138
143
  if (repeatedPaths.size > 0) for (const [path, xml] of parts) {
139
144
  if (occurrencesByPath.has(path) || !ANNOTATION_ELEMENT_CANDIDATE.test(xml)) continue;
140
- assertXmlResourceLimits(xml);
145
+ assertXmlResourceLimits({
146
+ xml,
147
+ partPath: path
148
+ });
141
149
  if (rewriteStreamingXmlDecimalAttributes(xml, (element) => {
142
150
  const identified = identifiedElement(element);
143
151
  if (identified !== null) reserved.add(identified.id);
144
152
  return null;
145
153
  }).status === "unsupported") throw new XmlResourceLimitError({
146
154
  message: `Revision-id normalization could not safely scan ${path}`,
147
- limit: "syntax"
155
+ limit: "syntax",
156
+ observed: 0,
157
+ allowed: 0
148
158
  });
149
159
  }
150
160
  let nextId = 0;
@@ -185,7 +195,9 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
185
195
  });
186
196
  if (rewritten.status === "unsupported") throw new XmlResourceLimitError({
187
197
  message: `Revision-id normalization could not safely rewrite ${path}`,
188
- limit: "syntax"
198
+ limit: "syntax",
199
+ observed: 0,
200
+ allowed: 0
189
201
  });
190
202
  normalized.set(path, rewritten.value);
191
203
  }