@stll/folio-core 0.32.2 → 0.33.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 (222) hide show
  1. package/dist/ai-edits/__fixtures__/paragraphs.d.ts +17 -0
  2. package/dist/ai-edits/__fixtures__/paragraphs.js +33 -0
  3. package/dist/ai-edits/apply.d.ts +49 -3
  4. package/dist/ai-edits/apply.js +649 -85
  5. package/dist/ai-edits/blockRange.d.ts +7 -3
  6. package/dist/ai-edits/blockRange.js +14 -6
  7. package/dist/ai-edits/headless.d.ts +39 -5
  8. package/dist/ai-edits/headless.js +76 -17
  9. package/dist/ai-edits/index.d.ts +6 -6
  10. package/dist/ai-edits/index.js +3 -3
  11. package/dist/ai-edits/read.d.ts +4 -0
  12. package/dist/ai-edits/read.js +30 -6
  13. package/dist/ai-edits/scoped-reading.js +4 -3
  14. package/dist/ai-edits/snapshot.d.ts +42 -2
  15. package/dist/ai-edits/snapshot.js +127 -62
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +24 -1
  17. package/dist/ai-edits/table-row-column-mutations.js +98 -6
  18. package/dist/ai-edits/table-targets.d.ts +12 -3
  19. package/dist/ai-edits/table-targets.js +15 -5
  20. package/dist/ai-edits/types.d.ts +219 -15
  21. package/dist/ai-edits/word-diff.d.ts +54 -11
  22. package/dist/ai-edits/word-diff.js +221 -61
  23. package/dist/compare/__fixtures__/body-sequence.d.ts +33 -0
  24. package/dist/compare/__fixtures__/body-sequence.js +67 -0
  25. package/dist/compare/__fixtures__/nested-table.d.ts +16 -0
  26. package/dist/compare/__fixtures__/nested-table.js +50 -0
  27. package/dist/compare/__fixtures__/numbered-list.d.ts +34 -0
  28. package/dist/compare/__fixtures__/numbered-list.js +85 -0
  29. package/dist/compare/column-alignment.d.ts +27 -0
  30. package/dist/compare/column-alignment.js +162 -0
  31. package/dist/compare/compare.d.ts +107 -0
  32. package/dist/compare/compare.js +406 -0
  33. package/dist/compare/formatting.d.ts +29 -0
  34. package/dist/compare/formatting.js +84 -0
  35. package/dist/compare/plan.d.ts +22 -0
  36. package/dist/compare/plan.js +1059 -0
  37. package/dist/compare/reproducible-package.d.ts +17 -0
  38. package/dist/compare/reproducible-package.js +30 -0
  39. package/dist/compare/scenario.d.ts +77 -0
  40. package/dist/compare/scenario.js +263 -0
  41. package/dist/compare/types.d.ts +282 -0
  42. package/dist/compare/types.js +32 -0
  43. package/dist/compare/verification.d.ts +55 -0
  44. package/dist/compare/verification.js +146 -0
  45. package/dist/compat/eigenpal.d.ts +9 -6
  46. package/dist/compat/eigenpal.js +6 -3
  47. package/dist/controller/layoutPipeline.d.ts +13 -0
  48. package/dist/controller/layoutPipeline.js +15 -1
  49. package/dist/display-list/build/buildContext.d.ts +39 -0
  50. package/dist/display-list/build/buildContext.js +31 -0
  51. package/dist/display-list/build/buildDisplayList.d.ts +79 -0
  52. package/dist/display-list/build/buildDisplayList.js +283 -0
  53. package/dist/display-list/build/colors.d.ts +20 -0
  54. package/dist/display-list/build/colors.js +136 -0
  55. package/dist/display-list/build/floatingImages.d.ts +24 -0
  56. package/dist/display-list/build/floatingImages.js +41 -0
  57. package/dist/display-list/build/fontTable.d.ts +31 -0
  58. package/dist/display-list/build/fontTable.js +97 -0
  59. package/dist/display-list/build/furniture.d.ts +86 -0
  60. package/dist/display-list/build/furniture.js +98 -0
  61. package/dist/display-list/build/glyphs.d.ts +55 -0
  62. package/dist/display-list/build/glyphs.js +103 -0
  63. package/dist/display-list/build/headerFooterPrimitives.d.ts +17 -0
  64. package/dist/display-list/build/headerFooterPrimitives.js +40 -0
  65. package/dist/display-list/build/imagePrimitives.d.ts +35 -0
  66. package/dist/display-list/build/imagePrimitives.js +264 -0
  67. package/dist/display-list/build/pageBorderPrimitives.d.ts +23 -0
  68. package/dist/display-list/build/pageBorderPrimitives.js +111 -0
  69. package/dist/display-list/build/pageFurniture.d.ts +35 -0
  70. package/dist/display-list/build/pageFurniture.js +141 -0
  71. package/dist/display-list/build/paragraphPrimitives.d.ts +19 -0
  72. package/dist/display-list/build/paragraphPrimitives.js +819 -0
  73. package/dist/display-list/build/regions.d.ts +46 -0
  74. package/dist/display-list/build/regions.js +56 -0
  75. package/dist/display-list/build/storyPrimitives.d.ts +29 -0
  76. package/dist/display-list/build/storyPrimitives.js +279 -0
  77. package/dist/display-list/build/strokes.d.ts +19 -0
  78. package/dist/display-list/build/strokes.js +78 -0
  79. package/dist/display-list/build/tablePrimitives.d.ts +38 -0
  80. package/dist/display-list/build/tablePrimitives.js +409 -0
  81. package/dist/display-list/build/textBoxPrimitives.d.ts +14 -0
  82. package/dist/display-list/build/textBoxPrimitives.js +129 -0
  83. package/dist/display-list/build/textDecorations.d.ts +29 -0
  84. package/dist/display-list/build/textDecorations.js +29 -0
  85. package/dist/display-list/build/unsupported.d.ts +57 -0
  86. package/dist/display-list/build/unsupported.js +0 -0
  87. package/dist/display-list/build/watermarkPrimitives.d.ts +15 -0
  88. package/dist/display-list/build/watermarkPrimitives.js +128 -0
  89. package/dist/display-list/dom/renderDisplayListToDom.d.ts +26 -0
  90. package/dist/display-list/dom/renderDisplayListToDom.js +620 -0
  91. package/dist/display-list/editor/displayListPagePainter.d.ts +22 -0
  92. package/dist/display-list/editor/displayListPagePainter.js +63 -0
  93. package/dist/display-list/editor/pageRenderer.d.ts +24 -0
  94. package/dist/display-list/editor/pageRenderer.js +36 -0
  95. package/dist/display-list/primitives.d.ts +95 -0
  96. package/dist/display-list/primitives.js +127 -0
  97. package/dist/display-list/types.d.ts +472 -0
  98. package/dist/display-list/types.js +0 -0
  99. package/dist/document-operations.d.ts +39 -8
  100. package/dist/document-operations.js +169 -16
  101. package/dist/document-stories.d.ts +16 -0
  102. package/dist/document-stories.js +48 -4
  103. package/dist/docx/packageParts.d.ts +35 -0
  104. package/dist/docx/packageParts.js +120 -0
  105. package/dist/docx/paragraphParser.js +22 -22
  106. package/dist/docx/paragraphTraversal.js +1 -1
  107. package/dist/docx/renderedPageBreakNormalization.js +3 -1
  108. package/dist/docx/revisionIdNormalization.d.ts +13 -0
  109. package/dist/docx/revisionIdNormalization.js +103 -0
  110. package/dist/docx/rezip.js +26 -17
  111. package/dist/docx/selectiveSave.js +2 -2
  112. package/dist/docx/serializer/commentSerializer.js +6 -1
  113. package/dist/docx/serializer/paragraphSerializer.js +33 -4
  114. package/dist/docx/serializer/runSerializer.js +11 -10
  115. package/dist/docx/serializer/tableSerializer.js +2 -1
  116. package/dist/docx/server/applyDocxXmlPatchProposal.js +1 -1
  117. package/dist/docx/server/createBilingualDocx.js +3 -2
  118. package/dist/docx/streamingXmlParser.d.ts +13 -1
  119. package/dist/docx/streamingXmlParser.js +49 -11
  120. package/dist/docx/unzip.d.ts +1 -2
  121. package/dist/docx/unzip.js +25 -6
  122. package/dist/docx/xmlParser.d.ts +3 -1
  123. package/dist/docx/xmlParser.js +33 -27
  124. package/dist/export-pdf.d.ts +43 -0
  125. package/dist/export-pdf.js +98 -0
  126. package/dist/fonts/headlessMeasure.d.ts +76 -0
  127. package/dist/fonts/headlessMeasure.js +0 -0
  128. package/dist/fonts/sfnt/parse.d.ts +51 -0
  129. package/dist/fonts/sfnt/parse.js +525 -0
  130. package/dist/fonts/sfnt/subset.d.ts +20 -0
  131. package/dist/fonts/sfnt/subset.js +350 -0
  132. package/dist/fonts/sfnt/tables.d.ts +88 -0
  133. package/dist/fonts/sfnt/tables.js +131 -0
  134. package/dist/fonts/sfnt/woff.d.ts +14 -0
  135. package/dist/fonts/sfnt/woff.js +163 -0
  136. package/dist/generated/text_shaper.js +324 -0
  137. package/dist/generated/text_shaper_bg.wasm +0 -0
  138. package/dist/headless-layout.d.ts +75 -0
  139. package/dist/headless-layout.js +350 -0
  140. package/dist/index.d.ts +9 -6
  141. package/dist/index.js +6 -3
  142. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  143. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  144. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  145. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  146. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -1
  147. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -0
  148. package/dist/layout-engine/measure/advanceComposition.d.ts +62 -0
  149. package/dist/layout-engine/measure/advanceComposition.js +148 -0
  150. package/dist/layout-engine/measure/cache.d.ts +2 -0
  151. package/dist/layout-engine/measure/measureContainer.js +13 -0
  152. package/dist/layout-engine/measure/measureParagraph.js +1 -2
  153. package/dist/layout-engine/measure/measureTypes.d.ts +12 -0
  154. package/dist/layout-engine/measure/tableInlinePlacement.d.ts +3 -2
  155. package/dist/layout-engine/measure/tableInlinePlacement.js +14 -1
  156. package/dist/layout-engine/tableIndentCompatibility.d.ts +5 -0
  157. package/dist/layout-engine/tableIndentCompatibility.js +15 -0
  158. package/dist/layout-engine/types.d.ts +8 -0
  159. package/dist/layout-painter/renderPage.d.ts +29 -1
  160. package/dist/layout-painter/renderPage.js +47 -19
  161. package/dist/layout-painter/renderParagraph.d.ts +21 -2
  162. package/dist/layout-painter/renderParagraph.js +1 -1
  163. package/dist/layout-painter/renderTable.js +37 -4
  164. package/dist/managers/editorShortcuts.d.ts +33 -1
  165. package/dist/managers/editorShortcuts.js +20 -1
  166. package/dist/markdown/renderRuns.js +7 -2
  167. package/dist/markdown/renderTable.js +5 -1
  168. package/dist/model.d.ts +3 -3
  169. package/dist/model.js +2 -2
  170. package/dist/pdf/contentStream.d.ts +73 -0
  171. package/dist/pdf/contentStream.js +143 -0
  172. package/dist/pdf/fonts.d.ts +96 -0
  173. package/dist/pdf/fonts.js +593 -0
  174. package/dist/pdf/images.d.ts +28 -0
  175. package/dist/pdf/images.js +439 -0
  176. package/dist/pdf/objects.d.ts +93 -0
  177. package/dist/pdf/objects.js +237 -0
  178. package/dist/pdf/pageSpace.d.ts +43 -0
  179. package/dist/pdf/pageSpace.js +57 -0
  180. package/dist/pdf/paint.d.ts +32 -0
  181. package/dist/pdf/paint.js +442 -0
  182. package/dist/pdf/writePdf.d.ts +56 -0
  183. package/dist/pdf/writePdf.js +345 -0
  184. package/dist/prosemirror/commands/comments.js +91 -6
  185. package/dist/prosemirror/conversion/fromProseDoc.js +41 -7
  186. package/dist/prosemirror/conversion/toProseDoc.js +41 -4
  187. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +15 -2
  188. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +35 -6
  189. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +2 -2
  190. package/dist/prosemirror/extensions/features/pasteCleanup.js +4 -3
  191. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +3 -1
  192. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +5 -3
  193. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -1
  194. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +9 -3
  195. package/dist/prosemirror/extensions/nodes/TableExtension.js +56 -39
  196. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +3 -1
  197. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +5 -3
  198. package/dist/prosemirror/plugins/suggestionMode.js +1 -0
  199. package/dist/prosemirror/revisionCarriers.js +19 -2
  200. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +2 -2
  201. package/dist/prosemirror/utils/extractTrackedChanges.js +59 -23
  202. package/dist/prosemirror/validation.js +55 -27
  203. package/dist/prosemirror/zeroWidthAnchors.d.ts +10 -0
  204. package/dist/prosemirror/zeroWidthAnchors.js +23 -0
  205. package/dist/redline.js +12 -79
  206. package/dist/server.d.ts +3 -3
  207. package/dist/server.js +2 -2
  208. package/dist/shaping/placeRun.d.ts +51 -0
  209. package/dist/shaping/placeRun.js +84 -0
  210. package/dist/shaping/shaper.d.ts +92 -0
  211. package/dist/shaping/shaper.js +102 -0
  212. package/dist/types/block-id.d.ts +18 -2
  213. package/dist/types/block-id.js +49 -5
  214. package/dist/types/content.d.ts +2 -2
  215. package/dist/utils/clipboard.js +4 -3
  216. package/dist/utils/fontResolver.js +183 -0
  217. package/dist/utils/htmlComments.d.ts +17 -0
  218. package/dist/utils/htmlComments.js +22 -0
  219. package/dist/utils/scriptSegments.d.ts +12 -1
  220. package/dist/utils/scriptSegments.js +17 -1
  221. package/dist/version-comparison.d.ts +1 -1
  222. package/package.json +7 -3
@@ -0,0 +1,32 @@
1
+ import { TaggedError } from "better-result";
2
+ //#region src/compare/types.ts
3
+ /**
4
+ * Public vocabulary of {@link ./compare.compareDocx}: the change list, the
5
+ * options that pin its output, and the failures it reports.
6
+ */
7
+ /** Why a part of the package is absent from `changes`. */
8
+ const COMPARE_UNSUPPORTED_REASONS = Object.freeze([
9
+ "story-missing-in-base",
10
+ "story-missing-in-target",
11
+ "story-not-editable"
12
+ ]);
13
+ var InvalidCompareDocxOptionsError = class extends TaggedError("InvalidCompareDocxOptionsError") {};
14
+ var CompareDocxParseError = class extends TaggedError("CompareDocxParseError") {};
15
+ /**
16
+ * The applier refused at least one derived operation, so accepting the result
17
+ * would not reproduce the target. Reported instead of returning a package that
18
+ * silently under-represents the difference.
19
+ */
20
+ var CompareDocxApplyError = class extends TaggedError("CompareDocxApplyError") {};
21
+ /**
22
+ * The generated tracked changes do not accept back to the target. Raised by
23
+ * the self-check {@link compareDocx} runs before returning: a redline that
24
+ * quietly loses part of the difference is worse than no redline, so the
25
+ * mismatch is surfaced instead of the document.
26
+ */
27
+ var CompareDocxRoundTripError = class extends TaggedError("CompareDocxRoundTripError") {};
28
+ /** The difference needs more operations than the engine will generate. */
29
+ var CompareDocxOperationLimitError = class extends TaggedError("CompareDocxOperationLimitError") {};
30
+ var CompareDocxSerializeError = class extends TaggedError("CompareDocxSerializeError") {};
31
+ //#endregion
32
+ export { COMPARE_UNSUPPORTED_REASONS, CompareDocxApplyError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, InvalidCompareDocxOptionsError };
@@ -0,0 +1,55 @@
1
+ import { FolioAIBlock } from "../ai-edits/types.js";
2
+ import { FolioDocumentStoryHandle } from "../ai-edits/headless.js";
3
+ //#region src/compare/verification.d.ts
4
+ /** The two directions of the round trip, each an invariant of its own. */
5
+ declare const COMPARE_VERIFICATION_INVARIANTS: readonly ["accept-reproduces-target", "reject-reproduces-base"];
6
+ type CompareVerificationInvariant = (typeof COMPARE_VERIFICATION_INVARIANTS)[number];
7
+ /**
8
+ * What diverged. Ordered from the structural to the textual: the first cause
9
+ * that fits is the one reported, because a block in the wrong container is a
10
+ * different finding from a block whose words are wrong even when both are true.
11
+ */
12
+ declare const COMPARE_VERIFICATION_CAUSES: readonly ["invisible-structure", "block-count", "container", "style", "list-level", "inline-formatting", "whitespace", "text"];
13
+ type CompareVerificationCause = (typeof COMPARE_VERIFICATION_CAUSES)[number];
14
+ /** One invariant that did not hold, in one story. */
15
+ type CompareVerificationFailure = {
16
+ invariant: CompareVerificationInvariant;
17
+ cause: CompareVerificationCause;
18
+ story: FolioDocumentStoryHandle;
19
+ /** Structural facts only: counts, offsets, container kinds. Safe to quote. */
20
+ detail: string;
21
+ };
22
+ /**
23
+ * Whether the redline was proven to round-trip.
24
+ *
25
+ * `unverified` is only ever returned when the caller asked for it with
26
+ * `onUnverified: "emit"`; the default refuses instead, because a redline that
27
+ * reads plausibly and is wrong is worse than no redline.
28
+ */
29
+ type CompareVerification = {
30
+ status: "verified";
31
+ } | {
32
+ status: "unverified";
33
+ failures: readonly CompareVerificationFailure[];
34
+ };
35
+ /** Effective supported formatting with equivalent adjacent runs normalized. */
36
+ declare const projectSupportedInlineFormatting: ({ text, previewRuns }: FolioAIBlock) => string;
37
+ /** Element by element, never by joining: a block's text may hold the separator. */
38
+ declare const sameProjection: (left: readonly string[], right: readonly string[]) => boolean;
39
+ type ClassifyOptions = {
40
+ invariant: CompareVerificationInvariant;
41
+ story: FolioDocumentStoryHandle;
42
+ /** What the redline actually leaves. */
43
+ actual: readonly string[];
44
+ /** What the invariant says it should leave. */
45
+ expected: readonly string[];
46
+ };
47
+ /**
48
+ * The failure two projections describe, or `null` when they agree.
49
+ *
50
+ * Total over the causes by construction: the last branch is unconditional, so
51
+ * a divergence always produces a failure rather than being dropped.
52
+ */
53
+ declare const classifyProjectionMismatch: ({ invariant, story, actual, expected }: ClassifyOptions) => CompareVerificationFailure | null;
54
+ //#endregion
55
+ export { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant, classifyProjectionMismatch, projectSupportedInlineFormatting, sameProjection };
@@ -0,0 +1,146 @@
1
+ //#region src/compare/verification.ts
2
+ /** The two directions of the round trip, each an invariant of its own. */
3
+ const COMPARE_VERIFICATION_INVARIANTS = Object.freeze(["accept-reproduces-target", "reject-reproduces-base"]);
4
+ /**
5
+ * What diverged. Ordered from the structural to the textual: the first cause
6
+ * that fits is the one reported, because a block in the wrong container is a
7
+ * different finding from a block whose words are wrong even when both are true.
8
+ */
9
+ const COMPARE_VERIFICATION_CAUSES = Object.freeze([
10
+ "invisible-structure",
11
+ "block-count",
12
+ "container",
13
+ "style",
14
+ "list-level",
15
+ "inline-formatting",
16
+ "whitespace",
17
+ "text"
18
+ ]);
19
+ const supportedInlineStyle = ({ bold, italic, underline, strike }) => `${bold === true ? "b" : ""}${italic === true ? "i" : ""}${underline === true ? "u" : ""}${strike === true ? "s" : ""}`;
20
+ /** Effective supported formatting with equivalent adjacent runs normalized. */
21
+ const projectSupportedInlineFormatting = ({ text, previewRuns }) => {
22
+ const projected = [];
23
+ for (const run of previewRuns ?? [{ text }]) {
24
+ if (run.text.length === 0) continue;
25
+ const style = supportedInlineStyle(run);
26
+ const previous = projected.at(-1);
27
+ if (previous?.style === style) {
28
+ previous.length += run.text.length;
29
+ continue;
30
+ }
31
+ projected.push({
32
+ length: run.text.length,
33
+ style
34
+ });
35
+ }
36
+ return projected.map(({ length, style }) => `${String(length)}:${style}`).join(",");
37
+ };
38
+ const parseProjection = (entry) => {
39
+ const first = entry.indexOf("|");
40
+ const second = entry.indexOf("|", first + 1);
41
+ const third = entry.indexOf("|", second + 1);
42
+ if (first === -1 || second === -1 || third === -1) return {
43
+ container: "",
44
+ styleId: "",
45
+ listLevel: "",
46
+ text: entry
47
+ };
48
+ return {
49
+ container: entry.slice(0, first),
50
+ styleId: entry.slice(first + 1, second),
51
+ listLevel: entry.slice(second + 1, third),
52
+ text: entry.slice(third + 1)
53
+ };
54
+ };
55
+ const CONTAINER_PATTERN = /^t(\d+)r(\d+)c(\d+)p(\d+)$/u;
56
+ const containerKind = (container) => CONTAINER_PATTERN.test(container) ? "cell" : "body";
57
+ const collapseWhitespace = (text) => text.replace(/\s+/gu, " ").trim();
58
+ /** Element by element, never by joining: a block's text may hold the separator. */
59
+ const sameProjection = (left, right) => left.length === right.length && left.every((entry, index) => entry === right[index]);
60
+ /**
61
+ * The same projection with every table coordinate renumbered by first
62
+ * appearance, so it counts the blocks the model holds rather than the
63
+ * paragraphs the package contains.
64
+ *
65
+ * The snapshot skips a hidden row's whole subtree, so a table that hides a row
66
+ * on one side only reports every later row one position along. No operation
67
+ * can put a block at those coordinates, because none can create or remove the
68
+ * hidden row that produces them. When two projections agree here and disagree
69
+ * on the raw coordinates, the redline holds every block the other side does,
70
+ * in order, and the difference is one the block model cannot see.
71
+ */
72
+ const byVisibleOrdinal = (entries) => {
73
+ const ordinals = /* @__PURE__ */ new Map();
74
+ const counts = /* @__PURE__ */ new Map();
75
+ const ordinalWithin = (scope, index) => {
76
+ const key = `${scope}:${index}`;
77
+ const existing = ordinals.get(key);
78
+ if (existing !== void 0) return existing;
79
+ const next = counts.get(scope) ?? 0;
80
+ counts.set(scope, next + 1);
81
+ ordinals.set(key, next);
82
+ return next;
83
+ };
84
+ const paragraphCounts = /* @__PURE__ */ new Map();
85
+ return entries.map((entry) => {
86
+ const first = entry.indexOf("|");
87
+ const match = CONTAINER_PATTERN.exec(entry.slice(0, first));
88
+ if (!match) return entry;
89
+ const [, table = "", row = "", cell = ""] = match;
90
+ const tableOrdinal = ordinalWithin("t", table);
91
+ const rowScope = `r${String(tableOrdinal)}`;
92
+ const rowOrdinal = ordinalWithin(rowScope, row);
93
+ const cellScope = `c${String(tableOrdinal)}.${String(rowOrdinal)}`;
94
+ const cellOrdinal = ordinalWithin(cellScope, cell);
95
+ const cellKey = `${cellScope}:${cell}`;
96
+ const paragraphOrdinal = paragraphCounts.get(cellKey) ?? 0;
97
+ paragraphCounts.set(cellKey, paragraphOrdinal + 1);
98
+ return `t${String(tableOrdinal)}r${String(rowOrdinal)}c${String(cellOrdinal)}p${String(paragraphOrdinal)}` + entry.slice(first);
99
+ });
100
+ };
101
+ /**
102
+ * Where two projections first diverge, and what diverged there. A pair that
103
+ * matches everywhere but in length diverges at the shorter one's end.
104
+ */
105
+ const firstDivergence = (actual, expected) => {
106
+ const shared = Math.min(actual.length, expected.length);
107
+ for (let index = 0; index < shared; index++) if (actual[index] !== expected[index]) return {
108
+ index,
109
+ actual: parseProjection(actual[index] ?? ""),
110
+ expected: parseProjection(expected[index] ?? "")
111
+ };
112
+ return {
113
+ index: shared,
114
+ actual: shared < actual.length ? parseProjection(actual[shared] ?? "") : null,
115
+ expected: shared < expected.length ? parseProjection(expected[shared] ?? "") : null
116
+ };
117
+ };
118
+ /**
119
+ * The failure two projections describe, or `null` when they agree.
120
+ *
121
+ * Total over the causes by construction: the last branch is unconditional, so
122
+ * a divergence always produces a failure rather than being dropped.
123
+ */
124
+ const classifyProjectionMismatch = ({ invariant, story, actual, expected }) => {
125
+ if (sameProjection(actual, expected)) return null;
126
+ const failure = (cause, detail) => ({
127
+ invariant,
128
+ cause,
129
+ story,
130
+ detail
131
+ });
132
+ if (sameProjection(byVisibleOrdinal(actual), byVisibleOrdinal(expected))) return failure("invisible-structure", `every block matches once table coordinates count visible blocks (${String(expected.length)} blocks)`);
133
+ const divergence = firstDivergence(actual, expected);
134
+ const at = `at block ${String(divergence.index)}/${String(expected.length)}`;
135
+ const counts = `${String(actual.length)} blocks against ${String(expected.length)}`;
136
+ if (divergence.actual === null || divergence.expected === null) return failure("block-count", `${actual.length > expected.length ? "more" : "fewer"} blocks than expected (${counts}), diverging ${at}`);
137
+ const { actual: left, expected: right } = divergence;
138
+ if (left.container !== right.container) return failure("container", `a block sits in a ${containerKind(left.container)} where it is expected in a ${containerKind(right.container)}, ${at} (${counts})`);
139
+ if (left.text === right.text && left.styleId !== right.styleId) return failure("style", `the paragraph style did not move ${at} (${counts})`);
140
+ if (left.text === right.text && left.listLevel !== right.listLevel) return failure("list-level", `the list level did not move ${at} (${counts})`);
141
+ if (collapseWhitespace(left.text) === collapseWhitespace(right.text)) return failure("whitespace", `a block's text differs only in whitespace ${at} (${counts})`);
142
+ if (actual.length !== expected.length) return failure("block-count", `${counts}, first differing ${at}`);
143
+ return failure("text", `a ${containerKind(left.container)} block's text does not match ${at}, length ${String(left.text.length)} against ${String(right.text.length)} (${counts})`);
144
+ };
145
+ //#endregion
146
+ export { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, classifyProjectionMismatch, projectSupportedInlineFormatting, sameProjection };
@@ -1,14 +1,17 @@
1
- import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
2
- import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
1
+ import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
2
+ import { WORD_DIFF_GRANULARITIES, WordDiffGranularity, WordDiffNormalization, WordDiffOptions, WordDiffSegment, diffWordSegments } from "../ai-edits/word-diff.js";
3
+ import { FolioAIEditApplyOutcome, FolioRevisionStamp, FolioWordDiffOptions, applyFolioAIEditOperations } from "../ai-edits/apply.js";
3
4
  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, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
5
- import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
5
+ 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, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
6
+ import { createFolioAIEditSnapshot, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
6
7
  import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
7
- import { WordDiffSegment, diffWordSegments } from "../ai-edits/word-diff.js";
8
8
  import { AIBarStatus, AIChatMode, AICitation, AICitationSource, AIGenerateInput, AISuggestion, AISuggestionApplyMode, AISuggestionPreset, AISuggestionSeverity, AISuggestionStatus, DEFAULT_AI_SUGGESTION_PRESETS } from "../ai-suggestions/types.js";
9
9
  import { ApplyResult, applySuggestions } from "../ai-suggestions/apply.js";
10
10
  import { ResolvedAnchor, isSuggestionStale, resolveSuggestionAnchor } from "../ai-suggestions/conflict.js";
11
11
  import { PositionalText, buildPositionalText } from "../ai-suggestions/text-positions.js";
12
+ import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant } from "../compare/verification.js";
13
+ import { COMPARE_UNSUPPORTED_REASONS, CompareChange, CompareChangeLocation, CompareDocxApplyError, CompareDocxError, CompareDocxOperationLimitError, CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, CompareFormatRange, CompareResult, CompareUnsupportedPart, CompareUnsupportedReason, InvalidCompareDocxOptionsError } from "../compare/types.js";
14
+ import { MAX_COMPARE_OPERATIONS, compareDocx } from "../compare/compare.js";
12
15
  import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocumentPreset, DocumentStyleSet } from "../style-sets/types.js";
13
16
  import { CreateEmptyDocumentOptions, createEmptyDocument } from "../utils/createDocument.js";
14
17
  import { mergeDocumentContent } from "../utils/mergeDocumentContent.js";
@@ -34,4 +37,4 @@ import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled
34
37
  import { DOCX_CONFORMANCE_CLASSES } from "../index.js";
35
38
  type Document = document_d_exports.Document;
36
39
  type DocxConformanceClass = document_d_exports.DocxConformanceClass;
37
- 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 BlockRect, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, 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 FolioAIEditNormalization, type FolioAIEditNormalizationCode, 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 FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidFolioDocumentOperationBatchError, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
40
+ 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 BlockRect, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, CompareDocxApplyError, type CompareDocxError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFormatRange, type CompareResult, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, 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 FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, 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 FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -1,10 +1,13 @@
1
1
  import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
2
- import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
3
- import { diffWordSegments } from "../ai-edits/word-diff.js";
2
+ import { createFolioAIEditSnapshot, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
3
+ import { WORD_DIFF_GRANULARITIES, diffWordSegments } from "../ai-edits/word-diff.js";
4
4
  import { applySuggestions } from "../ai-suggestions/apply.js";
5
5
  import { isSuggestionStale, resolveSuggestionAnchor } from "../ai-suggestions/conflict.js";
6
6
  import { buildPositionalText } from "../ai-suggestions/text-positions.js";
7
7
  import { DEFAULT_AI_SUGGESTION_PRESETS } from "../ai-suggestions/types.js";
8
+ import { MAX_COMPARE_OPERATIONS, compareDocx } from "../compare/compare.js";
9
+ import { COMPARE_UNSUPPORTED_REASONS, CompareDocxApplyError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, InvalidCompareDocxOptionsError } from "../compare/types.js";
10
+ import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS } from "../compare/verification.js";
8
11
  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";
9
12
  import { inspectDocxCompatibility } from "../docx/compatibility.js";
10
13
  import { createDocx } from "../docx/rezip.js";
@@ -28,4 +31,4 @@ import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialF
28
31
  import { createEmptyDocument } from "../utils/createDocument.js";
29
32
  import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled } from "../utils/fontResolver.js";
30
33
  import { mergeDocumentContent } from "../utils/mergeDocumentContent.js";
31
- export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, 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, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
34
+ export { COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareDocxApplyError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, 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, InvalidCompareDocxOptionsError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -7,6 +7,7 @@ import { ConvertHeaderFooterOptions, HeaderFooterMetrics } from "../layout-bridg
7
7
  import "../layout-engine/index.js";
8
8
  import { FootnoteRenderItem } from "../layout-painter/renderPage.js";
9
9
  import { BlockLookup, LayoutPainter } from "../layout-painter/index.js";
10
+ import { PageRendererName } from "../display-list/editor/pageRenderer.js";
10
11
  import { LayoutSelectionGate } from "../paged-layout/LayoutSelectionGate.js";
11
12
  import { LayoutSession } from "./layoutSession.js";
12
13
  import { EditorState } from "prosemirror-state";
@@ -59,6 +60,18 @@ type LayoutPipelineDeps<THfPMs> = {
59
60
  documentFontsAreLoaded: () => boolean;
60
61
  buildFootnoteRenderItems: (pageFootnoteMap: Map<number, number[]>, footnoteContentMap: Map<number, FootnoteContent>, doc: document_d_exports.Document | null) => Map<number, FootnoteRenderItem[]>;
61
62
  describeInvalidHighlightMarks: (doc: EditorState["doc"]) => string;
63
+ /**
64
+ * Which renderer paints the pages. `"legacy"` is the painter that has always
65
+ * painted them; `"display-list"` builds the painter-neutral paint IR from
66
+ * this layout and paints the pages from it, so the editor and an export draw
67
+ * from one structure.
68
+ *
69
+ * Only the *painting* is swapped. Page shells, virtualization, the
70
+ * fingerprint comparison that skips an unchanged page and the painted event
71
+ * are page-container concerns and stay shared, because a second copy of them
72
+ * is how incremental repaint would quietly stop working on long documents.
73
+ */
74
+ pageRenderer?: PageRendererName;
62
75
  emptyTemplatePreviewEntries: readonly TemplatePreviewEntry[];
63
76
  };
64
77
  declare function runLayoutPipeline<THfPMs>(deps: LayoutPipelineDeps<THfPMs>, state: EditorState, options?: LayoutRunOptions): LayoutOutcome;
@@ -1,3 +1,5 @@
1
+ import { createDisplayListPagePainter } from "../display-list/editor/displayListPagePainter.js";
2
+ import { PAGE_RENDERER, displayListFurnitureFrom } from "../display-list/editor/pageRenderer.js";
1
3
  import { resolveDocumentGridLinePitch } from "../docx/documentGrid.js";
2
4
  import { buildBookmarkPageMap } from "../fields/bookmarkPages.js";
3
5
  import { buildBookmarkText } from "../fields/bookmarkText.js";
@@ -15,6 +17,7 @@ import { recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayou
15
17
  import { measureBlocks, measureSingleBlockWithoutFloatingZones } from "../layout-engine/measure/measureBlocks.js";
16
18
  import { installCanvasMeasureProvider } from "../layout-engine/measure/measureContainer.js";
17
19
  import { resolveEffectiveParagraphSpacingTree } from "../layout-engine/paragraphSpacing.js";
20
+ import { resolveTableIndentCompatibility } from "../layout-engine/tableIndentCompatibility.js";
18
21
  import "../layout-engine/types.js";
19
22
  import { renderPages } from "../layout-painter/renderPage.js";
20
23
  import { tryBuildIncrementalMeasures } from "../paged-layout/incrementalMeasure.js";
@@ -84,7 +87,7 @@ function attachAuthoredMarginsToLayoutPages(layout, options) {
84
87
  } : layout;
85
88
  }
86
89
  function runLayoutPipeline(deps, state, options = {}) {
87
- const { contentWidth, columns, pageSize, margins, pageGap, showMarginGuides, marginGuideColor, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
90
+ const { contentWidth, columns, pageSize, margins, pageGap, showMarginGuides, marginGuideColor, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, pageRenderer = PAGE_RENDERER.legacy, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
88
91
  let outcome = {};
89
92
  let pendingArtifacts;
90
93
  let pendingTemplatePreview;
@@ -110,6 +113,8 @@ function runLayoutPipeline(deps, state, options = {}) {
110
113
  const documentSettings = document?.package.settings;
111
114
  const justificationCompatibility = resolveJustificationCompatibility(documentSettings?.compatibilityMode);
112
115
  if (justificationCompatibility) flowOpts.justificationCompatibility = justificationCompatibility;
116
+ const tableIndentCompatibility = resolveTableIndentCompatibility(documentSettings?.compatibilityMode);
117
+ if (tableIndentCompatibility) flowOpts.tableIndentCompatibility = tableIndentCompatibility;
113
118
  if (documentSettings?.autoHyphenation === true) flowOpts.automaticHyphenation = {
114
119
  enabled: true,
115
120
  ...documentSettings.doNotHyphenateCaps !== void 0 ? { doNotHyphenateCaps: documentSettings.doNotHyphenateCaps } : {},
@@ -166,6 +171,7 @@ function runLayoutPipeline(deps, state, options = {}) {
166
171
  ...defaultTabStop !== void 0 ? { defaultTabStopTwips: defaultTabStop } : {},
167
172
  ...flowOpts.lineBreakRules ? { lineBreakRules: flowOpts.lineBreakRules } : {},
168
173
  ...flowOpts.justificationCompatibility ? { justificationCompatibility: flowOpts.justificationCompatibility } : {},
174
+ ...flowOpts.tableIndentCompatibility ? { tableIndentCompatibility: flowOpts.tableIndentCompatibility } : {},
169
175
  ...flowOpts.automaticHyphenation ? { automaticHyphenation: flowOpts.automaticHyphenation } : {}
170
176
  };
171
177
  };
@@ -312,6 +318,7 @@ function runLayoutPipeline(deps, state, options = {}) {
312
318
  if (defaultTabStop !== void 0) footnoteOptions.defaultTabStopTwips = defaultTabStop;
313
319
  if (flowOpts.lineBreakRules) footnoteOptions.lineBreakRules = flowOpts.lineBreakRules;
314
320
  if (flowOpts.justificationCompatibility) footnoteOptions.justificationCompatibility = flowOpts.justificationCompatibility;
321
+ if (flowOpts.tableIndentCompatibility) footnoteOptions.tableIndentCompatibility = flowOpts.tableIndentCompatibility;
315
322
  if (flowOpts.automaticHyphenation) footnoteOptions.automaticHyphenation = flowOpts.automaticHyphenation;
316
323
  return footnoteOptions;
317
324
  })());
@@ -479,6 +486,13 @@ function runLayoutPipeline(deps, state, options = {}) {
479
486
  if (watermarkByHeaderRId.size > 0) renderOpts.watermarkByHeaderRId = watermarkByHeaderRId;
480
487
  }
481
488
  }
489
+ if (pageRenderer === PAGE_RENDERER.displayList) renderOpts.paintPage = createDisplayListPagePainter({
490
+ layout: newLayout,
491
+ blockLookup,
492
+ doc: pagesContainer.ownerDocument,
493
+ ...displayListFurnitureFrom(renderOpts),
494
+ ...footnoteContentMap.size === 0 ? {} : { footnoteContentById: footnoteContentMap }
495
+ }).paintPage;
482
496
  renderPages(newLayout.pages, pagesContainer, renderOpts);
483
497
  recordPhaseDuration("render-pages", phaseStartedAt);
484
498
  }
@@ -0,0 +1,39 @@
1
+ import { DisplayColor, DisplayLink, DisplayLinkTarget, DisplayStoryRef } from "../types.js";
2
+ import { FontTable } from "./fontTable.js";
3
+ import { ImageTable } from "./imagePrimitives.js";
4
+ import { UnsupportedCollector } from "./unsupported.js";
5
+ //#region src/display-list/build/buildContext.d.ts
6
+ /** Word's per-author redline palette, assigned in first-seen order per build. */
7
+ declare class AuthorColorTable {
8
+ private readonly indexByAuthor;
9
+ colorFor(author: string | undefined): DisplayColor;
10
+ }
11
+ /** Colour a tracked change paints in: the author's hue, or the proposal hue. */
12
+ declare const trackedChangeColor: (authorColors: AuthorColorTable, changeAuthor: string | undefined, isSuggestion: boolean | undefined) => DisplayColor;
13
+ /**
14
+ * Which OOXML story the primitives being built belong to, named precisely
15
+ * enough to address it: a document has many headers and many notes, and a
16
+ * position only means something against one of them.
17
+ */
18
+ type DisplayStory = DisplayStoryRef;
19
+ type BuildContext = {
20
+ readonly fonts: FontTable;
21
+ readonly images: ImageTable;
22
+ readonly unsupported: UnsupportedCollector;
23
+ readonly authorColors: AuthorColorTable;
24
+ /** Link sink for the page being built. */
25
+ readonly links: DisplayLink[];
26
+ /**
27
+ * Bookmark name → where it lands, collected in a first pass over the layout.
28
+ * A `#name` hyperlink can only become a `page` target once every page is
29
+ * known, which is why this is resolved before any page is painted.
30
+ */
31
+ readonly bookmarkTargets: ReadonlyMap<string, DisplayLinkTarget>;
32
+ readonly story: DisplayStory;
33
+ readonly pageIndex: number;
34
+ /** Authored page number, for `PAGE` fields. */
35
+ readonly pageNumber: number;
36
+ readonly totalPages: number;
37
+ };
38
+ //#endregion
39
+ export { AuthorColorTable, BuildContext, DisplayStory, trackedChangeColor };
@@ -0,0 +1,31 @@
1
+ import { AUTHOR_COLORS } from "../../utils/authorColors.js";
2
+ import { SUGGESTION_COLOR, parseDisplayColor } from "./colors.js";
3
+ //#region src/display-list/build/buildContext.ts
4
+ /**
5
+ * State threaded through one `buildDisplayList` call.
6
+ *
7
+ * Everything mutable the builder needs lives here so the builder itself stays a
8
+ * pure function of its arguments: the font table, the image table, the
9
+ * unsupported log and the author-colour assignment are all born and die inside
10
+ * a single call. `utils/authorColors.ts`'s `getAuthorColorIdx` deliberately is
11
+ * not used: it keeps a module-level map, so the colour an author gets depends
12
+ * on which documents the process opened earlier, and two builds of the same
13
+ * layout would not compare equal.
14
+ */
15
+ /** Word's per-author redline palette, assigned in first-seen order per build. */
16
+ var AuthorColorTable = class {
17
+ indexByAuthor = /* @__PURE__ */ new Map();
18
+ colorFor(author) {
19
+ const key = author ?? "";
20
+ let index = this.indexByAuthor.get(key);
21
+ if (index === void 0) {
22
+ index = this.indexByAuthor.size % AUTHOR_COLORS.length;
23
+ this.indexByAuthor.set(key, index);
24
+ }
25
+ return parseDisplayColor(AUTHOR_COLORS[index]) ?? SUGGESTION_COLOR;
26
+ }
27
+ };
28
+ /** Colour a tracked change paints in: the author's hue, or the proposal hue. */
29
+ const trackedChangeColor = (authorColors, changeAuthor, isSuggestion) => isSuggestion ? SUGGESTION_COLOR : authorColors.colorFor(changeAuthor);
30
+ //#endregion
31
+ export { AuthorColorTable, trackedChangeColor };
@@ -0,0 +1,79 @@
1
+ import { EmbeddedFont } from "../../fonts/embeddedFonts.js";
2
+ import { Layout } from "../../layout-engine/types.js";
3
+ import { BlockLookup } from "../../layout-painter/index.js";
4
+ import { DisplayColor, DisplayList, DisplayMetadata, DisplayPage } from "../types.js";
5
+ import { PageFurnitureInputs } from "./furniture.js";
6
+ //#region src/display-list/build/buildDisplayList.d.ts
7
+ /**
8
+ * Every feature a source document can have that a `Layout` does not record and
9
+ * that nothing on a page betrays, with the reason it paints nothing when the
10
+ * caller supplies neither the construct nor a flag denying it. The list is the
11
+ * single source of truth: {@link DocumentFeatures} is derived from it, so a
12
+ * feature added here cannot be left without a flag or without a reason.
13
+ *
14
+ * Footnote bodies and header/footer stories are deliberately absent: a page
15
+ * that carries them says so itself (`footnoteIds`, `headerFooterRefs`), so
16
+ * their gaps are reported per page from the layout rather than from a
17
+ * document-wide flag the caller would have to remember to set.
18
+ */
19
+ declare const DOCUMENT_FEATURE_GAPS: readonly [readonly ["pageBorders", "w:pgBorders reach the painter through render options, not through Layout, and none were supplied to the builder"], readonly ["watermark", "watermarks reach the painter through render options, not through Layout, and none was supplied to the builder"]];
20
+ /**
21
+ * Which of those features the source document actually has. The builder cannot
22
+ * detect them, so the caller that parsed the document states it.
23
+ */
24
+ type DocumentFeatures = { readonly [Feature in (typeof DOCUMENT_FEATURE_GAPS)[number][0]]: boolean; };
25
+ type BuildDisplayListOptions = PageFurnitureInputs & {
26
+ readonly layout: Layout;
27
+ readonly blockLookup: BlockLookup;
28
+ readonly metadata?: DisplayMetadata;
29
+ /** Page background. Defaults to opaque white: the PDF has no theme. */
30
+ readonly pageBackground?: DisplayColor;
31
+ /**
32
+ * States, for each construct in {@link DOCUMENT_FEATURE_GAPS}, whether the
33
+ * document has one at all. Omitted means unknown, and an unknown document is
34
+ * reported as having both: a silent gap is worse than one the reader can
35
+ * dismiss. A construct supplied through {@link PageFurnitureInputs} is
36
+ * painted and never reported, whatever this says.
37
+ */
38
+ readonly documentFeatures?: DocumentFeatures;
39
+ /**
40
+ * The package's own font faces (`fonts/embeddedFonts.ts`). Absent: a face the
41
+ * measurer resolved to an embedded family travels as a name, and a backend
42
+ * that cannot find that name on the host paints the document in a substitute.
43
+ */
44
+ readonly embeddedFonts?: readonly EmbeddedFont[];
45
+ };
46
+ /**
47
+ * A document's display list, one page at a time.
48
+ *
49
+ * The tables a page refers to (faces, images), the bookmark targets a link can
50
+ * resolve against, and the outline are properties of the whole document, so
51
+ * they are computed once; a page's primitives are not, and an editor paints a
52
+ * window of pages rather than all of them. Building every page to paint three
53
+ * of them is the difference between work proportional to the screen and work
54
+ * proportional to the document, which on a long one is the difference a reader
55
+ * feels on every keystroke.
56
+ *
57
+ * A page is built at most once. `snapshot` returns what has been built so far,
58
+ * so a caller that wants the whole list asks for every page first — which is
59
+ * what {@link buildDisplayList} does.
60
+ */
61
+ type DisplayListBuilder = {
62
+ readonly pageCount: number;
63
+ /** The page at that index, built on first request and kept. */
64
+ readonly pageAt: (pageIndex: number) => DisplayPage | undefined;
65
+ /**
66
+ * The list as far as it has been built. The tables grow as pages are built,
67
+ * so a backend reads them after the page it is about to paint, never before.
68
+ */
69
+ readonly snapshot: () => DisplayList;
70
+ };
71
+ declare const createDisplayListBuilder: ({ layout, blockLookup, metadata, pageBackground, documentFeatures, embeddedFonts, ...furniture }: BuildDisplayListOptions) => DisplayListBuilder;
72
+ /**
73
+ * The whole document's display list. Every page is built, so the tables, the
74
+ * outline and the gap report are complete; an editor that paints a window of
75
+ * pages uses {@link createDisplayListBuilder} instead.
76
+ */
77
+ declare const buildDisplayList: (options: BuildDisplayListOptions) => DisplayList;
78
+ //#endregion
79
+ export { BuildDisplayListOptions, DisplayListBuilder, DocumentFeatures, buildDisplayList, createDisplayListBuilder };