@stll/folio-core 0.33.0 → 0.33.1
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/apply.js +4 -2
- package/dist/compare/__fixtures__/body-sequence.d.ts +26 -3
- package/dist/compare/__fixtures__/body-sequence.js +81 -12
- package/dist/compare/compare.d.ts +2 -2
- package/dist/compare/compare.js +8 -2
- package/dist/compare/plan.js +82 -0
- package/dist/compare/reproducible-package.d.ts +7 -3
- package/dist/compare/reproducible-package.js +20 -3
- package/dist/compare/types.d.ts +18 -3
- package/dist/compare/types.js +11 -1
- package/dist/compare/verification.d.ts +29 -1
- package/dist/compare/verification.js +44 -1
- package/dist/compat/eigenpal.d.ts +3 -3
- package/dist/compat/eigenpal.js +2 -2
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/docx/hyperlinkParser.d.ts +9 -1
- package/dist/docx/hyperlinkParser.js +19 -13
- package/dist/docx/paraIdRangeNormalization.d.ts +40 -0
- package/dist/docx/paraIdRangeNormalization.js +64 -0
- package/dist/docx/paragraphParser.js +79 -4
- package/dist/docx/revisionIdNormalization.d.ts +15 -1
- package/dist/docx/revisionIdNormalization.js +22 -4
- package/dist/docx/rezip.d.ts +6 -0
- package/dist/docx/rezip.js +31 -8
- package/dist/docx/serializer/paragraphSerializer.js +42 -18
- package/dist/docx/serializer/tableSerializer.js +24 -9
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/prosemirror/commands/comments.js +7 -2
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import { hasComplexScript, isComplexScriptCodePoint } from "../utils/scriptSegme
|
|
|
15
15
|
* advances rightward from its origin whatever the paragraph does.
|
|
16
16
|
*/
|
|
17
17
|
declare const glyphCellOffsetsPx: (run: DisplayGlyphRun) => readonly number[];
|
|
18
|
-
declare const DISPLAY_PRIMITIVE_KINDS: ("
|
|
18
|
+
declare const DISPLAY_PRIMITIVE_KINDS: ("line" | "rect" | "image" | "glyphRun" | "clipGroup" | "rotateGroup" | "opacityGroup")[];
|
|
19
19
|
/**
|
|
20
20
|
* Dash geometry of each stroke pattern, as multiples of the stroke thickness.
|
|
21
21
|
*
|
|
@@ -16,6 +16,14 @@ import { XmlElement } from "./xmlParser.js";
|
|
|
16
16
|
* @returns Parsed Hyperlink object
|
|
17
17
|
*/
|
|
18
18
|
declare function parseHyperlink(node: XmlElement, rels: document_d_exports.RelationshipMap | null, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, media?: Map<string, document_d_exports.MediaFile> | null, rootXmlns?: Record<string, string>): document_d_exports.Hyperlink;
|
|
19
|
+
/**
|
|
20
|
+
* One `w:hyperlink` child, or `null` for markup the model does not carry.
|
|
21
|
+
*
|
|
22
|
+
* Exposed so a caller that has to segment a hyperlink — one holding revision
|
|
23
|
+
* wrappers, which the model nests the other way round — parses its plain
|
|
24
|
+
* children exactly as {@link parseHyperlink} does.
|
|
25
|
+
*/
|
|
26
|
+
declare function parseHyperlinkChild(node: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, inScopeXmlns: Record<string, string>): document_d_exports.Hyperlink["children"][number] | null;
|
|
19
27
|
/**
|
|
20
28
|
* Get the display text of a hyperlink
|
|
21
29
|
*
|
|
@@ -104,4 +112,4 @@ declare function createExternalHyperlink(url: string, children: document_d_expor
|
|
|
104
112
|
target?: string;
|
|
105
113
|
}): document_d_exports.Hyperlink;
|
|
106
114
|
//#endregion
|
|
107
|
-
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, resolveHyperlinkUrl };
|
|
115
|
+
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, parseHyperlinkChild, resolveHyperlinkUrl };
|
|
@@ -71,22 +71,28 @@ function parseHyperlink(node, rels, styles = null, theme = null, media = null, r
|
|
|
71
71
|
const docLocation = getAttribute(node, "w", "docLocation");
|
|
72
72
|
if (docLocation) hyperlink.docLocation = docLocation;
|
|
73
73
|
const inScopeXmlns = mergeXmlnsDeclarations(rootXmlns, node);
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
hyperlink.children.push(parseRun(child, styles, theme, rels, media, inScopeXmlns));
|
|
78
|
-
break;
|
|
79
|
-
case "bookmarkStart":
|
|
80
|
-
hyperlink.children.push(parseBookmarkStart(child));
|
|
81
|
-
break;
|
|
82
|
-
case "bookmarkEnd":
|
|
83
|
-
hyperlink.children.push(parseBookmarkEnd(child));
|
|
84
|
-
break;
|
|
85
|
-
default: break;
|
|
74
|
+
for (const child of getChildElements(node)) {
|
|
75
|
+
const parsed = parseHyperlinkChild(child, styles, theme, rels, media, inScopeXmlns);
|
|
76
|
+
if (parsed) hyperlink.children.push(parsed);
|
|
86
77
|
}
|
|
87
78
|
return hyperlink;
|
|
88
79
|
}
|
|
89
80
|
/**
|
|
81
|
+
* One `w:hyperlink` child, or `null` for markup the model does not carry.
|
|
82
|
+
*
|
|
83
|
+
* Exposed so a caller that has to segment a hyperlink — one holding revision
|
|
84
|
+
* wrappers, which the model nests the other way round — parses its plain
|
|
85
|
+
* children exactly as {@link parseHyperlink} does.
|
|
86
|
+
*/
|
|
87
|
+
function parseHyperlinkChild(node, styles, theme, rels, media, inScopeXmlns) {
|
|
88
|
+
switch (getLocalName(node.name)) {
|
|
89
|
+
case "r": return parseRun(node, styles, theme, rels, media, inScopeXmlns);
|
|
90
|
+
case "bookmarkStart": return parseBookmarkStart(node);
|
|
91
|
+
case "bookmarkEnd": return parseBookmarkEnd(node);
|
|
92
|
+
default: return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
90
96
|
* Get the display text of a hyperlink
|
|
91
97
|
*
|
|
92
98
|
* Concatenates text from all child runs.
|
|
@@ -219,4 +225,4 @@ function createExternalHyperlink(url, children, options) {
|
|
|
219
225
|
};
|
|
220
226
|
}
|
|
221
227
|
//#endregion
|
|
222
|
-
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, resolveHyperlinkUrl };
|
|
228
|
+
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, parseHyperlinkChild, resolveHyperlinkUrl };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/docx/paraIdRangeNormalization.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Keep every paragraph id a package carries inside the range the schema gives
|
|
4
|
+
* it.
|
|
5
|
+
*
|
|
6
|
+
* `w14:paraId`, `w14:textId` and the comment-part ids that reference a
|
|
7
|
+
* paragraph are `ST_LongHexNumber` with a maximum: the value has to be below
|
|
8
|
+
* `0x80000000`, so the ids are 31-bit. Producers exist that write eight hex
|
|
9
|
+
* digits without that bound, and folio preserves the ids a document arrives
|
|
10
|
+
* with — so a package can carry an out-of-range id in, and a save that copies
|
|
11
|
+
* it through hands a consumer a package it will refuse.
|
|
12
|
+
*
|
|
13
|
+
* {@link paraIdInRange} is the one mapping, and it is a pure function of the
|
|
14
|
+
* value alone. That is what lets the parser and the save agree without
|
|
15
|
+
* consulting each other: a paragraph's id in the model is the id the file gets,
|
|
16
|
+
* so bringing an id into range does not make a document's own identity move
|
|
17
|
+
* under it between reading and writing. The package pass below is the same
|
|
18
|
+
* mapping applied to every attribute that carries such an id, so a paragraph
|
|
19
|
+
* and every reference to it move together.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* `value` when it already fits, and a value derived from it when it does not.
|
|
23
|
+
*
|
|
24
|
+
* The replacement is derived from the id being replaced and from nothing else.
|
|
25
|
+
* A package-aware search for a free id would read better here and would be
|
|
26
|
+
* wrong: the parser has no package to search, and an id that means one
|
|
27
|
+
* paragraph while reading and another while writing is worse than the
|
|
28
|
+
* vanishing chance of two rewritten ids landing on one value, which is a
|
|
29
|
+
* duplicate rather than a package a consumer refuses.
|
|
30
|
+
*/
|
|
31
|
+
declare const paraIdInRange: (value: string) => string;
|
|
32
|
+
/**
|
|
33
|
+
* Rewrite out-of-range paragraph ids across a whole package.
|
|
34
|
+
*
|
|
35
|
+
* Returns the parts unchanged when every id already fits, so a save of a
|
|
36
|
+
* document that never carried one is byte-identical.
|
|
37
|
+
*/
|
|
38
|
+
declare const normalizeParaIdRangeInXmlParts: (parts: ReadonlyMap<string, string>) => Map<string, string>;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { normalizeParaIdRangeInXmlParts, paraIdInRange };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { deterministicHexId } from "../utils/hexId.js";
|
|
2
|
+
//#region src/docx/paraIdRangeNormalization.ts
|
|
3
|
+
/**
|
|
4
|
+
* Keep every paragraph id a package carries inside the range the schema gives
|
|
5
|
+
* it.
|
|
6
|
+
*
|
|
7
|
+
* `w14:paraId`, `w14:textId` and the comment-part ids that reference a
|
|
8
|
+
* paragraph are `ST_LongHexNumber` with a maximum: the value has to be below
|
|
9
|
+
* `0x80000000`, so the ids are 31-bit. Producers exist that write eight hex
|
|
10
|
+
* digits without that bound, and folio preserves the ids a document arrives
|
|
11
|
+
* with — so a package can carry an out-of-range id in, and a save that copies
|
|
12
|
+
* it through hands a consumer a package it will refuse.
|
|
13
|
+
*
|
|
14
|
+
* {@link paraIdInRange} is the one mapping, and it is a pure function of the
|
|
15
|
+
* value alone. That is what lets the parser and the save agree without
|
|
16
|
+
* consulting each other: a paragraph's id in the model is the id the file gets,
|
|
17
|
+
* so bringing an id into range does not make a document's own identity move
|
|
18
|
+
* under it between reading and writing. The package pass below is the same
|
|
19
|
+
* mapping applied to every attribute that carries such an id, so a paragraph
|
|
20
|
+
* and every reference to it move together.
|
|
21
|
+
*/
|
|
22
|
+
/** Exclusive upper bound on a paragraph id: the values are 31-bit. */
|
|
23
|
+
const MAX_PARA_ID_EXCLUSIVE = 2147483648;
|
|
24
|
+
/**
|
|
25
|
+
* Every attribute that carries a paragraph id or the text-revision marker
|
|
26
|
+
* written beside one: the paragraph's own `w14:paraId` / `w14:textId` (the
|
|
27
|
+
* parser accepts a `w:` prefix too), the comment part's `w15:paraId` and the
|
|
28
|
+
* `w15:paraIdParent` that links a reply to its thread, and the durable-comment
|
|
29
|
+
* part's `w16cid:paraId`.
|
|
30
|
+
*/
|
|
31
|
+
const PARA_ID_ATTRIBUTE = /\b(w|w14|w15|w16cid):(paraId|paraIdParent|textId)=(?<quote>["'])([0-9A-Fa-f]{8})\k<quote>/gu;
|
|
32
|
+
/** A candidate part is one that mentions any of those attributes at all. */
|
|
33
|
+
const PARA_ID_CANDIDATE = /\b(?:w|w14|w15|w16cid):(?:paraId|paraIdParent|textId)=/u;
|
|
34
|
+
/**
|
|
35
|
+
* `value` when it already fits, and a value derived from it when it does not.
|
|
36
|
+
*
|
|
37
|
+
* The replacement is derived from the id being replaced and from nothing else.
|
|
38
|
+
* A package-aware search for a free id would read better here and would be
|
|
39
|
+
* wrong: the parser has no package to search, and an id that means one
|
|
40
|
+
* paragraph while reading and another while writing is worse than the
|
|
41
|
+
* vanishing chance of two rewritten ids landing on one value, which is a
|
|
42
|
+
* duplicate rather than a package a consumer refuses.
|
|
43
|
+
*/
|
|
44
|
+
const paraIdInRange = (value) => Number.parseInt(value, 16) < MAX_PARA_ID_EXCLUSIVE ? value : deterministicHexId(value);
|
|
45
|
+
/**
|
|
46
|
+
* Rewrite out-of-range paragraph ids across a whole package.
|
|
47
|
+
*
|
|
48
|
+
* Returns the parts unchanged when every id already fits, so a save of a
|
|
49
|
+
* document that never carried one is byte-identical.
|
|
50
|
+
*/
|
|
51
|
+
const normalizeParaIdRangeInXmlParts = (parts) => {
|
|
52
|
+
const normalized = new Map(parts);
|
|
53
|
+
for (const [path, xml] of parts) {
|
|
54
|
+
if (!PARA_ID_CANDIDATE.test(xml)) continue;
|
|
55
|
+
const rewritten = xml.replaceAll(PARA_ID_ATTRIBUTE, (whole, prefix, name, quote, value) => {
|
|
56
|
+
const replacement = paraIdInRange(value);
|
|
57
|
+
return replacement === value ? whole : `${prefix}:${name}=${quote}${replacement}${quote}`;
|
|
58
|
+
});
|
|
59
|
+
if (rewritten !== xml) normalized.set(path, rewritten);
|
|
60
|
+
}
|
|
61
|
+
return normalized;
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { normalizeParaIdRangeInXmlParts, paraIdInRange };
|
|
@@ -2,8 +2,9 @@ import { isValidHexColor } from "../utils/colorResolver.js";
|
|
|
2
2
|
import { isValidHexId } from "../utils/hexId.js";
|
|
3
3
|
import { parseBookmarkEnd as parseBookmarkEnd$1, parseBookmarkStart as parseBookmarkStart$1 } from "./bookmarkParser.js";
|
|
4
4
|
import { parseFieldType } from "./fieldParser.js";
|
|
5
|
-
import { parseHyperlink as parseHyperlink$1 } from "./hyperlinkParser.js";
|
|
5
|
+
import { parseHyperlink as parseHyperlink$1, parseHyperlinkChild } from "./hyperlinkParser.js";
|
|
6
6
|
import { markerFormattingFromLevel } from "./numberingParser.js";
|
|
7
|
+
import { paraIdInRange } from "./paraIdRangeNormalization.js";
|
|
7
8
|
import { BorderStyleSchema, FrameWrapSchema, FrameXAlignSchema, FrameYAlignSchema, LineSpacingRuleSchema, ParagraphAlignmentSchema, ShadingPatternSchema, TabLeaderSchema, TabStopAlignmentSchema, ThemeColorSlotSchema, narrowEnum } from "./parserEnums.js";
|
|
8
9
|
import { consolidateParagraphContent } from "./runConsolidator.js";
|
|
9
10
|
import { parseRun, parseRunProperties } from "./runParser.js";
|
|
@@ -646,6 +647,80 @@ function pushInlineSdtSegments({ contents, properties, parsedContent }) {
|
|
|
646
647
|
function parseHyperlink(node, rels, styles, theme, media, rootXmlns = {}) {
|
|
647
648
|
return parseHyperlink$1(node, rels, styles, theme, media, rootXmlns);
|
|
648
649
|
}
|
|
650
|
+
/** The revision wrapper a `w:hyperlink` child is, when it is one. */
|
|
651
|
+
const hyperlinkRevisionWrapperType = (node) => {
|
|
652
|
+
switch (getLocalName(node.name)) {
|
|
653
|
+
case "ins": return "insertion";
|
|
654
|
+
case "del": return "deletion";
|
|
655
|
+
case "moveFrom": return "moveFrom";
|
|
656
|
+
case "moveTo": return "moveTo";
|
|
657
|
+
default: return;
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
const isHyperlinkChildContent = (content) => content.type === "run" || content.type === "bookmarkStart" || content.type === "bookmarkEnd";
|
|
661
|
+
/**
|
|
662
|
+
* A `w:hyperlink` as paragraph content, with any revision wrapper it holds
|
|
663
|
+
* hoisted around it.
|
|
664
|
+
*
|
|
665
|
+
* OOXML nests `w:ins`/`w:del` INSIDE `w:hyperlink`; the model nests the
|
|
666
|
+
* hyperlink inside the revision, because a revision is the unit a redline
|
|
667
|
+
* reads and a link that is half deleted is two links to it. This is the exact
|
|
668
|
+
* inverse of what the serializer writes, so a package survives the round trip.
|
|
669
|
+
*/
|
|
670
|
+
function parseHyperlinkParagraphContents(node, rels, styles, theme, media, rootXmlns) {
|
|
671
|
+
const children = getChildElements(node);
|
|
672
|
+
if (!children.some((child) => hyperlinkRevisionWrapperType(child) !== void 0)) return [parseHyperlink(node, rels, styles, theme, media, rootXmlns)];
|
|
673
|
+
const inScopeXmlns = mergeXmlnsDeclarations(rootXmlns, node);
|
|
674
|
+
const shell = parseHyperlink(node, rels, styles, theme, media, rootXmlns);
|
|
675
|
+
const linkOver = (linkChildren) => ({
|
|
676
|
+
...shell,
|
|
677
|
+
children: [...linkChildren]
|
|
678
|
+
});
|
|
679
|
+
const contents = [];
|
|
680
|
+
let plain = [];
|
|
681
|
+
const flushPlain = () => {
|
|
682
|
+
if (plain.length > 0) {
|
|
683
|
+
contents.push(linkOver(plain));
|
|
684
|
+
plain = [];
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
for (const child of children) {
|
|
688
|
+
const wrapperType = hyperlinkRevisionWrapperType(child);
|
|
689
|
+
if (wrapperType === void 0) {
|
|
690
|
+
const parsed = parseHyperlinkChild(child, styles, theme, rels, media, inScopeXmlns);
|
|
691
|
+
if (parsed) plain.push(parsed);
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
flushPlain();
|
|
695
|
+
const wrapped = parseParagraphContents(child, styles, theme, null, rels, media, wrapperType === "deletion" || wrapperType === "moveFrom" ? "deletion" : "default", inScopeXmlns);
|
|
696
|
+
const content = [];
|
|
697
|
+
let linked = [];
|
|
698
|
+
const flushLinked = () => {
|
|
699
|
+
if (linked.length > 0) {
|
|
700
|
+
content.push(linkOver(linked));
|
|
701
|
+
linked = [];
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
for (const item of wrapped) {
|
|
705
|
+
if (isHyperlinkChildContent(item)) {
|
|
706
|
+
linked.push(item);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
flushLinked();
|
|
710
|
+
if (isTrackedChangeWrapperChild(item)) content.push(item);
|
|
711
|
+
}
|
|
712
|
+
flushLinked();
|
|
713
|
+
pushTrackedChangeWrapper({
|
|
714
|
+
contents,
|
|
715
|
+
type: wrapperType,
|
|
716
|
+
info: parseTrackedChangeInfo(child),
|
|
717
|
+
content,
|
|
718
|
+
preserveEmpty: true
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
flushPlain();
|
|
722
|
+
return contents;
|
|
723
|
+
}
|
|
649
724
|
/**
|
|
650
725
|
* Parse bookmark start (w:bookmarkStart)
|
|
651
726
|
* Delegates to bookmarkParser module.
|
|
@@ -798,7 +873,7 @@ function parseParagraphContents(paraElement, styles, theme, _numbering, rels, me
|
|
|
798
873
|
break;
|
|
799
874
|
}
|
|
800
875
|
case "hyperlink":
|
|
801
|
-
contents.push(
|
|
876
|
+
contents.push(...parseHyperlinkParagraphContents(child, rels, styles, theme, media, inScopeXmlns));
|
|
802
877
|
break;
|
|
803
878
|
case "bookmarkStart":
|
|
804
879
|
contents.push(parseBookmarkStart(child));
|
|
@@ -961,9 +1036,9 @@ function parseParagraph(node, styles, theme, numbering, rels = null, media = nul
|
|
|
961
1036
|
content: []
|
|
962
1037
|
};
|
|
963
1038
|
const paraId = getAttribute(node, "w14", "paraId") ?? getAttribute(node, "w", "paraId");
|
|
964
|
-
if (paraId && isValidHexId(paraId)) paragraph.paraId = paraId;
|
|
1039
|
+
if (paraId && isValidHexId(paraId)) paragraph.paraId = paraIdInRange(paraId);
|
|
965
1040
|
const textId = getAttribute(node, "w14", "textId") ?? getAttribute(node, "w", "textId");
|
|
966
|
-
if (textId && isValidHexId(textId)) paragraph.textId = textId;
|
|
1041
|
+
if (textId && isValidHexId(textId)) paragraph.textId = paraIdInRange(textId);
|
|
967
1042
|
if (!options?.inHeaderFooter && paragraphStartsWithRenderedPageBreak(node)) paragraph.renderedPageBreakBefore = true;
|
|
968
1043
|
const pPr = findChild(node, "w", "pPr");
|
|
969
1044
|
if (pPr) {
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
//#region src/docx/revisionIdNormalization.d.ts
|
|
2
|
+
declare const RevisionIdCollisionError_base: import("better-result").TaggedErrorClass<"RevisionIdCollisionError">;
|
|
3
|
+
/**
|
|
4
|
+
* Two revision elements in one package claimed the same `w:id`.
|
|
5
|
+
*
|
|
6
|
+
* `w:id` on a revision element is unique across the package, so a collision is
|
|
7
|
+
* a package a consumer may reject rather than a cosmetic detail. The
|
|
8
|
+
* normalization below hands every id it emits to one choke point, which throws
|
|
9
|
+
* this rather than letting the duplicate reach the ZIP.
|
|
10
|
+
*/
|
|
11
|
+
declare class RevisionIdCollisionError extends RevisionIdCollisionError_base<{
|
|
12
|
+
message: string;
|
|
13
|
+
revisionId: number;
|
|
14
|
+
part: string;
|
|
15
|
+
}> {}
|
|
2
16
|
declare const REVISION_ELEMENT_NAMES: Set<string>;
|
|
3
17
|
/**
|
|
4
18
|
* Keep physical tracked-change element ids unique across a package.
|
|
@@ -10,4 +24,4 @@ declare const REVISION_ELEMENT_NAMES: Set<string>;
|
|
|
10
24
|
*/
|
|
11
25
|
declare const normalizeRevisionIdsInXmlParts: (parts: ReadonlyMap<string, string>) => Map<string, string>;
|
|
12
26
|
//#endregion
|
|
13
|
-
export { REVISION_ELEMENT_NAMES, normalizeRevisionIdsInXmlParts };
|
|
27
|
+
export { REVISION_ELEMENT_NAMES, RevisionIdCollisionError, normalizeRevisionIdsInXmlParts };
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { rewriteStreamingXmlDecimalAttributes } from "./streamingXmlParser.js";
|
|
2
2
|
import { WORDPROCESSINGML_NAMESPACE_URIS, findAttributeByNamespaceUri, getLocalName, getNamespaceUri } from "./xmlParser.js";
|
|
3
3
|
import { XmlResourceLimitError, assertXmlResourceLimits } from "./xmlResourceLimits.js";
|
|
4
|
+
import { TaggedError } from "better-result";
|
|
4
5
|
//#region src/docx/revisionIdNormalization.ts
|
|
6
|
+
/**
|
|
7
|
+
* Two revision elements in one package claimed the same `w:id`.
|
|
8
|
+
*
|
|
9
|
+
* `w:id` on a revision element is unique across the package, so a collision is
|
|
10
|
+
* a package a consumer may reject rather than a cosmetic detail. The
|
|
11
|
+
* normalization below hands every id it emits to one choke point, which throws
|
|
12
|
+
* this rather than letting the duplicate reach the ZIP.
|
|
13
|
+
*/
|
|
14
|
+
var RevisionIdCollisionError = class extends TaggedError("RevisionIdCollisionError") {};
|
|
5
15
|
const REVISION_ELEMENT_NAMES = /* @__PURE__ */ new Set([
|
|
6
16
|
"cellDel",
|
|
7
17
|
"cellIns",
|
|
@@ -76,19 +86,27 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
|
|
|
76
86
|
for (const [path, xml] of candidates) {
|
|
77
87
|
const ids = occurrencesByPath.get(path);
|
|
78
88
|
if (!ids) continue;
|
|
89
|
+
const claim = (id) => {
|
|
90
|
+
if (seen.has(id)) throw new RevisionIdCollisionError({
|
|
91
|
+
message: `Revision id ${String(id)} is claimed twice in ${path}`,
|
|
92
|
+
revisionId: id,
|
|
93
|
+
part: path
|
|
94
|
+
});
|
|
95
|
+
seen.add(id);
|
|
96
|
+
};
|
|
79
97
|
if (!repeatedPaths.has(path) && ids.every((id) => !seen.has(id))) {
|
|
80
|
-
for (const id of ids)
|
|
98
|
+
for (const id of ids) claim(id);
|
|
81
99
|
continue;
|
|
82
100
|
}
|
|
83
101
|
const rewritten = rewriteStreamingXmlDecimalAttributes(xml, (element) => {
|
|
84
102
|
const attribute = revisionAttribute(element);
|
|
85
103
|
if (!attribute) return null;
|
|
86
104
|
if (!seen.has(attribute.id)) {
|
|
87
|
-
|
|
105
|
+
claim(attribute.id);
|
|
88
106
|
return null;
|
|
89
107
|
}
|
|
90
108
|
const replacement = allocate();
|
|
91
|
-
|
|
109
|
+
claim(replacement);
|
|
92
110
|
return /* @__PURE__ */ new Map([[attribute.name, String(replacement)]]);
|
|
93
111
|
});
|
|
94
112
|
if (rewritten.status === "unsupported") throw new XmlResourceLimitError({
|
|
@@ -100,4 +118,4 @@ const normalizeRevisionIdsInXmlParts = (parts) => {
|
|
|
100
118
|
return normalized;
|
|
101
119
|
};
|
|
102
120
|
//#endregion
|
|
103
|
-
export { REVISION_ELEMENT_NAMES, normalizeRevisionIdsInXmlParts };
|
|
121
|
+
export { REVISION_ELEMENT_NAMES, RevisionIdCollisionError, normalizeRevisionIdsInXmlParts };
|
package/dist/docx/rezip.d.ts
CHANGED
|
@@ -105,6 +105,12 @@ declare function updateMultipleFiles(originalBuffer: ArrayBuffer, updates: Map<s
|
|
|
105
105
|
/**
|
|
106
106
|
* Apply file updates to an already-loaded JSZip instance and generate the output.
|
|
107
107
|
* Use this when the zip is already loaded to avoid a redundant decompression pass.
|
|
108
|
+
*
|
|
109
|
+
* This is the selective save's exit, so it owes the package the same id passes
|
|
110
|
+
* {@link generateDocxZip} runs: a save that rewrites only the changed
|
|
111
|
+
* paragraphs still has to see the parts it left alone, both to know which
|
|
112
|
+
* revision ids are free and because an out-of-range paragraph id can sit in a
|
|
113
|
+
* part it never touched.
|
|
108
114
|
*/
|
|
109
115
|
declare function applyUpdatesToZip(zip: JSZip, updates: Map<string, string | ArrayBuffer>, options?: RepackOptions): Promise<ArrayBuffer>;
|
|
110
116
|
/**
|
package/dist/docx/rezip.js
CHANGED
|
@@ -6,6 +6,7 @@ import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
|
6
6
|
import { isNewDataUrlDrawing } from "./newImage.js";
|
|
7
7
|
import { parseNumbering } from "./numberingParser.js";
|
|
8
8
|
import { isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries } from "./packageParts.js";
|
|
9
|
+
import { normalizeParaIdRangeInXmlParts } from "./paraIdRangeNormalization.js";
|
|
9
10
|
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
10
11
|
import { normalizeRevisionIdsInXmlParts } from "./revisionIdNormalization.js";
|
|
11
12
|
import { appendNumberingDefs, buildPatchedNotePartXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds } from "./selectiveXmlPatch.js";
|
|
@@ -407,19 +408,34 @@ async function processNewHyperlinks(parts, zip, compressionLevel) {
|
|
|
407
408
|
}
|
|
408
409
|
}
|
|
409
410
|
/**
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
411
|
+
* Bring the ids a package addresses itself by inside the bounds the format
|
|
412
|
+
* gives them.
|
|
413
|
+
*
|
|
414
|
+
* Both bounds belong to the package rather than to a part, and neither is
|
|
415
|
+
* something one serializer can see on its own. A revision `w:id` is unique
|
|
416
|
+
* across the package, and one logical revision serializes as several physical
|
|
417
|
+
* wrappers — a word diff cut around unchanged words, a revision split around a
|
|
418
|
+
* hyperlink. A paragraph id is 31-bit, and a paragraph is referenced by id
|
|
419
|
+
* from parts other than the one it lives in. So the passes run at the exits,
|
|
420
|
+
* over every `word/*.xml` part including the ones a save left untouched.
|
|
413
421
|
*/
|
|
414
|
-
const
|
|
415
|
-
await reconcilePackageReferences(zip, compressionLevel);
|
|
422
|
+
const normalizePackageIdsInZip = async (zip, compressionLevel) => {
|
|
416
423
|
const xmlParts = /* @__PURE__ */ new Map();
|
|
417
424
|
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.startsWith("word/") && path.endsWith(".xml")) xmlParts.set(path, await file.async("text"));
|
|
418
|
-
const normalizedParts = normalizeRevisionIdsInXmlParts(xmlParts);
|
|
425
|
+
const normalizedParts = normalizeParaIdRangeInXmlParts(normalizeRevisionIdsInXmlParts(xmlParts));
|
|
419
426
|
for (const [path, xml] of normalizedParts) if (xml !== xmlParts.get(path)) zip.file(path, xml, {
|
|
420
427
|
compression: "DEFLATE",
|
|
421
428
|
compressionOptions: { level: compressionLevel }
|
|
422
429
|
});
|
|
430
|
+
};
|
|
431
|
+
/**
|
|
432
|
+
* The single exit for a repacked package. Reconciliation runs here rather than
|
|
433
|
+
* at each caller so no save path can emit a package whose relationships or
|
|
434
|
+
* content types name a part it does not hold.
|
|
435
|
+
*/
|
|
436
|
+
const generateDocxZip = async (zip, compressionLevel) => {
|
|
437
|
+
await reconcilePackageReferences(zip, compressionLevel);
|
|
438
|
+
await normalizePackageIdsInZip(zip, compressionLevel);
|
|
423
439
|
return zip.generateAsync({
|
|
424
440
|
type: "arraybuffer",
|
|
425
441
|
compression: "DEFLATE",
|
|
@@ -758,14 +774,21 @@ async function updateMultipleFiles(originalBuffer, updates, options = {}) {
|
|
|
758
774
|
/**
|
|
759
775
|
* Apply file updates to an already-loaded JSZip instance and generate the output.
|
|
760
776
|
* Use this when the zip is already loaded to avoid a redundant decompression pass.
|
|
777
|
+
*
|
|
778
|
+
* This is the selective save's exit, so it owes the package the same id passes
|
|
779
|
+
* {@link generateDocxZip} runs: a save that rewrites only the changed
|
|
780
|
+
* paragraphs still has to see the parts it left alone, both to know which
|
|
781
|
+
* revision ids are free and because an out-of-range paragraph id can sit in a
|
|
782
|
+
* part it never touched.
|
|
761
783
|
*/
|
|
762
|
-
function applyUpdatesToZip(zip, updates, options = {}) {
|
|
784
|
+
async function applyUpdatesToZip(zip, updates, options = {}) {
|
|
763
785
|
const { compressionLevel = 6 } = options;
|
|
764
786
|
for (const [path, content] of updates) zip.file(path, content, {
|
|
765
787
|
compression: "DEFLATE",
|
|
766
788
|
compressionOptions: { level: compressionLevel }
|
|
767
789
|
});
|
|
768
|
-
|
|
790
|
+
await normalizePackageIdsInZip(zip, compressionLevel);
|
|
791
|
+
return await zip.generateAsync({
|
|
769
792
|
type: "arraybuffer",
|
|
770
793
|
compression: "DEFLATE",
|
|
771
794
|
compressionOptions: { level: compressionLevel }
|
|
@@ -210,10 +210,8 @@ function serializeParagraphPropertyChange(change) {
|
|
|
210
210
|
const normalizedPreviousPPr = previousPPrInner.length > 0 ? `<w:pPr>${previousPPrInner}</w:pPr>` : "<w:pPr/>";
|
|
211
211
|
return `<w:pPrChange ${attrs.join(" ")}>${normalizedPreviousPPr}</w:pPrChange>`;
|
|
212
212
|
}
|
|
213
|
-
/**
|
|
214
|
-
|
|
215
|
-
*/
|
|
216
|
-
function serializeHyperlink(hyperlink) {
|
|
213
|
+
/** The attribute list of a `w:hyperlink`, without its children. */
|
|
214
|
+
function hyperlinkAttributes(hyperlink) {
|
|
217
215
|
const attrs = [];
|
|
218
216
|
if (hyperlink.rId) attrs.push(`r:id="${escapeXml(hyperlink.rId)}"`);
|
|
219
217
|
if (hyperlink.anchor) attrs.push(`w:anchor="${escapeXml(hyperlink.anchor)}"`);
|
|
@@ -222,12 +220,19 @@ function serializeHyperlink(hyperlink) {
|
|
|
222
220
|
if (hyperlink.history === true) attrs.push("w:history=\"1\"");
|
|
223
221
|
else if (hyperlink.history === false) attrs.push("w:history=\"0\"");
|
|
224
222
|
if (hyperlink.docLocation) attrs.push(`w:docLocation="${escapeXml(hyperlink.docLocation)}"`);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return
|
|
223
|
+
return attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
224
|
+
}
|
|
225
|
+
/** One `w:hyperlink` child, with the caller deciding how a run is written. */
|
|
226
|
+
function serializeHyperlinkChild(child, serializeChildRun) {
|
|
227
|
+
if (child.type === "run") return serializeChildRun(child);
|
|
228
|
+
return child.type === "bookmarkStart" ? serializeBookmarkStart(child) : serializeBookmarkEnd(child);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Serialize a hyperlink (w:hyperlink)
|
|
232
|
+
*/
|
|
233
|
+
function serializeHyperlink(hyperlink) {
|
|
234
|
+
const childrenXml = hyperlink.children.map((child) => serializeHyperlinkChild(child, serializeRun)).join("");
|
|
235
|
+
return `<w:hyperlink${hyperlinkAttributes(hyperlink)}>${childrenXml}</w:hyperlink>`;
|
|
231
236
|
}
|
|
232
237
|
/**
|
|
233
238
|
* Serialize bookmark start (w:bookmarkStart)
|
|
@@ -397,20 +402,39 @@ function serializeTrackedChange(tag, change) {
|
|
|
397
402
|
return rewriteRunTextAsDeleted(contentXml);
|
|
398
403
|
}).join("");
|
|
399
404
|
};
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return serializeRun(item);
|
|
404
|
-
}
|
|
405
|
-
if (item.type === "hyperlink") return serializeHyperlink(item);
|
|
405
|
+
const serializeContentRun = (run) => tag === "del" || tag === "moveFrom" ? serializeDeletedRun(run) : serializeRun(run);
|
|
406
|
+
const serializeWrappedItem = (item) => {
|
|
407
|
+
if (item.type === "run") return serializeContentRun(item);
|
|
406
408
|
if (item.type === "simpleField" || item.type === "complexField") {
|
|
407
409
|
const xml = item.type === "simpleField" ? serializeSimpleField(item) : serializeComplexField(item);
|
|
408
410
|
return tag === "del" || tag === "moveFrom" ? rewriteRunTextAsDeleted(xml) : xml;
|
|
409
411
|
}
|
|
410
412
|
if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return serializeTrackedChange(trackedChangeTag(item), item);
|
|
411
413
|
return item.type === "bookmarkStart" ? serializeBookmarkStart(item) : serializeBookmarkEnd(item);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
+
};
|
|
415
|
+
const open = `<w:${tag} ${attrs.join(" ")}>`;
|
|
416
|
+
const close = `</w:${tag}>`;
|
|
417
|
+
const wrap = (inner) => inner.length === 0 ? "" : `${open}${inner}${close}`;
|
|
418
|
+
if (change.content.length === 0) return `${open}${close}`;
|
|
419
|
+
const segments = [];
|
|
420
|
+
const pending = [];
|
|
421
|
+
const flushPending = () => {
|
|
422
|
+
if (pending.length > 0) {
|
|
423
|
+
segments.push(wrap(pending.join("")));
|
|
424
|
+
pending.length = 0;
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
for (const item of change.content) {
|
|
428
|
+
if (item.type === "hyperlink") {
|
|
429
|
+
flushPending();
|
|
430
|
+
const childrenXml = item.children.map((child) => serializeHyperlinkChild(child, serializeContentRun)).join("");
|
|
431
|
+
segments.push(`<w:hyperlink${hyperlinkAttributes(item)}>${open}${childrenXml}${close}</w:hyperlink>`);
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
pending.push(serializeWrappedItem(item));
|
|
435
|
+
}
|
|
436
|
+
flushPending();
|
|
437
|
+
return segments.join("");
|
|
414
438
|
}
|
|
415
439
|
/** Emit the `<w:commentReference>` run Word places after a comment range end. */
|
|
416
440
|
function serializeCommentReferenceRun(id) {
|
|
@@ -277,11 +277,30 @@ function serializeTableCellPropertyChange(change) {
|
|
|
277
277
|
return `<w:tcPrChange ${attrs}>${previousTcPrInner.length > 0 ? `<w:tcPr>${previousTcPrInner}</w:tcPr>` : "<w:tcPr/>"}</w:tcPrChange>`;
|
|
278
278
|
}
|
|
279
279
|
/**
|
|
280
|
-
*
|
|
280
|
+
* Columns the grid has to declare: the widest row's span total, because a grid
|
|
281
|
+
* narrower than a row leaves cells with no column to sit in.
|
|
281
282
|
*/
|
|
282
|
-
function
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
function gridColumnCount(table) {
|
|
284
|
+
let widest = 0;
|
|
285
|
+
for (const row of table.rows) {
|
|
286
|
+
let columns = 0;
|
|
287
|
+
for (const cell of row.cells) columns += cell.formatting?.gridSpan ?? 1;
|
|
288
|
+
widest = Math.max(widest, columns);
|
|
289
|
+
}
|
|
290
|
+
return widest;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Serialize table grid (w:tblGrid).
|
|
294
|
+
*
|
|
295
|
+
* `w:tblGrid` is required on every `w:tbl` and `w:w` is optional on a
|
|
296
|
+
* `w:gridCol`, so a table whose column widths were never measured — one the
|
|
297
|
+
* comparison creates, say — still declares a grid, just without widths.
|
|
298
|
+
*/
|
|
299
|
+
function serializeTableGrid(table) {
|
|
300
|
+
const columnWidths = table.columnWidths;
|
|
301
|
+
if (columnWidths && columnWidths.length > 0) return `<w:tblGrid>${columnWidths.map((w) => `<w:gridCol w:w="${intAttr(w)}"/>`).join("")}</w:tblGrid>`;
|
|
302
|
+
const columns = gridColumnCount(table);
|
|
303
|
+
return columns === 0 ? "<w:tblGrid/>" : `<w:tblGrid>${"<w:gridCol/>".repeat(columns)}</w:tblGrid>`;
|
|
285
304
|
}
|
|
286
305
|
/**
|
|
287
306
|
* Serialize cell content (paragraphs, nested tables)
|
|
@@ -320,11 +339,7 @@ function serializeTableRow(row, serializeParagraph) {
|
|
|
320
339
|
* @returns XML string for the table
|
|
321
340
|
*/
|
|
322
341
|
function serializeTable(table, serializeParagraph) {
|
|
323
|
-
const parts = [];
|
|
324
|
-
const tblPrXml = serializeTableFormatting(table.formatting, table.propertyChanges);
|
|
325
|
-
if (tblPrXml) parts.push(tblPrXml);
|
|
326
|
-
const tblGridXml = serializeTableGrid(table.columnWidths);
|
|
327
|
-
if (tblGridXml) parts.push(tblGridXml);
|
|
342
|
+
const parts = [serializeTableFormatting(table.formatting, table.propertyChanges) || "<w:tblPr/>", serializeTableGrid(table)];
|
|
328
343
|
for (const row of table.rows) parts.push(serializeTableRow(row, serializeParagraph));
|
|
329
344
|
return `<w:tbl>${parts.join("")}</w:tbl>`;
|
|
330
345
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ import { AIBarStatus, AIChatMode, AICitation, AICitationSource, AIGenerateInput,
|
|
|
10
10
|
import { ApplyResult, applySuggestions } from "./ai-suggestions/apply.js";
|
|
11
11
|
import { ResolvedAnchor, isSuggestionStale, resolveSuggestionAnchor } from "./ai-suggestions/conflict.js";
|
|
12
12
|
import { PositionalText, buildPositionalText } from "./ai-suggestions/text-positions.js";
|
|
13
|
-
import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant } from "./compare/verification.js";
|
|
14
|
-
import { COMPARE_UNSUPPORTED_REASONS, CompareChange, CompareChangeLocation, CompareDocxApplyError, CompareDocxError, CompareDocxOperationLimitError, CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, CompareFormatRange, CompareResult, CompareUnsupportedPart, CompareUnsupportedReason, InvalidCompareDocxOptionsError } from "./compare/types.js";
|
|
13
|
+
import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant, FinalParagraphMarkDeletion } from "./compare/verification.js";
|
|
14
|
+
import { COMPARE_UNSUPPORTED_REASONS, CompareChange, CompareChangeLocation, CompareDocxApplyError, CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, CompareFormatRange, CompareResult, CompareUnsupportedPart, CompareUnsupportedReason, InvalidCompareDocxOptionsError } from "./compare/types.js";
|
|
15
15
|
import { MAX_COMPARE_OPERATIONS, compareDocx } from "./compare/compare.js";
|
|
16
16
|
import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocumentPreset, DocumentStyleSet } from "./style-sets/types.js";
|
|
17
17
|
import { CreateEmptyDocumentOptions, createEmptyDocument } from "./utils/createDocument.js";
|
|
@@ -38,4 +38,4 @@ import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled
|
|
|
38
38
|
import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
|
|
39
39
|
type Document = document_d_exports.Document;
|
|
40
40
|
type DocxConformanceClass = document_d_exports.DocxConformanceClass;
|
|
41
|
-
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 };
|
|
41
|
+
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, CompareDocxFinalParagraphMarkError, 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 FinalParagraphMarkDeletion, 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 };
|