@stll/folio-core 0.4.0 → 0.5.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 (99) hide show
  1. package/dist/ai-edits/apply.d.ts +3 -9
  2. package/dist/ai-edits/apply.js +94 -14
  3. package/dist/ai-edits/blockRange.d.ts +33 -0
  4. package/dist/ai-edits/blockRange.js +58 -0
  5. package/dist/ai-edits/headless.d.ts +33 -4
  6. package/dist/ai-edits/headless.js +83 -15
  7. package/dist/ai-edits/index.d.ts +5 -3
  8. package/dist/ai-edits/index.js +3 -2
  9. package/dist/ai-edits/snapshot.d.ts +14 -2
  10. package/dist/ai-edits/snapshot.js +12 -1
  11. package/dist/ai-edits/types.d.ts +42 -3
  12. package/dist/compat/eigenpal.d.ts +3 -2
  13. package/dist/compat/eigenpal.js +6 -5
  14. package/dist/controller/layoutPipeline.d.ts +1 -0
  15. package/dist/controller/layoutPipeline.js +35 -137
  16. package/dist/controller/layoutScheduler.d.ts +2 -1
  17. package/dist/controller/layoutScheduler.js +6 -0
  18. package/dist/document-operations.d.ts +122 -0
  19. package/dist/document-operations.js +575 -0
  20. package/dist/docx/blockContentParser.js +17 -7
  21. package/dist/docx/encryption/agileDecryption.js +2 -1
  22. package/dist/docx/encryption/compoundFile.js +4 -2
  23. package/dist/docx/footnoteParser.d.ts +1 -17
  24. package/dist/docx/footnoteParser.js +1 -27
  25. package/dist/docx/groupDrawingParser.d.ts +8 -0
  26. package/dist/docx/groupDrawingParser.js +131 -0
  27. package/dist/docx/numberingParser.d.ts +3 -1
  28. package/dist/docx/numberingParser.js +8 -2
  29. package/dist/docx/paragraphParser.js +9 -3
  30. package/dist/docx/runParser.js +8 -1
  31. package/dist/docx/selectiveXmlPatch.js +4 -10
  32. package/dist/docx/serializer/numberingSerializer.js +3 -1
  33. package/dist/docx/settingsParser.d.ts +6 -3
  34. package/dist/docx/settingsParser.js +2 -0
  35. package/dist/docx/xmlParser.js +11 -4
  36. package/dist/index.d.ts +3 -2
  37. package/dist/index.js +6 -5
  38. package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
  39. package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
  40. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -7
  41. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -7
  42. package/dist/layout-bridge/convert/toFlowBlocks.js +56 -19
  43. package/dist/layout-engine/index.d.ts +6 -5
  44. package/dist/layout-engine/index.js +89 -26
  45. package/dist/layout-engine/keep-together.d.ts +13 -8
  46. package/dist/layout-engine/keep-together.js +40 -25
  47. package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
  48. package/dist/layout-engine/layoutInstrumentation.js +10 -1
  49. package/dist/layout-engine/measure/measureBlocks.js +28 -18
  50. package/dist/layout-engine/measure/measureParagraph.js +61 -15
  51. package/dist/layout-engine/paginator.d.ts +2 -1
  52. package/dist/layout-engine/paginator.js +9 -3
  53. package/dist/layout-engine/textBoxGroup.d.ts +7 -0
  54. package/dist/layout-engine/textBoxGroup.js +8 -0
  55. package/dist/layout-engine/types.d.ts +30 -9
  56. package/dist/layout-engine/types.js +20 -2
  57. package/dist/layout-painter/renderPage.d.ts +15 -1
  58. package/dist/layout-painter/renderPage.js +27 -11
  59. package/dist/layout-painter/renderParagraph.js +18 -8
  60. package/dist/layout-painter/renderTable.js +10 -7
  61. package/dist/managers/DocumentLoaderManager.js +12 -5
  62. package/dist/managers/TableSelectionManager.js +1 -1
  63. package/dist/model.js +1 -1
  64. package/dist/paged-layout/pageText.d.ts +14 -0
  65. package/dist/paged-layout/pageText.js +21 -0
  66. package/dist/prosemirror/attrs/index.js +2 -0
  67. package/dist/prosemirror/commands/comments.js +75 -5
  68. package/dist/prosemirror/commands/hyperlink.js +4 -2
  69. package/dist/prosemirror/commands/image.js +2 -1
  70. package/dist/prosemirror/commands/index.js +1 -1
  71. package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
  72. package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
  73. package/dist/prosemirror/conversion/fromProseDoc.js +14 -3
  74. package/dist/prosemirror/conversion/toProseDoc.js +29 -8
  75. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
  76. package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
  77. package/dist/prosemirror/extensions/nodes/TableExtension.js +10 -11
  78. package/dist/prosemirror/findReplaceSelection.js +2 -1
  79. package/dist/prosemirror/index.js +1 -1
  80. package/dist/prosemirror/insertOperations.js +1 -1
  81. package/dist/prosemirror/schema/nodes.d.ts +10 -5
  82. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  83. package/dist/prosemirror/utils/tabCalculator.js +4 -2
  84. package/dist/redline.d.ts +20 -0
  85. package/dist/redline.js +127 -0
  86. package/dist/server.d.ts +7 -3
  87. package/dist/server.js +6 -2
  88. package/dist/symbols.d.ts +35 -0
  89. package/dist/symbols.js +512 -0
  90. package/dist/utils/clipboard.js +3 -3
  91. package/dist/utils/fontLoader.js +3 -0
  92. package/dist/utils/fontResolver.js +48 -1
  93. package/dist/utils/zoom.d.ts +21 -0
  94. package/dist/utils/zoom.js +21 -0
  95. package/dist/version-comparison.d.ts +92 -0
  96. package/dist/version-comparison.js +436 -0
  97. package/package.json +3 -3
  98. package/dist/paged-layout/headerFooterMargins.d.ts +0 -75
  99. package/dist/paged-layout/headerFooterMargins.js +0 -122
@@ -205,32 +205,6 @@ function isSeparatorEndnote(endnote) {
205
205
  return endnote.noteType === "separator" || endnote.noteType === "continuationSeparator" || endnote.noteType === "continuationNotice";
206
206
  }
207
207
  /**
208
- * Get footnote number for display (excluding separators)
209
- * @param footnote - The footnote to get the number for
210
- * @param footnoteMap - The footnote map
211
- * @param startNumber - Starting number (default 1)
212
- * @returns The display number, or null for separator footnotes
213
- */
214
- function getFootnoteDisplayNumber(footnote, footnoteMap, startNumber = 1) {
215
- if (isSeparatorFootnote(footnote)) return null;
216
- const index = footnoteMap.getNormalFootnotes().findIndex((fn) => fn.id === footnote.id);
217
- if (index === -1) return null;
218
- return startNumber + index;
219
- }
220
- /**
221
- * Get endnote number for display (excluding separators)
222
- * @param endnote - The endnote to get the number for
223
- * @param endnoteMap - The endnote map
224
- * @param startNumber - Starting number (default 1)
225
- * @returns The display number, or null for separator endnotes
226
- */
227
- function getEndnoteDisplayNumber(endnote, endnoteMap, startNumber = 1) {
228
- if (isSeparatorEndnote(endnote)) return null;
229
- const index = endnoteMap.getNormalEndnotes().findIndex((en) => en.id === endnote.id);
230
- if (index === -1) return null;
231
- return startNumber + index;
232
- }
233
- /**
234
208
  * Create an empty footnote map
235
209
  */
236
210
  function createEmptyFootnoteMap() {
@@ -267,4 +241,4 @@ function mergeEndnoteMaps(...maps) {
267
241
  return createEndnoteMap(byId, endnotes);
268
242
  }
269
243
  //#endregion
270
- export { createEmptyEndnoteMap, createEmptyFootnoteMap, getEndnoteDisplayNumber, getEndnoteText, getFootnoteDisplayNumber, getFootnoteText, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
244
+ export { createEmptyEndnoteMap, createEmptyFootnoteMap, getEndnoteText, getFootnoteText, isSeparatorEndnote, isSeparatorFootnote, mergeEndnoteMaps, mergeFootnoteMaps, parseEndnoteProperties, parseEndnotes, parseFootnoteProperties, parseFootnotes };
@@ -0,0 +1,8 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { XmlElement } from "./xmlParser.js";
3
+
4
+ //#region src/docx/groupDrawingParser.d.ts
5
+ /** Parse a WordprocessingGroup drawing into a safe SVG-backed image preview. */
6
+ declare const parseGroupDrawing: (drawing: XmlElement) => document_d_exports.Image | null;
7
+ //#endregion
8
+ export { parseGroupDrawing };
@@ -0,0 +1,131 @@
1
+ import { findAllDeep, findChildByLocalName, findChildrenByLocalName, getAttribute, getLocalName, getTextContent, parseNumericAttribute } from "./xmlParser.js";
2
+ import { emuToPixels } from "../utils/units.js";
3
+ import { parseImage } from "./imageParser.js";
4
+ //#region src/docx/groupDrawingParser.ts
5
+ const HEX_COLOR = /^[0-9A-Fa-f]{6}$/u;
6
+ const DEFAULT_TEXT_COLOR = "000000";
7
+ const DEFAULT_FONT_HALF_POINTS = 22;
8
+ const DEFAULT_LINE_WIDTH_EMU = 9525;
9
+ const HALF_POINT_TO_EMU = 6350;
10
+ const MAX_GROUP_SHAPES = 256;
11
+ const MAX_PATH_COMMANDS = 1e4;
12
+ const MAX_TEXT_CHARACTERS = 2e4;
13
+ const MAX_SVG_CHARACTERS = 1e6;
14
+ const escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
15
+ const numericAttr = (element, name) => {
16
+ const direct = parseNumericAttribute(element, null, name);
17
+ if (direct !== void 0) return direct;
18
+ const wordValue = getAttribute(element, "w", name);
19
+ if (!wordValue) return 0;
20
+ const parsed = Number.parseInt(wordValue, 10);
21
+ return Number.isNaN(parsed) ? 0 : parsed;
22
+ };
23
+ const childTransform = (wsp) => {
24
+ const xfrm = findChildByLocalName(findChildByLocalName(wsp, "spPr"), "xfrm");
25
+ const off = findChildByLocalName(xfrm, "off");
26
+ const ext = findChildByLocalName(xfrm, "ext");
27
+ return {
28
+ x: numericAttr(off, "x"),
29
+ y: numericAttr(off, "y"),
30
+ width: numericAttr(ext, "cx"),
31
+ height: numericAttr(ext, "cy")
32
+ };
33
+ };
34
+ const colorFrom = (parent, fallback) => {
35
+ if (parent && getLocalName(parent.name ?? "") === "color") {
36
+ const value = getAttribute(parent, "w", "val");
37
+ if (value && HEX_COLOR.test(value)) return value.toUpperCase();
38
+ }
39
+ const value = getAttribute(findChildByLocalName(findChildByLocalName(parent, "solidFill"), "srgbClr"), null, "val");
40
+ if (value && HEX_COLOR.test(value)) return value.toUpperCase();
41
+ return fallback;
42
+ };
43
+ const wrapLine = (line, maxCharacters) => {
44
+ const words = line.trim().split(/\s+/u);
45
+ const lines = [];
46
+ let current = "";
47
+ for (const word of words) {
48
+ const candidate = current ? `${current} ${word}` : word;
49
+ if (current && candidate.length > maxCharacters) {
50
+ lines.push(current);
51
+ current = word;
52
+ } else current = candidate;
53
+ }
54
+ if (current) lines.push(current);
55
+ return lines;
56
+ };
57
+ const pathData = (path) => {
58
+ const commands = [];
59
+ for (const command of path.elements ?? []) {
60
+ if (commands.length >= MAX_PATH_COMMANDS) break;
61
+ if (command.type !== "element") continue;
62
+ const point = findChildByLocalName(command, "pt");
63
+ const x = numericAttr(point, "x");
64
+ const y = numericAttr(point, "y");
65
+ const name = command.name?.split(":").at(-1);
66
+ if (name === "moveTo") commands.push(`M ${x} ${y}`);
67
+ else if (name === "lnTo") commands.push(`L ${x} ${y}`);
68
+ else if (name === "quadBezTo") {
69
+ const points = findChildrenByLocalName(command, "pt");
70
+ if (points.length >= 2) commands.push(`Q ${numericAttr(points[0] ?? null, "x")} ${numericAttr(points[0] ?? null, "y")} ${numericAttr(points[1] ?? null, "x")} ${numericAttr(points[1] ?? null, "y")}`);
71
+ } else if (name === "cubicBezTo") {
72
+ const points = findChildrenByLocalName(command, "pt");
73
+ if (points.length >= 3) commands.push(`C ${numericAttr(points[0] ?? null, "x")} ${numericAttr(points[0] ?? null, "y")} ${numericAttr(points[1] ?? null, "x")} ${numericAttr(points[1] ?? null, "y")} ${numericAttr(points[2] ?? null, "x")} ${numericAttr(points[2] ?? null, "y")}`);
74
+ } else if (name === "close") commands.push("Z");
75
+ }
76
+ return commands.join(" ");
77
+ };
78
+ const renderGeometry = (wsp) => {
79
+ const { x, y, width, height } = childTransform(wsp);
80
+ if (width <= 0 || height <= 0) return "";
81
+ const spPr = findChildByLocalName(wsp, "spPr");
82
+ const fill = colorFrom(spPr, "none");
83
+ const line = findChildByLocalName(spPr, "ln");
84
+ const stroke = colorFrom(line, "none");
85
+ const strokeWidth = line ? parseNumericAttribute(line, null, "w") ?? DEFAULT_LINE_WIDTH_EMU : 0;
86
+ const paths = findAllDeep(findChildByLocalName(spPr, "custGeom"), "a", "path");
87
+ if (paths.length === 0) return `<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="${fill === "none" ? "none" : `#${fill}`}" stroke="${stroke === "none" ? "none" : `#${stroke}`}" stroke-width="${strokeWidth}"/>`;
88
+ return paths.map((path) => {
89
+ const viewWidth = numericAttr(path, "w") || width;
90
+ const viewHeight = numericAttr(path, "h") || height;
91
+ const d = pathData(path);
92
+ if (!d) return "";
93
+ return `<path d="${d}" transform="translate(${x} ${y}) scale(${width / viewWidth} ${height / viewHeight})" fill="${fill === "none" ? "none" : `#${fill}`}" stroke="${stroke === "none" ? "none" : `#${stroke}`}" stroke-width="${strokeWidth}"/>`;
94
+ }).join("");
95
+ };
96
+ const renderTextBox = (wsp) => {
97
+ const { x, y, width, height } = childTransform(wsp);
98
+ if (width <= 0 || height <= 0) return "";
99
+ const paragraphs = findAllDeep(wsp, "w", "p");
100
+ const firstSize = findAllDeep(wsp, "w", "sz").at(0);
101
+ const halfPoints = numericAttr(firstSize ?? null, "val") || DEFAULT_FONT_HALF_POINTS;
102
+ const color = colorFrom(findAllDeep(wsp, "w", "color").at(0) ?? null, DEFAULT_TEXT_COLOR);
103
+ const fontSize = halfPoints * HALF_POINT_TO_EMU;
104
+ const maxCharacters = Math.max(1, Math.floor(width / (fontSize * .38)));
105
+ const lines = paragraphs.flatMap((paragraph) => wrapLine(getTextContent(paragraph).slice(0, MAX_TEXT_CHARACTERS), maxCharacters)).map(escapeXml);
106
+ if (lines.length === 0) return "";
107
+ const lineHeight = fontSize * 1.15;
108
+ const svgFontSize = 1e3;
109
+ const scale = fontSize / svgFontSize;
110
+ const lineStep = lineHeight / fontSize * svgFontSize;
111
+ return `<text x="0" y="${svgFontSize}" transform="translate(${x} ${y}) scale(${scale})" font-family="Arial, sans-serif" font-size="${svgFontSize}" fill="#${color}">${lines.map((line, index) => `<tspan x="0" dy="${index === 0 ? 0 : lineStep}">${line}</tspan>`).join("")}</text>`;
112
+ };
113
+ const createSvg = (group, width, height) => {
114
+ const content = findChildrenByLocalName(group, "wsp").slice(0, MAX_GROUP_SHAPES).map((wsp) => findChildByLocalName(wsp, "txbx") ? renderTextBox(wsp) : renderGeometry(wsp)).join("");
115
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${emuToPixels(width)}" height="${emuToPixels(height)}">${content}</svg>`;
116
+ };
117
+ /** Parse a WordprocessingGroup drawing into a safe SVG-backed image preview. */
118
+ const parseGroupDrawing = (drawing) => {
119
+ const group = findChildByLocalName(findAllDeep(drawing, "a", "graphicData").at(0) ?? null, "wgp");
120
+ if (!group) return null;
121
+ const image = parseImage(drawing, void 0, void 0);
122
+ if (!image || image.size.width <= 0 || image.size.height <= 0) return null;
123
+ const svg = createSvg(group, image.size.width, image.size.height);
124
+ if (svg.length > MAX_SVG_CHARACTERS) return null;
125
+ image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
126
+ image.mimeType = "image/svg+xml";
127
+ image.filename = "wordprocessing-group.svg";
128
+ return image;
129
+ };
130
+ //#endregion
131
+ export { parseGroupDrawing };
@@ -39,7 +39,9 @@ declare function createNumberingMap(definitions: document_d_exports.NumberingDef
39
39
  declare function computeListRendering(numPr: {
40
40
  numId?: number;
41
41
  ilvl?: number;
42
- }, numbering: NumberingMap): document_d_exports.ListRendering | null;
42
+ }, numbering: NumberingMap): (document_d_exports.ListRendering & {
43
+ levelStarts: number[];
44
+ }) | null;
43
45
  /**
44
46
  * Format a number according to the specified format
45
47
  *
@@ -581,7 +581,12 @@ function computeListRendering(numPr, numbering) {
581
581
  const level = numbering.getLevel(numId, ilvl);
582
582
  if (!level) return null;
583
583
  const levelNumFmts = [];
584
- for (let i = 0; i <= ilvl; i += 1) levelNumFmts.push(level.isLgl ? "decimal" : numbering.getLevel(numId, i)?.numFmt ?? "decimal");
584
+ const levelStarts = [];
585
+ for (let i = 0; i <= ilvl; i += 1) {
586
+ const listLevel = numbering.getLevel(numId, i);
587
+ levelNumFmts.push(level.isLgl ? "decimal" : listLevel?.numFmt ?? "decimal");
588
+ levelStarts.push(listLevel?.start ?? 1);
589
+ }
585
590
  const instance = numbering.getInstance(numId);
586
591
  const overrideForLevel = instance?.levelOverrides?.find((override) => override.ilvl === ilvl);
587
592
  const rendering = {
@@ -590,7 +595,8 @@ function computeListRendering(numPr, numbering) {
590
595
  marker: level.lvlText,
591
596
  isBullet: level.numFmt === "bullet",
592
597
  numFmt: level.isLgl ? "decimal" : level.numFmt,
593
- levelNumFmts
598
+ levelNumFmts,
599
+ levelStarts
594
600
  };
595
601
  if (level.isLgl) rendering.isLegal = true;
596
602
  if (level.rPr?.hidden) rendering.markerHidden = true;
@@ -436,7 +436,7 @@ function paragraphStartsWithRenderedPageBreak(node) {
436
436
  return "continue";
437
437
  };
438
438
  const outcome = visit(node);
439
- if (outcome === "forced") return true;
439
+ if (outcome === "forced") return sawRenderedPageBreak;
440
440
  return outcome === "visible" && sawRenderedPageBreak;
441
441
  }
442
442
  function replaceLocalName(name, localName) {
@@ -949,13 +949,19 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
949
949
  const level = numbering.getLevel(numId, ilvl);
950
950
  if (level) {
951
951
  const levelNumFmts = [];
952
- for (let levelIndex = 0; levelIndex <= ilvl; levelIndex += 1) levelNumFmts.push(level.isLgl ? "decimal" : numbering.getLevel(numId, levelIndex)?.numFmt ?? "decimal");
952
+ const levelStarts = [];
953
+ for (let levelIndex = 0; levelIndex <= ilvl; levelIndex += 1) {
954
+ const listLevel = numbering.getLevel(numId, levelIndex);
955
+ levelNumFmts.push(level.isLgl ? "decimal" : listLevel?.numFmt ?? "decimal");
956
+ levelStarts.push(listLevel?.start ?? 1);
957
+ }
953
958
  const listRendering = {
954
959
  level: ilvl,
955
960
  numId,
956
961
  marker: level.lvlText,
957
962
  isBullet: level.numFmt === "bullet",
958
- levelNumFmts
963
+ levelNumFmts,
964
+ levelStarts
959
965
  };
960
966
  const instance = numbering.getInstance(numId);
961
967
  const overrideForLevel = instance?.levelOverrides?.find((override) => override.ilvl === ilvl);
@@ -1,6 +1,7 @@
1
1
  import { cloneWithXmlnsDeclarations, elementToXml, findChild, findChildren, getAttribute, getChildElements, getTextContent, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
2
2
  import { EmphasisMarkSchema, FontThemeSchema, HighlightColorSchema, ShadingPatternSchema, TextEffectSchema, ThemeColorSlotSchema, UnderlineStyleSchema, narrowEnum } from "./parserEnums.js";
3
3
  import { parseImage } from "./imageParser.js";
4
+ import { parseGroupDrawing } from "./groupDrawingParser.js";
4
5
  import { parseShapeFromDrawing, shouldPreserveRawShapeDrawing } from "./shapeParser.js";
5
6
  import { parseVmlImageContent } from "./vmlImageParser.js";
6
7
  import { resolveThemeFontRef } from "./themeParser.js";
@@ -442,6 +443,12 @@ function parseInstrText(element) {
442
443
  * `shapeParser.parseShapeFromDrawing` into a `ShapeContent`.
443
444
  */
444
445
  function parseDrawingContent(element, rels, media) {
446
+ const groupImage = parseGroupDrawing(element);
447
+ if (groupImage) return {
448
+ type: "drawing",
449
+ image: groupImage,
450
+ rawXml: elementToXml(element)
451
+ };
445
452
  if (shouldPreserveRawShapeDrawing(element)) return {
446
453
  type: "drawing",
447
454
  image: {
@@ -550,7 +557,7 @@ function parseRunContents(runElement, rels, media, rootXmlns = {}) {
550
557
  if (innerName === "drawing") {
551
558
  const innerDrawing = parseDrawingContent(innerChild, rels, media);
552
559
  if (innerDrawing) {
553
- if (innerDrawing.type === "drawing" && !innerDrawing.image.src) innerDrawing.rawXml = elementToXml(child);
560
+ if (innerDrawing.type === "drawing" && (innerDrawing.rawXml !== void 0 || !innerDrawing.image.src)) innerDrawing.rawXml = elementToXml(child);
554
561
  contents.push(innerDrawing);
555
562
  }
556
563
  } else if (innerName === "pict") {
@@ -50,11 +50,8 @@ function findParagraphOffsets(xml, paraId) {
50
50
  start,
51
51
  end: tagEnd + 1
52
52
  };
53
- pos = tagEnd + 1;
54
- } else {
55
- depth++;
56
- pos = tagEnd + 1;
57
- }
53
+ } else depth++;
54
+ pos = tagEnd + 1;
58
55
  } else pos = tagStart + 1;
59
56
  } else if (xml.startsWith("</w:p>", tagStart)) {
60
57
  depth--;
@@ -226,11 +223,8 @@ function scanElementRange(xml, start, openLiteral, closeTag) {
226
223
  start,
227
224
  end: tagEnd + 1
228
225
  };
229
- pos = tagEnd + 1;
230
- } else {
231
- depth++;
232
- pos = tagEnd + 1;
233
- }
226
+ } else depth++;
227
+ pos = tagEnd + 1;
234
228
  } else if (xml.startsWith(closeTag, tagStart)) {
235
229
  depth--;
236
230
  if (depth === 0) return {
@@ -87,7 +87,9 @@ function serializeNum(instance) {
87
87
  * change detection and per-definition splicing, never to overwrite the part.
88
88
  */
89
89
  function serializeNumberingXml(numbering) {
90
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:numbering xmlns:w="${W_NS}">${numbering.abstractNums.map(serializeAbstractNum).join("")}${numbering.nums.map(serializeNum).join("")}</w:numbering>`;
90
+ const abstractNums = numbering.abstractNums.map(serializeAbstractNum).join("");
91
+ const nums = numbering.nums.map(serializeNum).join("");
92
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:numbering xmlns:w="${W_NS}">${abstractNums}${nums}</w:numbering>`;
91
93
  }
92
94
  //#endregion
93
95
  export { serializeNumberingXml };
@@ -1,8 +1,11 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
 
3
3
  //#region src/docx/settingsParser.d.ts
4
+ type FolioDocumentSettings = document_d_exports.DocumentSettings & {
5
+ /** Swap left/right section margins on even physical pages. */mirrorMargins?: boolean;
6
+ };
4
7
  /** OOXML default per §17.6.13 when `w:defaultTabStop` is absent. */
5
8
  declare const DEFAULT_TAB_STOP_TWIPS = 720;
6
- declare function parseSettings(xml: string | null): document_d_exports.DocumentSettings;
7
- type DocumentSettings = document_d_exports.DocumentSettings;
8
- export { DEFAULT_TAB_STOP_TWIPS, type DocumentSettings, parseSettings };
9
+ declare function parseSettings(xml: string | null): FolioDocumentSettings;
10
+ //#endregion
11
+ export { DEFAULT_TAB_STOP_TWIPS, FolioDocumentSettings, parseSettings };
@@ -13,6 +13,8 @@ function parseSettings(xml) {
13
13
  const settings = { defaultTabStop: parseDefaultTabStop(root) };
14
14
  const evenAndOddHeaders = root ? findChild(root, "w", "evenAndOddHeaders") : null;
15
15
  if (evenAndOddHeaders && parseBooleanElement(evenAndOddHeaders)) settings.evenAndOddHeaders = true;
16
+ const mirrorMargins = root ? findChild(root, "w", "mirrorMargins") : null;
17
+ if (mirrorMargins && parseBooleanElement(mirrorMargins)) settings.mirrorMargins = true;
16
18
  const themeFontLangEl = root ? findChild(root, "w", "themeFontLang") : null;
17
19
  const eastAsiaLang = themeFontLangEl ? getAttribute(themeFontLangEl, "w", "eastAsia") || void 0 : void 0;
18
20
  const bidiLang = themeFontLangEl ? getAttribute(themeFontLangEl, "w", "bidi") || void 0 : void 0;
@@ -31,6 +31,7 @@ const fxpParserOptions = {
31
31
  parseAttributeValue: false,
32
32
  ignoreDeclaration: true,
33
33
  ignorePiTags: true,
34
+ jPath: false,
34
35
  processEntities: true,
35
36
  htmlEntities: true
36
37
  };
@@ -65,15 +66,19 @@ function fxpNodeToElement(node) {
65
66
  text: node[TEXT_KEY]
66
67
  };
67
68
  const attrs = node[ATTR_KEY];
68
- for (const key of Object.keys(node)) {
69
+ for (const key in node) {
69
70
  if (key === ATTR_KEY) continue;
70
71
  const children = node[key];
71
72
  const element = {
72
73
  type: "element",
73
74
  name: key
74
75
  };
75
- if (attrs && Object.keys(attrs).length > 0) element.attributes = attrs;
76
- if (children.length > 0) element.elements = children.map(fxpNodeToElement);
76
+ if (attrs) element.attributes = attrs;
77
+ if (children.length > 0) {
78
+ const elements = [];
79
+ for (const child of children) elements.push(fxpNodeToElement(child));
80
+ element.elements = elements;
81
+ }
77
82
  return element;
78
83
  }
79
84
  return { type: "element" };
@@ -84,7 +89,9 @@ function fxpNodeToElement(node) {
84
89
  * `{ elements: [...] }`.
85
90
  */
86
91
  function fxpToRootElement(nodes) {
87
- return { elements: nodes.map(fxpNodeToElement) };
92
+ const elements = [];
93
+ for (const node of nodes) elements.push(fxpNodeToElement(node));
94
+ return { elements };
88
95
  }
89
96
  /**
90
97
  * Convert an XmlElement back into the fast-xml-parser preserveOrder format
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "./ai-edits/types.js";
1
+ import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "./ai-edits/types.js";
2
2
  import { applyFolioAIEditOperations } from "./ai-edits/apply.js";
3
3
  import { document_d_exports } from "./types/document.js";
4
+ import { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
4
5
  import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "./ai-edits/snapshot.js";
5
6
  import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
6
7
  import { WordDiffSegment, diffWordSegments } from "./ai-edits/word-diff.js";
@@ -26,4 +27,4 @@ import { toMarkdown, toMarkdownResult } from "./markdown/index.js";
26
27
  import { EmbeddedFont, EmbeddedFontParts, extractEmbeddedFonts, getEmbeddedFontFaces } from "./fonts/embeddedFonts.js";
27
28
  import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "./utils/fontResolver.js";
28
29
  type Document = document_d_exports.Document;
29
- export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocxCompatibility, type EmbeddedFont, type EmbeddedFontParts, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type ImageMeta, type ImageRef, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
30
+ export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocxCompatibility, type EmbeddedFont, type EmbeddedFontParts, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationStatus, type FolioDocumentOperationType, type ImageMeta, type ImageRef, InvalidFolioDocumentOperationBatchError, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
package/dist/index.js CHANGED
@@ -1,13 +1,14 @@
1
+ import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
2
+ import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "./ai-edits/snapshot.js";
3
+ import { diffWordSegments } from "./ai-edits/word-diff.js";
4
+ import { applyFolioAIEditOperations } from "./ai-edits/apply.js";
5
+ import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
1
6
  import { createEmptyDocument } from "./utils/createDocument.js";
2
7
  import { createDocx } from "./docx/rezip.js";
3
- import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
4
8
  import { DEFAULT_AI_SUGGESTION_PRESETS } from "./ai-suggestions/types.js";
5
9
  import { buildPositionalText } from "./ai-suggestions/text-positions.js";
6
10
  import { isSuggestionStale, resolveSuggestionAnchor } from "./ai-suggestions/conflict.js";
7
11
  import { applySuggestions } from "./ai-suggestions/apply.js";
8
- import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "./ai-edits/snapshot.js";
9
- import { diffWordSegments } from "./ai-edits/word-diff.js";
10
- import { applyFolioAIEditOperations } from "./ai-edits/apply.js";
11
12
  import { setAISuggestionsMeta, setFocusedSuggestionMeta } from "./prosemirror/plugins/aiSuggestionDecorations.js";
12
13
  import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "./utils/fontResolver.js";
13
14
  import { scrollFolioPositionIntoView } from "./paged-layout/scrollToPmPosition.js";
@@ -21,4 +22,4 @@ import { DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acc
21
22
  import { fromMarkdown } from "./markdown/fromMarkdown.js";
22
23
  import { toMarkdown, toMarkdownResult } from "./markdown/index.js";
23
24
  import { extractEmbeddedFonts, getEmbeddedFontFaces } from "./fonts/embeddedFonts.js";
24
- export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
25
+ export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -23,6 +23,42 @@ declare function collectFootnoteRefs(blocks: FlowBlock[]): {
23
23
  footnoteId: number;
24
24
  pmPos: number;
25
25
  }[];
26
+ /**
27
+ * Scan FlowBlocks for runs with endnoteRefId set, in document order.
28
+ * Same recursive walk as `collectFootnoteRefs`.
29
+ */
30
+ declare function collectEndnoteRefs(blocks: FlowBlock[]): {
31
+ endnoteId: number;
32
+ pmPos: number;
33
+ }[];
34
+ type NumberableNote = {
35
+ id: number;
36
+ noteType?: document_d_exports.Footnote["noteType"];
37
+ };
38
+ /**
39
+ * Assign sequential display numbers (1, 2, 3, …) to notes in order of first
40
+ * reference. Word numbers footnotes/endnotes by reference order, not by their
41
+ * `w:id` values, which may be non-contiguous or out of document order. Only
42
+ * `normal` notes are numbered; separator/continuation notes and refs to
43
+ * missing notes consume no number.
44
+ */
45
+ declare function computeNoteDisplayNumbers(notes: readonly NumberableNote[], refNoteIds: readonly number[]): Map<number, number>;
46
+ type NoteDisplayNumberMaps = {
47
+ /** footnote `w:id` → sequential display number */footnoteNumbers?: ReadonlyMap<number, number>; /** endnote `w:id` → sequential display number */
48
+ endnoteNumbers?: ReadonlyMap<number, number>;
49
+ };
50
+ /**
51
+ * Rewrite body reference-marker run text from the raw `w:id` (which the PM
52
+ * doc stores as the marker text; the save path serializes from the mark
53
+ * attrs, never from this text) to the sequential display number, so the
54
+ * inline marker matches the number rendered in the note area. Must run
55
+ * before measurement so marker widths match the painted digits. Untouched
56
+ * blocks/runs are returned by reference so the painter's fingerprinting and
57
+ * the incremental measure path see them unchanged. Runs keep their PM range,
58
+ * so click-to-position still resolves into the marker (same contract as the
59
+ * template preview substitution).
60
+ */
61
+ declare function remapNoteMarkerText(blocks: FlowBlock[], maps: NoteDisplayNumberMaps): FlowBlock[];
26
62
  /**
27
63
  * After layout, determine which footnotes appear on which pages.
28
64
  * Checks each page's fragments to see if any footnoteRef PM positions fall within.
@@ -54,4 +90,4 @@ declare function calculateFootnoteReservedHeights(pageFootnoteMap: Map<number, n
54
90
  height: number;
55
91
  }>): Map<number, number>;
56
92
  //#endregion
57
- export { ConvertFootnoteOptions, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, MeasureBlocksFn, applyFootnotePresentation, buildFootnoteContentMap, calculateFootnoteReservedHeights, collectFootnoteRefs, convertFootnoteToContent, mapFootnotesToPages };
93
+ export { ConvertFootnoteOptions, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, MeasureBlocksFn, NoteDisplayNumberMaps, applyFootnotePresentation, buildFootnoteContentMap, calculateFootnoteReservedHeights, collectEndnoteRefs, collectFootnoteRefs, computeNoteDisplayNumbers, convertFootnoteToContent, mapFootnotesToPages, remapNoteMarkerText };