@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.
- package/dist/ai-edits/__fixtures__/paragraphs.d.ts +17 -0
- package/dist/ai-edits/__fixtures__/paragraphs.js +33 -0
- package/dist/ai-edits/apply.d.ts +49 -3
- package/dist/ai-edits/apply.js +649 -85
- package/dist/ai-edits/blockRange.d.ts +7 -3
- package/dist/ai-edits/blockRange.js +14 -6
- package/dist/ai-edits/headless.d.ts +39 -5
- package/dist/ai-edits/headless.js +76 -17
- package/dist/ai-edits/index.d.ts +6 -6
- package/dist/ai-edits/index.js +3 -3
- package/dist/ai-edits/read.d.ts +4 -0
- package/dist/ai-edits/read.js +30 -6
- package/dist/ai-edits/scoped-reading.js +4 -3
- package/dist/ai-edits/snapshot.d.ts +42 -2
- package/dist/ai-edits/snapshot.js +127 -62
- package/dist/ai-edits/table-row-column-mutations.d.ts +24 -1
- package/dist/ai-edits/table-row-column-mutations.js +98 -6
- package/dist/ai-edits/table-targets.d.ts +12 -3
- package/dist/ai-edits/table-targets.js +15 -5
- package/dist/ai-edits/types.d.ts +219 -15
- package/dist/ai-edits/word-diff.d.ts +54 -11
- package/dist/ai-edits/word-diff.js +221 -61
- package/dist/compare/__fixtures__/body-sequence.d.ts +33 -0
- package/dist/compare/__fixtures__/body-sequence.js +67 -0
- package/dist/compare/__fixtures__/nested-table.d.ts +16 -0
- package/dist/compare/__fixtures__/nested-table.js +50 -0
- package/dist/compare/__fixtures__/numbered-list.d.ts +34 -0
- package/dist/compare/__fixtures__/numbered-list.js +85 -0
- package/dist/compare/column-alignment.d.ts +27 -0
- package/dist/compare/column-alignment.js +162 -0
- package/dist/compare/compare.d.ts +107 -0
- package/dist/compare/compare.js +406 -0
- package/dist/compare/formatting.d.ts +29 -0
- package/dist/compare/formatting.js +84 -0
- package/dist/compare/plan.d.ts +22 -0
- package/dist/compare/plan.js +1059 -0
- package/dist/compare/reproducible-package.d.ts +17 -0
- package/dist/compare/reproducible-package.js +30 -0
- package/dist/compare/scenario.d.ts +77 -0
- package/dist/compare/scenario.js +263 -0
- package/dist/compare/types.d.ts +282 -0
- package/dist/compare/types.js +32 -0
- package/dist/compare/verification.d.ts +55 -0
- package/dist/compare/verification.js +146 -0
- package/dist/compat/eigenpal.d.ts +9 -6
- package/dist/compat/eigenpal.js +6 -3
- package/dist/controller/layoutPipeline.d.ts +13 -0
- package/dist/controller/layoutPipeline.js +15 -1
- package/dist/display-list/build/buildContext.d.ts +39 -0
- package/dist/display-list/build/buildContext.js +31 -0
- package/dist/display-list/build/buildDisplayList.d.ts +79 -0
- package/dist/display-list/build/buildDisplayList.js +283 -0
- package/dist/display-list/build/colors.d.ts +20 -0
- package/dist/display-list/build/colors.js +136 -0
- package/dist/display-list/build/floatingImages.d.ts +24 -0
- package/dist/display-list/build/floatingImages.js +41 -0
- package/dist/display-list/build/fontTable.d.ts +31 -0
- package/dist/display-list/build/fontTable.js +97 -0
- package/dist/display-list/build/furniture.d.ts +86 -0
- package/dist/display-list/build/furniture.js +98 -0
- package/dist/display-list/build/glyphs.d.ts +55 -0
- package/dist/display-list/build/glyphs.js +103 -0
- package/dist/display-list/build/headerFooterPrimitives.d.ts +17 -0
- package/dist/display-list/build/headerFooterPrimitives.js +40 -0
- package/dist/display-list/build/imagePrimitives.d.ts +35 -0
- package/dist/display-list/build/imagePrimitives.js +264 -0
- package/dist/display-list/build/pageBorderPrimitives.d.ts +23 -0
- package/dist/display-list/build/pageBorderPrimitives.js +111 -0
- package/dist/display-list/build/pageFurniture.d.ts +35 -0
- package/dist/display-list/build/pageFurniture.js +141 -0
- package/dist/display-list/build/paragraphPrimitives.d.ts +19 -0
- package/dist/display-list/build/paragraphPrimitives.js +819 -0
- package/dist/display-list/build/regions.d.ts +46 -0
- package/dist/display-list/build/regions.js +56 -0
- package/dist/display-list/build/storyPrimitives.d.ts +29 -0
- package/dist/display-list/build/storyPrimitives.js +279 -0
- package/dist/display-list/build/strokes.d.ts +19 -0
- package/dist/display-list/build/strokes.js +78 -0
- package/dist/display-list/build/tablePrimitives.d.ts +38 -0
- package/dist/display-list/build/tablePrimitives.js +409 -0
- package/dist/display-list/build/textBoxPrimitives.d.ts +14 -0
- package/dist/display-list/build/textBoxPrimitives.js +129 -0
- package/dist/display-list/build/textDecorations.d.ts +29 -0
- package/dist/display-list/build/textDecorations.js +29 -0
- package/dist/display-list/build/unsupported.d.ts +57 -0
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/build/watermarkPrimitives.d.ts +15 -0
- package/dist/display-list/build/watermarkPrimitives.js +128 -0
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +26 -0
- package/dist/display-list/dom/renderDisplayListToDom.js +620 -0
- package/dist/display-list/editor/displayListPagePainter.d.ts +22 -0
- package/dist/display-list/editor/displayListPagePainter.js +63 -0
- package/dist/display-list/editor/pageRenderer.d.ts +24 -0
- package/dist/display-list/editor/pageRenderer.js +36 -0
- package/dist/display-list/primitives.d.ts +95 -0
- package/dist/display-list/primitives.js +127 -0
- package/dist/display-list/types.d.ts +472 -0
- package/dist/display-list/types.js +0 -0
- package/dist/document-operations.d.ts +39 -8
- package/dist/document-operations.js +169 -16
- package/dist/document-stories.d.ts +16 -0
- package/dist/document-stories.js +48 -4
- package/dist/docx/packageParts.d.ts +35 -0
- package/dist/docx/packageParts.js +120 -0
- package/dist/docx/paragraphParser.js +22 -22
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/renderedPageBreakNormalization.js +3 -1
- package/dist/docx/revisionIdNormalization.d.ts +13 -0
- package/dist/docx/revisionIdNormalization.js +103 -0
- package/dist/docx/rezip.js +26 -17
- package/dist/docx/selectiveSave.js +2 -2
- package/dist/docx/serializer/commentSerializer.js +6 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -4
- package/dist/docx/serializer/runSerializer.js +11 -10
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +1 -1
- package/dist/docx/server/createBilingualDocx.js +3 -2
- package/dist/docx/streamingXmlParser.d.ts +13 -1
- package/dist/docx/streamingXmlParser.js +49 -11
- package/dist/docx/unzip.d.ts +1 -2
- package/dist/docx/unzip.js +25 -6
- package/dist/docx/xmlParser.d.ts +3 -1
- package/dist/docx/xmlParser.js +33 -27
- package/dist/export-pdf.d.ts +43 -0
- package/dist/export-pdf.js +98 -0
- package/dist/fonts/headlessMeasure.d.ts +76 -0
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/fonts/sfnt/parse.d.ts +51 -0
- package/dist/fonts/sfnt/parse.js +525 -0
- package/dist/fonts/sfnt/subset.d.ts +20 -0
- package/dist/fonts/sfnt/subset.js +350 -0
- package/dist/fonts/sfnt/tables.d.ts +88 -0
- package/dist/fonts/sfnt/tables.js +131 -0
- package/dist/fonts/sfnt/woff.d.ts +14 -0
- package/dist/fonts/sfnt/woff.js +163 -0
- package/dist/generated/text_shaper.js +324 -0
- package/dist/generated/text_shaper_bg.wasm +0 -0
- package/dist/headless-layout.d.ts +75 -0
- package/dist/headless-layout.js +350 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +6 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -0
- package/dist/layout-engine/measure/advanceComposition.d.ts +62 -0
- package/dist/layout-engine/measure/advanceComposition.js +148 -0
- package/dist/layout-engine/measure/cache.d.ts +2 -0
- package/dist/layout-engine/measure/measureContainer.js +13 -0
- package/dist/layout-engine/measure/measureParagraph.js +1 -2
- package/dist/layout-engine/measure/measureTypes.d.ts +12 -0
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +3 -2
- package/dist/layout-engine/measure/tableInlinePlacement.js +14 -1
- package/dist/layout-engine/tableIndentCompatibility.d.ts +5 -0
- package/dist/layout-engine/tableIndentCompatibility.js +15 -0
- package/dist/layout-engine/types.d.ts +8 -0
- package/dist/layout-painter/renderPage.d.ts +29 -1
- package/dist/layout-painter/renderPage.js +47 -19
- package/dist/layout-painter/renderParagraph.d.ts +21 -2
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/layout-painter/renderTable.js +37 -4
- package/dist/managers/editorShortcuts.d.ts +33 -1
- package/dist/managers/editorShortcuts.js +20 -1
- package/dist/markdown/renderRuns.js +7 -2
- package/dist/markdown/renderTable.js +5 -1
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/pdf/contentStream.d.ts +73 -0
- package/dist/pdf/contentStream.js +143 -0
- package/dist/pdf/fonts.d.ts +96 -0
- package/dist/pdf/fonts.js +593 -0
- package/dist/pdf/images.d.ts +28 -0
- package/dist/pdf/images.js +439 -0
- package/dist/pdf/objects.d.ts +93 -0
- package/dist/pdf/objects.js +237 -0
- package/dist/pdf/pageSpace.d.ts +43 -0
- package/dist/pdf/pageSpace.js +57 -0
- package/dist/pdf/paint.d.ts +32 -0
- package/dist/pdf/paint.js +442 -0
- package/dist/pdf/writePdf.d.ts +56 -0
- package/dist/pdf/writePdf.js +345 -0
- package/dist/prosemirror/commands/comments.js +91 -6
- package/dist/prosemirror/conversion/fromProseDoc.js +41 -7
- package/dist/prosemirror/conversion/toProseDoc.js +41 -4
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +15 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +35 -6
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +2 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +4 -3
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +3 -1
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +5 -3
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +9 -3
- package/dist/prosemirror/extensions/nodes/TableExtension.js +56 -39
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +3 -1
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +5 -3
- package/dist/prosemirror/plugins/suggestionMode.js +1 -0
- package/dist/prosemirror/revisionCarriers.js +19 -2
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +2 -2
- package/dist/prosemirror/utils/extractTrackedChanges.js +59 -23
- package/dist/prosemirror/validation.js +55 -27
- package/dist/prosemirror/zeroWidthAnchors.d.ts +10 -0
- package/dist/prosemirror/zeroWidthAnchors.js +23 -0
- package/dist/redline.js +12 -79
- package/dist/server.d.ts +3 -3
- package/dist/server.js +2 -2
- package/dist/shaping/placeRun.d.ts +51 -0
- package/dist/shaping/placeRun.js +84 -0
- package/dist/shaping/shaper.d.ts +92 -0
- package/dist/shaping/shaper.js +102 -0
- package/dist/types/block-id.d.ts +18 -2
- package/dist/types/block-id.js +49 -5
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/clipboard.js +4 -3
- package/dist/utils/fontResolver.js +183 -0
- package/dist/utils/htmlComments.d.ts +17 -0
- package/dist/utils/htmlComments.js +22 -0
- package/dist/utils/scriptSegments.d.ts +12 -1
- package/dist/utils/scriptSegments.js +17 -1
- package/dist/version-comparison.d.ts +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/compare/reproducible-package.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The last clock in the compare path is the ZIP container itself.
|
|
4
|
+
*
|
|
5
|
+
* Every part the serializer rewrites is stored with JSZip's default entry
|
|
6
|
+
* date, which is `new Date()`. The XML is identical between two runs, but the
|
|
7
|
+
* DOS timestamp fields in the local headers are not, and they only agree when
|
|
8
|
+
* both runs land in the same two-second bucket — so the packages match most of
|
|
9
|
+
* the time and differ occasionally, which is worse than differing always.
|
|
10
|
+
*
|
|
11
|
+
* Restamping every entry from the comparison's own timestamp removes it. It
|
|
12
|
+
* also states the truth about the package: a generated redline is dated by the
|
|
13
|
+
* comparison that produced it, not by the second it happened to be written.
|
|
14
|
+
*/
|
|
15
|
+
declare const withFixedPackageDates: (buffer: ArrayBuffer, date: Date) => Promise<ArrayBuffer>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { withFixedPackageDates };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import JSZip from "jszip";
|
|
2
|
+
//#region src/compare/reproducible-package.ts
|
|
3
|
+
/**
|
|
4
|
+
* The last clock in the compare path is the ZIP container itself.
|
|
5
|
+
*
|
|
6
|
+
* Every part the serializer rewrites is stored with JSZip's default entry
|
|
7
|
+
* date, which is `new Date()`. The XML is identical between two runs, but the
|
|
8
|
+
* DOS timestamp fields in the local headers are not, and they only agree when
|
|
9
|
+
* both runs land in the same two-second bucket — so the packages match most of
|
|
10
|
+
* the time and differ occasionally, which is worse than differing always.
|
|
11
|
+
*
|
|
12
|
+
* Restamping every entry from the comparison's own timestamp removes it. It
|
|
13
|
+
* also states the truth about the package: a generated redline is dated by the
|
|
14
|
+
* comparison that produced it, not by the second it happened to be written.
|
|
15
|
+
*/
|
|
16
|
+
/** JSZip deflate level `repackDocx` writes DOCX parts at. */
|
|
17
|
+
const DOCX_COMPRESSION_LEVEL = 6;
|
|
18
|
+
const withFixedPackageDates = async (buffer, date) => {
|
|
19
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
20
|
+
zip.forEach((_path, file) => {
|
|
21
|
+
file.date = date;
|
|
22
|
+
});
|
|
23
|
+
return await zip.generateAsync({
|
|
24
|
+
type: "arraybuffer",
|
|
25
|
+
compression: "DEFLATE",
|
|
26
|
+
compressionOptions: { level: DOCX_COMPRESSION_LEVEL }
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { withFixedPackageDates };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { FolioAIInlineFormatting } from "../ai-edits/types.js";
|
|
2
|
+
import { CompareDocxParseError, CompareDocxSerializeError } from "./types.js";
|
|
3
|
+
import { Result } from "better-result";
|
|
4
|
+
//#region src/compare/scenario.d.ts
|
|
5
|
+
type EditScriptStep = {
|
|
6
|
+
type: "insertParagraphAfter";
|
|
7
|
+
blockIndex: number;
|
|
8
|
+
text: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: "deleteParagraph";
|
|
11
|
+
blockIndex: number;
|
|
12
|
+
} | {
|
|
13
|
+
type: "replaceWords";
|
|
14
|
+
blockIndex: number;
|
|
15
|
+
find: string;
|
|
16
|
+
replace: string;
|
|
17
|
+
} |
|
|
18
|
+
/** Delete the block at `blockIndex` and reinsert its text before `beforeBlockIndex`. */
|
|
19
|
+
{
|
|
20
|
+
type: "moveParagraph";
|
|
21
|
+
blockIndex: number;
|
|
22
|
+
beforeBlockIndex: number;
|
|
23
|
+
} |
|
|
24
|
+
/**
|
|
25
|
+
* Break one paragraph into two at `wordIndex`, which is an inserted
|
|
26
|
+
* paragraph mark and nothing else: both halves keep their words.
|
|
27
|
+
*/
|
|
28
|
+
{
|
|
29
|
+
type: "splitParagraph";
|
|
30
|
+
blockIndex: number;
|
|
31
|
+
wordIndex: number;
|
|
32
|
+
} |
|
|
33
|
+
/**
|
|
34
|
+
* Join the block at `blockIndex` with the one after it, which is a deleted
|
|
35
|
+
* paragraph mark and nothing else.
|
|
36
|
+
*/
|
|
37
|
+
{
|
|
38
|
+
type: "mergeParagraphs";
|
|
39
|
+
blockIndex: number;
|
|
40
|
+
} | {
|
|
41
|
+
type: "formatRange";
|
|
42
|
+
blockIndex: number;
|
|
43
|
+
startOffset: number;
|
|
44
|
+
endOffset: number;
|
|
45
|
+
formatting: FolioAIInlineFormatting;
|
|
46
|
+
} | {
|
|
47
|
+
type: "insertTableRow";
|
|
48
|
+
blockIndex: number;
|
|
49
|
+
cellTexts: readonly string[];
|
|
50
|
+
} | {
|
|
51
|
+
type: "deleteTableRow";
|
|
52
|
+
blockIndex: number;
|
|
53
|
+
} | {
|
|
54
|
+
type: "editTableCell";
|
|
55
|
+
blockIndex: number;
|
|
56
|
+
text: string;
|
|
57
|
+
};
|
|
58
|
+
type EditScript = readonly EditScriptStep[];
|
|
59
|
+
declare const EDIT_SCRIPT_UNRESOLVED_REASONS: readonly ["block-out-of-range", "block-not-in-table", "range-out-of-bounds", "text-not-found", "no-paragraph-boundary", "refused"];
|
|
60
|
+
type EditScriptUnresolvedReason = (typeof EDIT_SCRIPT_UNRESOLVED_REASONS)[number];
|
|
61
|
+
type EditScriptUnresolvedStep = {
|
|
62
|
+
step: EditScriptStep;
|
|
63
|
+
reason: EditScriptUnresolvedReason;
|
|
64
|
+
};
|
|
65
|
+
type EditScriptResult = {
|
|
66
|
+
/** The base document with every applied step written in directly. */
|
|
67
|
+
buffer: ArrayBuffer;
|
|
68
|
+
/** The steps that reached the document, in script order. */
|
|
69
|
+
applied: readonly EditScriptStep[];
|
|
70
|
+
unresolved: readonly EditScriptUnresolvedStep[];
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Apply `script` to `base` directly and return the resulting target document.
|
|
74
|
+
*/
|
|
75
|
+
declare const applyEditScript: (base: ArrayBuffer, script: EditScript) => Promise<Result<EditScriptResult, CompareDocxParseError | CompareDocxSerializeError>>;
|
|
76
|
+
//#endregion
|
|
77
|
+
export { EDIT_SCRIPT_UNRESOLVED_REASONS, EditScript, EditScriptResult, EditScriptStep, EditScriptUnresolvedReason, EditScriptUnresolvedStep, applyEditScript };
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { FolioDocxReviewer } from "../ai-edits/headless.js";
|
|
2
|
+
import { createFolioAITextRangeHandle } from "../ai-edits/snapshot.js";
|
|
3
|
+
import { CompareDocxParseError, CompareDocxSerializeError } from "./types.js";
|
|
4
|
+
import { Result, panic } from "better-result";
|
|
5
|
+
//#region src/compare/scenario.ts
|
|
6
|
+
/**
|
|
7
|
+
* Edit scripts: ground truth for the compare engine, by construction.
|
|
8
|
+
*
|
|
9
|
+
* A property test cannot assert "this redline is right" against a document it
|
|
10
|
+
* only guessed at. It can assert it against a document it BUILT: take a real
|
|
11
|
+
* base, apply a scripted edit directly (no tracked changes), and the result is
|
|
12
|
+
* a target whose difference from the base is known exactly. `compareDocx` then
|
|
13
|
+
* has to rediscover that difference, and the script says what it should have
|
|
14
|
+
* found.
|
|
15
|
+
*
|
|
16
|
+
* Every step is applied through the same headless applier `compareDocx` writes
|
|
17
|
+
* its own operations through, in `"direct"` mode — so the target is an ordinary
|
|
18
|
+
* document, not one carrying revisions the comparison would have to resolve
|
|
19
|
+
* first.
|
|
20
|
+
*
|
|
21
|
+
* Steps address blocks by their index in the base story's block list rather
|
|
22
|
+
* than by id, so a generator can pick targets without first parsing the
|
|
23
|
+
* document. A step that does not resolve is reported in `unresolved`, never
|
|
24
|
+
* dropped: a script silently doing less than it says would weaken every
|
|
25
|
+
* property built on it.
|
|
26
|
+
*/
|
|
27
|
+
const EDIT_SCRIPT_UNRESOLVED_REASONS = Object.freeze([
|
|
28
|
+
"block-out-of-range",
|
|
29
|
+
"block-not-in-table",
|
|
30
|
+
"range-out-of-bounds",
|
|
31
|
+
"text-not-found",
|
|
32
|
+
"no-paragraph-boundary",
|
|
33
|
+
"refused"
|
|
34
|
+
]);
|
|
35
|
+
const blockAt = (blocks, index) => Number.isInteger(index) && index >= 0 ? blocks.at(index) : void 0;
|
|
36
|
+
const planStep = ({ step, blocks, nextOperationId }) => {
|
|
37
|
+
const block = blockAt(blocks, step.blockIndex);
|
|
38
|
+
if (!block) return {
|
|
39
|
+
status: "unresolved",
|
|
40
|
+
reason: "block-out-of-range"
|
|
41
|
+
};
|
|
42
|
+
switch (step.type) {
|
|
43
|
+
case "insertParagraphAfter": return {
|
|
44
|
+
status: "planned",
|
|
45
|
+
operations: [{
|
|
46
|
+
id: nextOperationId(),
|
|
47
|
+
type: "insertAfterBlock",
|
|
48
|
+
blockId: block.id,
|
|
49
|
+
text: step.text
|
|
50
|
+
}]
|
|
51
|
+
};
|
|
52
|
+
case "deleteParagraph": return {
|
|
53
|
+
status: "planned",
|
|
54
|
+
operations: [{
|
|
55
|
+
id: nextOperationId(),
|
|
56
|
+
type: "deleteBlock",
|
|
57
|
+
blockId: block.id
|
|
58
|
+
}]
|
|
59
|
+
};
|
|
60
|
+
case "replaceWords": return block.text.includes(step.find) ? {
|
|
61
|
+
status: "planned",
|
|
62
|
+
operations: [{
|
|
63
|
+
id: nextOperationId(),
|
|
64
|
+
type: "replaceInBlock",
|
|
65
|
+
blockId: block.id,
|
|
66
|
+
find: step.find,
|
|
67
|
+
replace: step.replace
|
|
68
|
+
}]
|
|
69
|
+
} : {
|
|
70
|
+
status: "unresolved",
|
|
71
|
+
reason: "text-not-found"
|
|
72
|
+
};
|
|
73
|
+
case "moveParagraph": {
|
|
74
|
+
const destination = blockAt(blocks, step.beforeBlockIndex);
|
|
75
|
+
if (!destination || destination.id === block.id) return {
|
|
76
|
+
status: "unresolved",
|
|
77
|
+
reason: "block-out-of-range"
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
status: "planned",
|
|
81
|
+
operations: [{
|
|
82
|
+
id: nextOperationId(),
|
|
83
|
+
type: "deleteBlock",
|
|
84
|
+
blockId: block.id
|
|
85
|
+
}, {
|
|
86
|
+
id: nextOperationId(),
|
|
87
|
+
type: "insertBeforeBlock",
|
|
88
|
+
blockId: destination.id,
|
|
89
|
+
text: block.text,
|
|
90
|
+
styleId: block.styleId ?? null,
|
|
91
|
+
listLevel: block.listLevel ?? null
|
|
92
|
+
}]
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
case "splitParagraph": {
|
|
96
|
+
const words = block.text.split(" ");
|
|
97
|
+
if (step.wordIndex <= 0 || step.wordIndex >= words.length) return {
|
|
98
|
+
status: "unresolved",
|
|
99
|
+
reason: "no-paragraph-boundary"
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
status: "planned",
|
|
103
|
+
operations: [{
|
|
104
|
+
id: nextOperationId(),
|
|
105
|
+
type: "replaceBlock",
|
|
106
|
+
blockId: block.id,
|
|
107
|
+
text: words.slice(0, step.wordIndex).join(" ")
|
|
108
|
+
}, {
|
|
109
|
+
id: nextOperationId(),
|
|
110
|
+
type: "insertAfterBlock",
|
|
111
|
+
blockId: block.id,
|
|
112
|
+
text: words.slice(step.wordIndex).join(" "),
|
|
113
|
+
...block.styleId !== void 0 && { styleId: block.styleId }
|
|
114
|
+
}]
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
case "mergeParagraphs": {
|
|
118
|
+
const next = blockAt(blocks, step.blockIndex + 1);
|
|
119
|
+
if (!next || next.table?.cellIndex !== block.table?.cellIndex) return {
|
|
120
|
+
status: "unresolved",
|
|
121
|
+
reason: "no-paragraph-boundary"
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
status: "planned",
|
|
125
|
+
operations: [{
|
|
126
|
+
id: nextOperationId(),
|
|
127
|
+
type: "replaceBlock",
|
|
128
|
+
blockId: block.id,
|
|
129
|
+
text: `${block.text} ${next.text}`
|
|
130
|
+
}, {
|
|
131
|
+
id: nextOperationId(),
|
|
132
|
+
type: "deleteBlock",
|
|
133
|
+
blockId: next.id
|
|
134
|
+
}]
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case "formatRange": {
|
|
138
|
+
const range = createFolioAITextRangeHandle({
|
|
139
|
+
blockId: block.id,
|
|
140
|
+
text: block.text,
|
|
141
|
+
startOffset: step.startOffset,
|
|
142
|
+
endOffset: step.endOffset
|
|
143
|
+
});
|
|
144
|
+
return range ? {
|
|
145
|
+
status: "planned",
|
|
146
|
+
operations: [{
|
|
147
|
+
id: nextOperationId(),
|
|
148
|
+
type: "formatRange",
|
|
149
|
+
range,
|
|
150
|
+
formatting: step.formatting
|
|
151
|
+
}]
|
|
152
|
+
} : {
|
|
153
|
+
status: "unresolved",
|
|
154
|
+
reason: "range-out-of-bounds"
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
case "insertTableRow": return block.table ? {
|
|
158
|
+
status: "planned",
|
|
159
|
+
operations: [{
|
|
160
|
+
id: nextOperationId(),
|
|
161
|
+
type: "insertTableRow",
|
|
162
|
+
blockId: block.id,
|
|
163
|
+
position: "after",
|
|
164
|
+
cellTexts: [...step.cellTexts]
|
|
165
|
+
}]
|
|
166
|
+
} : {
|
|
167
|
+
status: "unresolved",
|
|
168
|
+
reason: "block-not-in-table"
|
|
169
|
+
};
|
|
170
|
+
case "deleteTableRow": return block.table ? {
|
|
171
|
+
status: "planned",
|
|
172
|
+
operations: [{
|
|
173
|
+
id: nextOperationId(),
|
|
174
|
+
type: "deleteTableRow",
|
|
175
|
+
blockId: block.id
|
|
176
|
+
}]
|
|
177
|
+
} : {
|
|
178
|
+
status: "unresolved",
|
|
179
|
+
reason: "block-not-in-table"
|
|
180
|
+
};
|
|
181
|
+
case "editTableCell": return block.table ? {
|
|
182
|
+
status: "planned",
|
|
183
|
+
operations: [{
|
|
184
|
+
id: nextOperationId(),
|
|
185
|
+
type: "replaceBlock",
|
|
186
|
+
blockId: block.id,
|
|
187
|
+
text: step.text
|
|
188
|
+
}]
|
|
189
|
+
} : {
|
|
190
|
+
status: "unresolved",
|
|
191
|
+
reason: "block-not-in-table"
|
|
192
|
+
};
|
|
193
|
+
default: return panic("Unhandled edit script step", { step });
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Apply `script` to `base` directly and return the resulting target document.
|
|
198
|
+
*/
|
|
199
|
+
const applyEditScript = async (base, script) => {
|
|
200
|
+
const parsed = await Result.tryPromise({
|
|
201
|
+
try: async () => await FolioDocxReviewer.fromBuffer(base),
|
|
202
|
+
catch: (cause) => new CompareDocxParseError({
|
|
203
|
+
message: "The edit script's base document could not be parsed.",
|
|
204
|
+
side: "base",
|
|
205
|
+
cause
|
|
206
|
+
})
|
|
207
|
+
});
|
|
208
|
+
if (parsed.isErr()) return Result.err(parsed.error);
|
|
209
|
+
const reviewer = parsed.value;
|
|
210
|
+
const snapshot = reviewer.snapshot();
|
|
211
|
+
const unresolved = [];
|
|
212
|
+
const planned = [];
|
|
213
|
+
let operationSequence = 0;
|
|
214
|
+
const nextOperationId = () => `scenario-${++operationSequence}`;
|
|
215
|
+
for (const step of script) {
|
|
216
|
+
const plan = planStep({
|
|
217
|
+
step,
|
|
218
|
+
blocks: snapshot.blocks,
|
|
219
|
+
nextOperationId
|
|
220
|
+
});
|
|
221
|
+
if (plan.status === "unresolved") {
|
|
222
|
+
unresolved.push({
|
|
223
|
+
step,
|
|
224
|
+
reason: plan.reason
|
|
225
|
+
});
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
planned.push({
|
|
229
|
+
step,
|
|
230
|
+
operations: plan.operations
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const { skipped } = reviewer.applyOperations(planned.flatMap(({ operations }) => [...operations]), {
|
|
234
|
+
mode: "direct",
|
|
235
|
+
snapshot
|
|
236
|
+
});
|
|
237
|
+
const skippedIds = new Set(skipped.map(({ id }) => id));
|
|
238
|
+
const applied = [];
|
|
239
|
+
for (const { step, operations } of planned) {
|
|
240
|
+
if (operations.some(({ id }) => skippedIds.has(id))) {
|
|
241
|
+
unresolved.push({
|
|
242
|
+
step,
|
|
243
|
+
reason: "refused"
|
|
244
|
+
});
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
applied.push(step);
|
|
248
|
+
}
|
|
249
|
+
const serialized = await Result.tryPromise({
|
|
250
|
+
try: async () => await reviewer.toBuffer(),
|
|
251
|
+
catch: (cause) => new CompareDocxSerializeError({
|
|
252
|
+
message: "The edit script's target document could not be serialized.",
|
|
253
|
+
cause
|
|
254
|
+
})
|
|
255
|
+
});
|
|
256
|
+
return serialized.isErr() ? Result.err(serialized.error) : Result.ok({
|
|
257
|
+
buffer: serialized.value,
|
|
258
|
+
applied,
|
|
259
|
+
unresolved
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
//#endregion
|
|
263
|
+
export { EDIT_SCRIPT_UNRESOLVED_REASONS, applyEditScript };
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { FolioAIBlockParagraphProperties, FolioAIBlockTableLocation, FolioAIEditSkippedOperation, FolioAIInlineFormatting } from "../ai-edits/types.js";
|
|
2
|
+
import { WordDiffGranularity } from "../ai-edits/word-diff.js";
|
|
3
|
+
import { FolioDocumentStoryHandle, FolioNumberingLevel } from "../ai-edits/headless.js";
|
|
4
|
+
import { CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant } from "./verification.js";
|
|
5
|
+
//#region src/compare/types.d.ts
|
|
6
|
+
/** Everything {@link compareDocx} needs; nothing it reads from the ambient clock. */
|
|
7
|
+
type CompareDocxOptions = {
|
|
8
|
+
/** Author recorded on every generated tracked change. */
|
|
9
|
+
author: string;
|
|
10
|
+
/**
|
|
11
|
+
* ISO-8601 date stamped on every generated tracked change. Required rather
|
|
12
|
+
* than defaulted so a caller cannot get a nondeterministic package by
|
|
13
|
+
* omission; pass the base document's own timestamp, a release date, or a
|
|
14
|
+
* fixed epoch.
|
|
15
|
+
*/
|
|
16
|
+
timestamp: string;
|
|
17
|
+
/**
|
|
18
|
+
* What to do when the round-trip self-check cannot prove the result.
|
|
19
|
+
*
|
|
20
|
+
* `"refuse"` (default) returns a {@link CompareDocxRoundTripError}: a
|
|
21
|
+
* redline that reads plausibly and is wrong is worse than no redline.
|
|
22
|
+
* `"emit"` returns the redline anyway, with `verification` naming every
|
|
23
|
+
* invariant that did not hold, for a caller that would rather show its best
|
|
24
|
+
* attempt and say what is missing.
|
|
25
|
+
*/
|
|
26
|
+
onUnverified?: "refuse" | "emit";
|
|
27
|
+
/**
|
|
28
|
+
* Token size a changed paragraph's redline is cut at: `"word"` (default)
|
|
29
|
+
* marks whole words, `"character"` marks the changed letters inside one.
|
|
30
|
+
*
|
|
31
|
+
* Case and whitespace normalization are not options here, though
|
|
32
|
+
* `diffWordSegments` offers them: a comparison that leaves a difference
|
|
33
|
+
* unmarked does not accept back to the target, and the round trip is the
|
|
34
|
+
* one thing this call promises.
|
|
35
|
+
*/
|
|
36
|
+
granularity?: WordDiffGranularity;
|
|
37
|
+
};
|
|
38
|
+
/** Where one change sits in the base or target document. */
|
|
39
|
+
type CompareChangeLocation = {
|
|
40
|
+
story: FolioDocumentStoryHandle;
|
|
41
|
+
/** Innermost table cell, when the change is inside a table. */
|
|
42
|
+
cell?: FolioAIBlockTableLocation;
|
|
43
|
+
};
|
|
44
|
+
/** One run of characters whose inline formatting differs, in base-block offsets. */
|
|
45
|
+
type CompareFormatRange = {
|
|
46
|
+
startOffset: number;
|
|
47
|
+
endOffset: number;
|
|
48
|
+
/** Only the properties that differ, set to the target document's value. */
|
|
49
|
+
formatting: FolioAIInlineFormatting;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* One difference between the two documents, in target-document order with
|
|
53
|
+
* base-only entries slotted where they sat. Every variant is plain JSON, so a
|
|
54
|
+
* caller can hand the list to an agent instead of the package.
|
|
55
|
+
*
|
|
56
|
+
* A `move` is reported, not represented: the tracked-change grammar has no
|
|
57
|
+
* "this paragraph came from there" mark that Word round-trips, so the buffer
|
|
58
|
+
* carries a deletion at the source and an insertion at the destination while
|
|
59
|
+
* the change list keeps the relocation visible.
|
|
60
|
+
*/
|
|
61
|
+
type CompareChange = {
|
|
62
|
+
kind: "insert";
|
|
63
|
+
location: CompareChangeLocation;
|
|
64
|
+
/** Id of the inserted block in the target document. */
|
|
65
|
+
targetBlockId: string;
|
|
66
|
+
after: string;
|
|
67
|
+
} | {
|
|
68
|
+
kind: "delete";
|
|
69
|
+
location: CompareChangeLocation;
|
|
70
|
+
baseBlockId: string;
|
|
71
|
+
before: string;
|
|
72
|
+
} | {
|
|
73
|
+
kind: "replace";
|
|
74
|
+
location: CompareChangeLocation;
|
|
75
|
+
baseBlockId: string;
|
|
76
|
+
targetBlockId: string;
|
|
77
|
+
before: string;
|
|
78
|
+
after: string;
|
|
79
|
+
} | {
|
|
80
|
+
kind: "move";
|
|
81
|
+
location: CompareChangeLocation;
|
|
82
|
+
/** The block's id where it sat in the base document. */
|
|
83
|
+
baseBlockId: string;
|
|
84
|
+
/** The same content's id where it sits in the target document. */
|
|
85
|
+
targetBlockId: string;
|
|
86
|
+
text: string;
|
|
87
|
+
} |
|
|
88
|
+
/**
|
|
89
|
+
* One paragraph became two: a paragraph mark was inserted and no words
|
|
90
|
+
* changed. Reported as its own kind so a reader is not told the tail was
|
|
91
|
+
* newly written.
|
|
92
|
+
*/
|
|
93
|
+
{
|
|
94
|
+
kind: "split";
|
|
95
|
+
location: CompareChangeLocation;
|
|
96
|
+
baseBlockId: string;
|
|
97
|
+
/** The two blocks the base block became, in target order. */
|
|
98
|
+
targetBlockIds: readonly string[];
|
|
99
|
+
text: string;
|
|
100
|
+
} |
|
|
101
|
+
/** Two paragraphs became one: a paragraph mark was deleted. */
|
|
102
|
+
{
|
|
103
|
+
kind: "merge";
|
|
104
|
+
location: CompareChangeLocation;
|
|
105
|
+
/** The two blocks that became one, in base order. */
|
|
106
|
+
baseBlockIds: readonly string[];
|
|
107
|
+
targetBlockId: string;
|
|
108
|
+
text: string;
|
|
109
|
+
} |
|
|
110
|
+
/**
|
|
111
|
+
* A paragraph property moved and no words did: a list item demoted a level,
|
|
112
|
+
* a paragraph restyled. Written as `w:pPrChange`, so rejecting restores the
|
|
113
|
+
* whole previous property set the way Word does.
|
|
114
|
+
*/
|
|
115
|
+
{
|
|
116
|
+
kind: "paragraph-format";
|
|
117
|
+
location: CompareChangeLocation;
|
|
118
|
+
baseBlockId: string;
|
|
119
|
+
targetBlockId: string;
|
|
120
|
+
/** Only the properties that differ, set to the target document's value. */
|
|
121
|
+
properties: FolioAIBlockParagraphProperties;
|
|
122
|
+
} | {
|
|
123
|
+
kind: "format";
|
|
124
|
+
location: CompareChangeLocation;
|
|
125
|
+
baseBlockId: string;
|
|
126
|
+
targetBlockId: string;
|
|
127
|
+
text: string;
|
|
128
|
+
ranges: readonly CompareFormatRange[];
|
|
129
|
+
} | {
|
|
130
|
+
kind: "table-row-insert";
|
|
131
|
+
location: CompareChangeLocation;
|
|
132
|
+
tableIndex: number;
|
|
133
|
+
/** Row index in the target document's table. */
|
|
134
|
+
rowIndex: number;
|
|
135
|
+
/** The new row's cell texts, in physical cell order. */
|
|
136
|
+
cells: readonly string[];
|
|
137
|
+
targetBlockIds: readonly string[];
|
|
138
|
+
} |
|
|
139
|
+
/**
|
|
140
|
+
* A numbering definition that differs. It carries no `location`: numbering
|
|
141
|
+
* lives in the package, not in a story, and one definition governs every
|
|
142
|
+
* list that references it.
|
|
143
|
+
*
|
|
144
|
+
* Reported and not represented. A renumbering that FOLLOWS from an edit —
|
|
145
|
+
* an item inserted, so the ones below it count on — is already shown
|
|
146
|
+
* as-if-accepted, because labels are rendered from these definitions rather
|
|
147
|
+
* than stored on the paragraphs. A definition that itself changed is a
|
|
148
|
+
* different thing, and OOXML has no tracked-change grammar for it: Word
|
|
149
|
+
* does not track `numbering.xml` either.
|
|
150
|
+
*/
|
|
151
|
+
{
|
|
152
|
+
kind: "numbering";
|
|
153
|
+
numId: number;
|
|
154
|
+
level: number;
|
|
155
|
+
/** `null` when the target added this level. */
|
|
156
|
+
before: FolioNumberingLevel | null;
|
|
157
|
+
/** `null` when the target dropped it. */
|
|
158
|
+
after: FolioNumberingLevel | null;
|
|
159
|
+
} |
|
|
160
|
+
/** A whole table the target added. */
|
|
161
|
+
{
|
|
162
|
+
kind: "table-insert";
|
|
163
|
+
location: CompareChangeLocation;
|
|
164
|
+
tableIndex: number;
|
|
165
|
+
/** Cell texts row by row, in physical cell order. */
|
|
166
|
+
rows: readonly (readonly string[])[];
|
|
167
|
+
targetBlockIds: readonly string[];
|
|
168
|
+
} |
|
|
169
|
+
/** A whole table the target dropped. */
|
|
170
|
+
{
|
|
171
|
+
kind: "table-delete";
|
|
172
|
+
location: CompareChangeLocation;
|
|
173
|
+
tableIndex: number;
|
|
174
|
+
rows: readonly (readonly string[])[];
|
|
175
|
+
baseBlockIds: readonly string[];
|
|
176
|
+
} | {
|
|
177
|
+
kind: "table-row-delete";
|
|
178
|
+
location: CompareChangeLocation;
|
|
179
|
+
tableIndex: number;
|
|
180
|
+
/** Row index in the base document's table. */
|
|
181
|
+
rowIndex: number;
|
|
182
|
+
cells: readonly string[];
|
|
183
|
+
baseBlockIds: readonly string[];
|
|
184
|
+
} | {
|
|
185
|
+
kind: "table-column-insert";
|
|
186
|
+
location: CompareChangeLocation;
|
|
187
|
+
tableIndex: number;
|
|
188
|
+
/** Grid-column index in the target table. */
|
|
189
|
+
columnIndex: number;
|
|
190
|
+
/** Newly created physical-cell text in row order. */
|
|
191
|
+
cells: readonly string[];
|
|
192
|
+
targetBlockIds: readonly string[];
|
|
193
|
+
} | {
|
|
194
|
+
kind: "table-column-delete";
|
|
195
|
+
location: CompareChangeLocation;
|
|
196
|
+
tableIndex: number;
|
|
197
|
+
/** Grid-column index in the base table. */
|
|
198
|
+
columnIndex: number;
|
|
199
|
+
cells: readonly string[];
|
|
200
|
+
baseBlockIds: readonly string[];
|
|
201
|
+
};
|
|
202
|
+
/** Why a part of the package is absent from `changes`. */
|
|
203
|
+
declare const COMPARE_UNSUPPORTED_REASONS: readonly ["story-missing-in-base", "story-missing-in-target", "story-not-editable"];
|
|
204
|
+
type CompareUnsupportedReason = (typeof COMPARE_UNSUPPORTED_REASONS)[number];
|
|
205
|
+
/**
|
|
206
|
+
* A package part the comparison did not cover. Reported rather than dropped so
|
|
207
|
+
* a caller can tell "no differences" from "not looked at".
|
|
208
|
+
*/
|
|
209
|
+
type CompareUnsupportedPart = {
|
|
210
|
+
reason: CompareUnsupportedReason;
|
|
211
|
+
baseStory: FolioDocumentStoryHandle | null;
|
|
212
|
+
targetStory: FolioDocumentStoryHandle | null;
|
|
213
|
+
};
|
|
214
|
+
type CompareResult = {
|
|
215
|
+
/** The base package carrying the generated tracked changes. */
|
|
216
|
+
buffer: ArrayBuffer;
|
|
217
|
+
changes: readonly CompareChange[];
|
|
218
|
+
/**
|
|
219
|
+
* Whether the round trip was proven. Always `verified` unless the call asked
|
|
220
|
+
* for `onUnverified: "emit"`, which is the only way an unproven redline is
|
|
221
|
+
* returned at all.
|
|
222
|
+
*/
|
|
223
|
+
verification: CompareVerification;
|
|
224
|
+
unsupported: readonly CompareUnsupportedPart[];
|
|
225
|
+
};
|
|
226
|
+
declare const InvalidCompareDocxOptionsError_base: import("better-result").TaggedErrorClass<"InvalidCompareDocxOptionsError">;
|
|
227
|
+
declare class InvalidCompareDocxOptionsError extends InvalidCompareDocxOptionsError_base<{
|
|
228
|
+
message: string;
|
|
229
|
+
option: "timestamp";
|
|
230
|
+
receivedValue: unknown;
|
|
231
|
+
}> {}
|
|
232
|
+
declare const CompareDocxParseError_base: import("better-result").TaggedErrorClass<"CompareDocxParseError">;
|
|
233
|
+
declare class CompareDocxParseError extends CompareDocxParseError_base<{
|
|
234
|
+
message: string;
|
|
235
|
+
side: "base" | "target";
|
|
236
|
+
cause: unknown;
|
|
237
|
+
}> {}
|
|
238
|
+
declare const CompareDocxApplyError_base: import("better-result").TaggedErrorClass<"CompareDocxApplyError">;
|
|
239
|
+
/**
|
|
240
|
+
* The applier refused at least one derived operation, so accepting the result
|
|
241
|
+
* would not reproduce the target. Reported instead of returning a package that
|
|
242
|
+
* silently under-represents the difference.
|
|
243
|
+
*/
|
|
244
|
+
declare class CompareDocxApplyError extends CompareDocxApplyError_base<{
|
|
245
|
+
message: string;
|
|
246
|
+
skipped: readonly FolioAIEditSkippedOperation[];
|
|
247
|
+
}> {}
|
|
248
|
+
declare const CompareDocxRoundTripError_base: import("better-result").TaggedErrorClass<"CompareDocxRoundTripError">;
|
|
249
|
+
/**
|
|
250
|
+
* The generated tracked changes do not accept back to the target. Raised by
|
|
251
|
+
* the self-check {@link compareDocx} runs before returning: a redline that
|
|
252
|
+
* quietly loses part of the difference is worse than no redline, so the
|
|
253
|
+
* mismatch is surfaced instead of the document.
|
|
254
|
+
*/
|
|
255
|
+
declare class CompareDocxRoundTripError extends CompareDocxRoundTripError_base<{
|
|
256
|
+
message: string;
|
|
257
|
+
story: FolioDocumentStoryHandle;
|
|
258
|
+
/** The invariant that did not hold, and what diverged under it. */
|
|
259
|
+
invariant: CompareVerificationInvariant;
|
|
260
|
+
cause: CompareVerificationCause;
|
|
261
|
+
/**
|
|
262
|
+
* Every invariant that failed, not only the one named above: a redline that
|
|
263
|
+
* loses a difference usually loses it in both directions, and a caller
|
|
264
|
+
* deciding what to do next wants the whole list. Each detail is structural,
|
|
265
|
+
* so it is safe to log or quote.
|
|
266
|
+
*/
|
|
267
|
+
failures: readonly CompareVerificationFailure[];
|
|
268
|
+
}> {}
|
|
269
|
+
declare const CompareDocxOperationLimitError_base: import("better-result").TaggedErrorClass<"CompareDocxOperationLimitError">;
|
|
270
|
+
/** The difference needs more operations than the engine will generate. */
|
|
271
|
+
declare class CompareDocxOperationLimitError extends CompareDocxOperationLimitError_base<{
|
|
272
|
+
message: string;
|
|
273
|
+
limit: number;
|
|
274
|
+
}> {}
|
|
275
|
+
declare const CompareDocxSerializeError_base: import("better-result").TaggedErrorClass<"CompareDocxSerializeError">;
|
|
276
|
+
declare class CompareDocxSerializeError extends CompareDocxSerializeError_base<{
|
|
277
|
+
message: string;
|
|
278
|
+
cause: unknown;
|
|
279
|
+
}> {}
|
|
280
|
+
type CompareDocxError = CompareDocxApplyError | CompareDocxOperationLimitError | CompareDocxParseError | CompareDocxRoundTripError | CompareDocxSerializeError | InvalidCompareDocxOptionsError;
|
|
281
|
+
//#endregion
|
|
282
|
+
export { COMPARE_UNSUPPORTED_REASONS, CompareChange, CompareChangeLocation, CompareDocxApplyError, CompareDocxError, CompareDocxOperationLimitError, CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, CompareFormatRange, CompareResult, CompareUnsupportedPart, CompareUnsupportedReason, InvalidCompareDocxOptionsError };
|