@stll/folio-core 0.37.5 → 0.38.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/apply.js +275 -88
- package/dist/ai-edits/clean-text.js +12 -1
- package/dist/ai-edits/headless.d.ts +110 -0
- package/dist/ai-edits/headless.js +569 -40
- package/dist/ai-edits/snapshot.d.ts +24 -1
- package/dist/ai-edits/snapshot.js +206 -9
- package/dist/ai-edits/table-geometry.d.ts +7 -7
- package/dist/ai-edits/table-geometry.js +43 -27
- package/dist/ai-edits/table-template.d.ts +2 -1
- package/dist/ai-edits/table-template.js +9 -3
- package/dist/ai-edits/types.d.ts +37 -15
- package/dist/compare/__fixtures__/body-sequence.d.ts +4 -0
- package/dist/compare/__fixtures__/body-sequence.js +5 -3
- package/dist/compare/compare.d.ts +26 -2
- package/dist/compare/compare.js +444 -16
- package/dist/compare/content-alignment.js +3 -2
- package/dist/compare/content-types.d.ts +34 -2
- package/dist/compare/content.d.ts +13 -10
- package/dist/compare/content.js +69 -23
- package/dist/compare/formatting.d.ts +4 -22
- package/dist/compare/formatting.js +8 -112
- package/dist/compare/inline-atom-resources.d.ts +6 -0
- package/dist/compare/inline-atom-resources.js +26 -0
- package/dist/compare/inline-atoms.d.ts +35 -0
- package/dist/compare/inline-atoms.js +383 -0
- package/dist/compare/inline-provenance.d.ts +36 -0
- package/dist/compare/inline-provenance.js +334 -0
- package/dist/compare/plan.d.ts +4 -1
- package/dist/compare/plan.js +32 -4
- package/dist/compare/scenario.d.ts +4 -6
- package/dist/compare/section-boundary-properties.d.ts +63 -0
- package/dist/compare/section-boundary-properties.js +235 -0
- package/dist/compare/style-resources.d.ts +30 -0
- package/dist/compare/style-resources.js +404 -0
- package/dist/compare/types.d.ts +50 -11
- package/dist/compare/types.js +3 -1
- package/dist/compare/verification.d.ts +3 -5
- package/dist/compare/verification.js +8 -39
- package/dist/compat/eigenpal.d.ts +4 -4
- package/dist/compat/eigenpal.js +3 -3
- package/dist/document-operations.d.ts +5 -3
- package/dist/document-operations.js +112 -5
- package/dist/docx/blockContentParser.js +14 -2
- package/dist/docx/drawingIdNormalization.js +43 -2
- package/dist/docx/drawingRelationships.d.ts +10 -0
- package/dist/docx/drawingRelationships.js +28 -0
- package/dist/docx/fieldParser.js +1 -1
- package/dist/docx/hyperlinkParser.js +3 -5
- package/dist/docx/imageRawXml.d.ts +8 -0
- package/dist/docx/imageRawXml.js +13 -0
- package/dist/docx/newImage.d.ts +2 -2
- package/dist/docx/newImage.js +3 -3
- package/dist/docx/numberingParser.js +30 -27
- package/dist/docx/paragraphParser.js +11 -4
- package/dist/docx/removeHeaderFooterParts.d.ts +14 -0
- package/dist/docx/removeHeaderFooterParts.js +87 -0
- package/dist/docx/rezip.d.ts +3 -1
- package/dist/docx/rezip.js +143 -41
- package/dist/docx/runParser.js +16 -5
- package/dist/docx/sectionParser.js +3 -0
- package/dist/docx/sectionReferenceHistory.d.ts +17 -0
- package/dist/docx/sectionReferenceHistory.js +59 -0
- package/dist/docx/selectiveSave.js +11 -31
- package/dist/docx/selectiveXmlPatch.d.ts +8 -1
- package/dist/docx/selectiveXmlPatch.js +62 -2
- package/dist/docx/serializer/paragraphSerializer.js +2 -0
- package/dist/docx/serializer/partNamespaces.d.ts +1 -1
- package/dist/docx/serializer/partNamespaces.js +4 -0
- package/dist/docx/serializer/runSerializer.js +2 -1
- package/dist/docx/serializer/sectionPropertiesSerializer.js +5 -2
- package/dist/docx/serializer/textFormattingSerializer.d.ts +1 -1
- package/dist/docx/serializer/textFormattingSerializer.js +3 -1
- package/dist/docx/tableParser.js +21 -11
- package/dist/docx/xmlParser.d.ts +10 -1
- package/dist/docx/xmlParser.js +23 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/internal/compare/inline-presentation.d.ts +20 -0
- package/dist/internal/compare/inline-presentation.js +222 -0
- package/dist/internal/paragraphFormattingSerialization.d.ts +3 -1
- package/dist/internal/paragraphFormattingSerialization.js +8 -1
- package/dist/internal/sectionReferenceResolution.d.ts +21 -0
- package/dist/internal/sectionReferenceResolution.js +72 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +1 -0
- package/dist/markdown/renderRuns.js +1 -0
- package/dist/markdown/renderTable.js +1 -0
- package/dist/prosemirror/attrs/index.js +20 -1
- package/dist/prosemirror/commands/comments.d.ts +11 -1
- package/dist/prosemirror/commands/comments.js +68 -6
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +9 -3
- package/dist/prosemirror/commands/propertyChangeScope.js +4 -10
- package/dist/prosemirror/conversion/fromProseDoc.js +16 -8
- package/dist/prosemirror/conversion/toProseDoc.js +16 -57
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +3 -0
- package/dist/prosemirror/imageCommit.js +7 -9
- package/dist/prosemirror/paragraphIndentation.d.ts +21 -0
- package/dist/prosemirror/paragraphIndentation.js +72 -0
- package/dist/prosemirror/plugins/documentNumbering.d.ts +3 -1
- package/dist/prosemirror/plugins/documentNumbering.js +7 -1
- package/dist/prosemirror/plugins/documentStyles.d.ts +3 -1
- package/dist/prosemirror/plugins/documentStyles.js +7 -1
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +3 -1
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +2 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +15 -2
- package/dist/prosemirror/runFormattingInlineCarriers.js +33 -3
- package/dist/prosemirror/runStyleFormatting.d.ts +15 -2
- package/dist/prosemirror/runStyleFormatting.js +76 -2
- package/dist/prosemirror/schema/marks.d.ts +3 -1
- package/dist/prosemirror/schema/marks.js +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +3 -0
- package/dist/prosemirror/tableCellRevisionVisibility.d.ts +6 -0
- package/dist/prosemirror/tableCellRevisionVisibility.js +14 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
- package/dist/redline.js +15 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/version-comparison.d.ts +2 -0
- package/dist/version-comparison.js +7 -2
- package/package.json +2 -2
|
@@ -9,6 +9,29 @@ declare const numberingReferenceKeysOf: (snapshot: FolioAIEditSnapshot) => reado
|
|
|
9
9
|
declare const storyTablesOf: (snapshot: FolioAIEditSnapshot) => readonly FolioStoryTable[];
|
|
10
10
|
/** @internal The immutable ProseMirror document that produced this snapshot. */
|
|
11
11
|
declare const sourceDocumentOf: (snapshot: FolioAIEditSnapshot) => Node;
|
|
12
|
+
/** @internal Style context that produced the snapshot's authored run properties. */
|
|
13
|
+
declare const styleResolverOf: (snapshot: FolioAIEditSnapshot) => RunStyleResolver | null;
|
|
14
|
+
/**
|
|
15
|
+
* Derive a comparison-only view with concrete numbering references rebound.
|
|
16
|
+
* Rebuild from the remapped source document so blocks, anchors, table nodes,
|
|
17
|
+
* and operation templates retain one canonical set of numbering references.
|
|
18
|
+
*/
|
|
19
|
+
declare const remapFolioAIEditSnapshotNumberingReferences: (snapshot: FolioAIEditSnapshot, numIdMap: ReadonlyMap<number, number>) => FolioAIEditSnapshot;
|
|
20
|
+
/**
|
|
21
|
+
* Detach external hyperlink relationship ids before copying a story into a
|
|
22
|
+
* different package. The serializer allocates relationship ids for the
|
|
23
|
+
* receiving part; bookmark targets remain package-local and are refused.
|
|
24
|
+
*/
|
|
25
|
+
declare const detachFolioAIEditSnapshotExternalHyperlinks: (snapshot: FolioAIEditSnapshot) => FolioAIEditSnapshot | null;
|
|
26
|
+
type RemapFolioAIEditSnapshotStyleReferencesOptions = {
|
|
27
|
+
snapshot: FolioAIEditSnapshot;
|
|
28
|
+
styleIdMap: ReadonlyMap<string, string>;
|
|
29
|
+
defaultParagraphStyleId: string | undefined;
|
|
30
|
+
importedStyleResolver: RunStyleResolver | null;
|
|
31
|
+
reconcileAuthoredFormatting?: boolean;
|
|
32
|
+
};
|
|
33
|
+
/** Rebind imported style identifiers while retaining the source formatting context. */
|
|
34
|
+
declare const remapFolioAIEditSnapshotStyleReferences: ({ snapshot, styleIdMap, defaultParagraphStyleId, importedStyleResolver, reconcileAuthoredFormatting }: RemapFolioAIEditSnapshotStyleReferencesOptions) => FolioAIEditSnapshot;
|
|
12
35
|
declare const normalizeFolioAIBlockText: (text: string) => string;
|
|
13
36
|
/**
|
|
14
37
|
* Whether a block carries text a reader would see.
|
|
@@ -82,4 +105,4 @@ declare const createFolioAIEditSnapshot: (doc: Node) => FolioAIEditSnapshot;
|
|
|
82
105
|
/** @internal Use for an EditorState that owns the document's style resolver. */
|
|
83
106
|
declare const createFolioAIEditSnapshotWithStyleResolver: (doc: Node, styleResolver: RunStyleResolver | null) => FolioAIEditSnapshot;
|
|
84
107
|
//#endregion
|
|
85
|
-
export { FolioStoryTable, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, folioStoryTables, hashFolioAIBlockStructuralBoundaries, hashFolioAIBlockText, isFolioAIContentBlock, isHiddenTableRow, normalizeFolioAIBlockText, numberingReferenceKeysOf, projectFolioAIBlockStructuralBoundaries, sourceDocumentOf, storyTablesOf, trailingBodyBlockId };
|
|
108
|
+
export { FolioStoryTable, createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, detachFolioAIEditSnapshotExternalHyperlinks, folioStoryTables, hashFolioAIBlockStructuralBoundaries, hashFolioAIBlockText, isFolioAIContentBlock, isHiddenTableRow, normalizeFolioAIBlockText, numberingReferenceKeysOf, projectFolioAIBlockStructuralBoundaries, remapFolioAIEditSnapshotNumberingReferences, remapFolioAIEditSnapshotStyleReferences, sourceDocumentOf, storyTablesOf, styleResolverOf, trailingBodyBlockId };
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { recreateProseNodeWithParagraphPropertySource } from "../docx/paragraphPropertySource.js";
|
|
2
|
+
import { expectCharacterStyleMarkAttrs, expectHyperlinkMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
2
3
|
import { marksToTextFormatting } from "../prosemirror/conversion/fromProseDoc.js";
|
|
3
4
|
import { directParagraphAlignment } from "../prosemirror/paragraphAlignment.js";
|
|
5
|
+
import { directParagraphIndentation } from "../prosemirror/paragraphIndentation.js";
|
|
4
6
|
import { directParagraphSpacing } from "../prosemirror/paragraphSpacing.js";
|
|
7
|
+
import { runFormattingInlineControlCharacter } from "../prosemirror/runFormattingInlineCarriers.js";
|
|
5
8
|
import { authoredRunFormattingFromAttrs } from "../prosemirror/runFormattingProvenance.js";
|
|
9
|
+
import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../prosemirror/runFormattingReconciliation.js";
|
|
6
10
|
import { paragraphRunStyleContext } from "../prosemirror/runStyleFormatting.js";
|
|
7
11
|
import { deriveBlankBlockId, deriveBlockId } from "../types/block-id.js";
|
|
8
12
|
import { buildCleanBlockText } from "./clean-text.js";
|
|
9
13
|
import { panic } from "better-result";
|
|
14
|
+
import { Fragment } from "prosemirror-model";
|
|
10
15
|
import { TableMap } from "prosemirror-tables";
|
|
11
16
|
//#region src/ai-edits/snapshot.ts
|
|
12
17
|
const metadataBySnapshot = /* @__PURE__ */ new WeakMap();
|
|
@@ -17,6 +22,169 @@ const numberingReferenceKeysOf = (snapshot) => metadataOf(snapshot).numberingRef
|
|
|
17
22
|
const storyTablesOf = (snapshot) => metadataOf(snapshot).storyTables;
|
|
18
23
|
/** @internal The immutable ProseMirror document that produced this snapshot. */
|
|
19
24
|
const sourceDocumentOf = (snapshot) => metadataOf(snapshot).sourceDocument;
|
|
25
|
+
/** @internal Style context that produced the snapshot's authored run properties. */
|
|
26
|
+
const styleResolverOf = (snapshot) => metadataOf(snapshot).styleResolver;
|
|
27
|
+
/**
|
|
28
|
+
* Derive a comparison-only view with concrete numbering references rebound.
|
|
29
|
+
* Rebuild from the remapped source document so blocks, anchors, table nodes,
|
|
30
|
+
* and operation templates retain one canonical set of numbering references.
|
|
31
|
+
*/
|
|
32
|
+
const remapFolioAIEditSnapshotNumberingReferences = (snapshot, numIdMap) => {
|
|
33
|
+
if (numIdMap.size === 0) return snapshot;
|
|
34
|
+
const metadata = metadataOf(snapshot);
|
|
35
|
+
const remapNode = (node) => {
|
|
36
|
+
const numPr = node.attrs["numPr"];
|
|
37
|
+
if (typeof numPr !== "object" || numPr === null || !("numId" in numPr)) return node;
|
|
38
|
+
const numId = numPr.numId;
|
|
39
|
+
if (typeof numId !== "number") return node;
|
|
40
|
+
const remappedNumId = numIdMap.get(numId);
|
|
41
|
+
if (remappedNumId === void 0) return node;
|
|
42
|
+
return recreateProseNodeWithParagraphPropertySource(node, { attrs: {
|
|
43
|
+
...node.attrs,
|
|
44
|
+
numPr: {
|
|
45
|
+
...numPr,
|
|
46
|
+
numId: remappedNumId
|
|
47
|
+
}
|
|
48
|
+
} });
|
|
49
|
+
};
|
|
50
|
+
const remapped = remapDocument(metadata.sourceDocument, remapNode);
|
|
51
|
+
if (remapped === metadata.sourceDocument) return snapshot;
|
|
52
|
+
return createFolioAIEditSnapshotInternal(remapped, metadata.styleResolver);
|
|
53
|
+
};
|
|
54
|
+
const remapDocument = (doc, remapNode) => {
|
|
55
|
+
const rewrite = (node) => {
|
|
56
|
+
if (node.isText) return remapNode(node);
|
|
57
|
+
const children = [];
|
|
58
|
+
let changed = false;
|
|
59
|
+
node.forEach((child) => {
|
|
60
|
+
const next = rewrite(child);
|
|
61
|
+
if (next !== child) changed = true;
|
|
62
|
+
children.push(next);
|
|
63
|
+
});
|
|
64
|
+
return remapNode(changed ? recreateProseNodeWithParagraphPropertySource(node, { content: Fragment.fromArray(children) }) : node);
|
|
65
|
+
};
|
|
66
|
+
return rewrite(doc);
|
|
67
|
+
};
|
|
68
|
+
const externalHrefCanCrossPackage = (href) => href.length > 0 && !href.startsWith("#");
|
|
69
|
+
const hyperlinkCanCrossPackage = ({ href, rId }) => externalHrefCanCrossPackage(href) || href.length === 0 && !(typeof rId === "string" && rId.length > 0);
|
|
70
|
+
/**
|
|
71
|
+
* Detach external hyperlink relationship ids before copying a story into a
|
|
72
|
+
* different package. The serializer allocates relationship ids for the
|
|
73
|
+
* receiving part; bookmark targets remain package-local and are refused.
|
|
74
|
+
*/
|
|
75
|
+
const detachFolioAIEditSnapshotExternalHyperlinks = (snapshot) => {
|
|
76
|
+
const metadata = metadataOf(snapshot);
|
|
77
|
+
let portable = true;
|
|
78
|
+
metadata.sourceDocument.descendants((node) => {
|
|
79
|
+
const emptyHyperlinks = node.attrs["_emptyHyperlinks"];
|
|
80
|
+
if (Array.isArray(emptyHyperlinks)) {
|
|
81
|
+
for (const hyperlink of emptyHyperlinks) if (typeof hyperlink !== "object" || hyperlink === null || "anchor" in hyperlink || "rId" in hyperlink && (typeof hyperlink.href !== "string" || !externalHrefCanCrossPackage(hyperlink.href))) {
|
|
82
|
+
portable = false;
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const mark of node.marks) {
|
|
87
|
+
if (mark.type.name !== "hyperlink") continue;
|
|
88
|
+
if (!hyperlinkCanCrossPackage(expectHyperlinkMarkAttrs(mark))) {
|
|
89
|
+
portable = false;
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
if (!portable) return null;
|
|
96
|
+
const remapNode = (node) => {
|
|
97
|
+
const emptyHyperlinks = node.attrs["_emptyHyperlinks"];
|
|
98
|
+
const attrs = Array.isArray(emptyHyperlinks) ? {
|
|
99
|
+
...node.attrs,
|
|
100
|
+
_emptyHyperlinks: emptyHyperlinks.map(({ rId: _rId, ...hyperlink }) => hyperlink)
|
|
101
|
+
} : node.attrs;
|
|
102
|
+
let marks = node.marks;
|
|
103
|
+
for (const mark of node.marks) {
|
|
104
|
+
if (mark.type.name !== "hyperlink") continue;
|
|
105
|
+
const { rId: _rId, ...hyperlink } = expectHyperlinkMarkAttrs(mark);
|
|
106
|
+
marks = marks.map((candidate) => candidate === mark ? mark.type.create(hyperlink) : candidate);
|
|
107
|
+
}
|
|
108
|
+
if (attrs === node.attrs && marks === node.marks) return node;
|
|
109
|
+
if (node.isText) return node.mark(marks);
|
|
110
|
+
return recreateProseNodeWithParagraphPropertySource(node, {
|
|
111
|
+
attrs,
|
|
112
|
+
marks
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
const remapped = remapDocument(metadata.sourceDocument, remapNode);
|
|
116
|
+
return remapped === metadata.sourceDocument ? snapshot : createFolioAIEditSnapshotInternal(remapped, metadata.styleResolver);
|
|
117
|
+
};
|
|
118
|
+
/** Rebind imported style identifiers while retaining the source formatting context. */
|
|
119
|
+
const remapFolioAIEditSnapshotStyleReferences = ({ snapshot, styleIdMap, defaultParagraphStyleId, importedStyleResolver, reconcileAuthoredFormatting = false }) => {
|
|
120
|
+
if (defaultParagraphStyleId === void 0 && (styleIdMap.size === 0 || [...styleIdMap].every(([source, target]) => source === target))) return snapshot;
|
|
121
|
+
const metadata = metadataOf(snapshot);
|
|
122
|
+
const remapNode = (node) => {
|
|
123
|
+
const styleId = node.attrs["styleId"];
|
|
124
|
+
const remappedStyleId = typeof styleId === "string" ? styleIdMap.get(styleId) : void 0;
|
|
125
|
+
if (remappedStyleId !== void 0) return recreateProseNodeWithParagraphPropertySource(node, { attrs: {
|
|
126
|
+
...node.attrs,
|
|
127
|
+
styleId: remappedStyleId
|
|
128
|
+
} });
|
|
129
|
+
if (node.isTextblock && typeof styleId !== "string" && defaultParagraphStyleId !== void 0) return recreateProseNodeWithParagraphPropertySource(node, { attrs: {
|
|
130
|
+
...node.attrs,
|
|
131
|
+
styleId: defaultParagraphStyleId
|
|
132
|
+
} });
|
|
133
|
+
if (!node.isText) return node;
|
|
134
|
+
let marks = node.marks;
|
|
135
|
+
for (const mark of node.marks) {
|
|
136
|
+
if (mark.type.name !== "characterStyle") continue;
|
|
137
|
+
const attrs = expectCharacterStyleMarkAttrs(mark);
|
|
138
|
+
const remapped = styleIdMap.get(attrs.styleId);
|
|
139
|
+
if (remapped === void 0) continue;
|
|
140
|
+
marks = marks.map((candidate) => candidate === mark ? mark.type.create({
|
|
141
|
+
...attrs,
|
|
142
|
+
styleId: remapped
|
|
143
|
+
}) : candidate);
|
|
144
|
+
}
|
|
145
|
+
return marks === node.marks ? node : node.mark(marks);
|
|
146
|
+
};
|
|
147
|
+
const remapped = remapDocument(metadata.sourceDocument, remapNode);
|
|
148
|
+
if (remapped === metadata.sourceDocument) return snapshot;
|
|
149
|
+
if (!reconcileAuthoredFormatting) return createFolioAIEditSnapshotInternal(remapped, importedStyleResolver);
|
|
150
|
+
const rebindAuthoredInlineFormatting = (source, candidate) => {
|
|
151
|
+
if (source.childCount !== candidate.childCount) return panic("Style remapping changed the document structure");
|
|
152
|
+
if (source.isInline) {
|
|
153
|
+
if (!source.marks.some(({ type }) => type.name === "runFormattingOverride" || type.name === "characterStyle")) return candidate;
|
|
154
|
+
return candidate;
|
|
155
|
+
}
|
|
156
|
+
const sourceContext = source.type.name === "paragraph" ? paragraphRunStyleContext(source, metadata.styleResolver) : void 0;
|
|
157
|
+
const candidateContext = candidate.type.name === "paragraph" ? paragraphRunStyleContext(candidate, importedStyleResolver) : void 0;
|
|
158
|
+
const children = [];
|
|
159
|
+
let changed = false;
|
|
160
|
+
source.forEach((sourceChild, _offset, index) => {
|
|
161
|
+
const candidateChild = candidate.child(index);
|
|
162
|
+
let next = rebindAuthoredInlineFormatting(sourceChild, candidateChild);
|
|
163
|
+
if (sourceContext && candidateContext && sourceChild.isInline) {
|
|
164
|
+
if (sourceChild.marks.some(({ type }) => type.name === "runFormattingOverride" || type.name === "characterStyle")) {
|
|
165
|
+
const authoredFormatting = readAuthoredRunFormatting({
|
|
166
|
+
context: sourceContext,
|
|
167
|
+
marks: sourceChild.marks,
|
|
168
|
+
styleResolver: metadata.styleResolver
|
|
169
|
+
});
|
|
170
|
+
if (authoredFormatting.styleId !== void 0) authoredFormatting.styleId = styleIdMap.get(authoredFormatting.styleId) ?? authoredFormatting.styleId;
|
|
171
|
+
const marks = reconcileRunFormattingMarks({
|
|
172
|
+
authoredFormatting,
|
|
173
|
+
context: candidateContext,
|
|
174
|
+
node: candidateChild,
|
|
175
|
+
styleResolver: importedStyleResolver
|
|
176
|
+
});
|
|
177
|
+
next = candidateChild.isText ? candidateChild.mark(marks) : recreateProseNodeWithParagraphPropertySource(candidateChild, { marks });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (next !== candidateChild) changed = true;
|
|
181
|
+
children.push(next);
|
|
182
|
+
});
|
|
183
|
+
return changed ? recreateProseNodeWithParagraphPropertySource(candidate, { content: Fragment.fromArray(children) }) : candidate;
|
|
184
|
+
};
|
|
185
|
+
const rebound = rebindAuthoredInlineFormatting(metadata.sourceDocument, remapped);
|
|
186
|
+
return createFolioAIEditSnapshotInternal(rebound, importedStyleResolver);
|
|
187
|
+
};
|
|
20
188
|
const normalizeFolioAIBlockText = (text) => text.replace(/\s+/gu, " ").trim();
|
|
21
189
|
/**
|
|
22
190
|
* Whether a block carries text a reader would see.
|
|
@@ -226,11 +394,18 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
|
|
|
226
394
|
const displayLabel = getDisplayLabel(node);
|
|
227
395
|
const styleId = getStyleId(node);
|
|
228
396
|
const listLevel = getListLevel(node);
|
|
397
|
+
const listReference = getListReference(node);
|
|
229
398
|
const numberingReferenceKey = getNumberingReferenceKey(node);
|
|
230
399
|
if (numberingReferenceKey) numberingReferenceKeys.add(numberingReferenceKey);
|
|
231
400
|
const directAlignment = getDirectAlignment(node);
|
|
232
401
|
const directSpacing = getDirectSpacing(node);
|
|
233
|
-
const
|
|
402
|
+
const directIndentation = getDirectIndentation(node);
|
|
403
|
+
const previewRuns = getPreviewRuns({
|
|
404
|
+
node,
|
|
405
|
+
nodeFrom: pos,
|
|
406
|
+
cleanBlock,
|
|
407
|
+
styleResolver
|
|
408
|
+
});
|
|
234
409
|
const table = getTableLocation({
|
|
235
410
|
path,
|
|
236
411
|
blockIndex: index,
|
|
@@ -246,8 +421,10 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
|
|
|
246
421
|
...displayLabel !== void 0 && { displayLabel },
|
|
247
422
|
...styleId !== void 0 && { styleId },
|
|
248
423
|
...listLevel !== void 0 && { listLevel },
|
|
424
|
+
...listReference !== void 0 && { listReference },
|
|
249
425
|
...directAlignment !== void 0 && { directAlignment },
|
|
250
426
|
...directSpacing !== void 0 && { directSpacing },
|
|
427
|
+
...directIndentation !== void 0 && { directIndentation },
|
|
251
428
|
...previewRuns !== void 0 && { previewRuns },
|
|
252
429
|
...structuralBoundaries.length > 0 && { structuralBoundaries },
|
|
253
430
|
...table !== void 0 && { table }
|
|
@@ -280,6 +457,7 @@ const createFolioAIEditSnapshotInternal = (doc, styleResolver) => {
|
|
|
280
457
|
metadataBySnapshot.set(snapshot, {
|
|
281
458
|
numberingReferenceKeys: [...numberingReferenceKeys],
|
|
282
459
|
sourceDocument: doc,
|
|
460
|
+
styleResolver,
|
|
283
461
|
storyTables: tables
|
|
284
462
|
});
|
|
285
463
|
return snapshot;
|
|
@@ -314,6 +492,16 @@ const getListLevel = (node) => {
|
|
|
314
492
|
const { ilvl } = numPr;
|
|
315
493
|
return typeof ilvl === "number" && Number.isInteger(ilvl) && ilvl >= 0 ? ilvl : void 0;
|
|
316
494
|
};
|
|
495
|
+
const getListReference = (node) => {
|
|
496
|
+
const numPr = node.attrs["numPr"];
|
|
497
|
+
if (typeof numPr !== "object" || numPr === null || !("numId" in numPr)) return void 0;
|
|
498
|
+
const { numId } = numPr;
|
|
499
|
+
const level = "ilvl" in numPr ? numPr.ilvl : 0;
|
|
500
|
+
return typeof numId === "number" && Number.isInteger(numId) && numId > 0 && typeof level === "number" && Number.isInteger(level) && level >= 0 ? {
|
|
501
|
+
numId,
|
|
502
|
+
level
|
|
503
|
+
} : void 0;
|
|
504
|
+
};
|
|
317
505
|
const getNumberingReferenceKey = (node) => {
|
|
318
506
|
const numPr = node.attrs["numPr"];
|
|
319
507
|
if (typeof numPr !== "object" || numPr === null || !("numId" in numPr)) return null;
|
|
@@ -331,17 +519,26 @@ const getStyleId = (node) => {
|
|
|
331
519
|
const getDirectAlignment = (node) => directParagraphAlignment(expectParagraphAttrs(node));
|
|
332
520
|
/** Read only authored `w:spacing`, never effective spacing resolved from a style. */
|
|
333
521
|
const getDirectSpacing = (node) => directParagraphSpacing(expectParagraphAttrs(node));
|
|
522
|
+
/** Read only authored `w:ind`, never effective indentation resolved from a style. */
|
|
523
|
+
const getDirectIndentation = (node) => directParagraphIndentation(expectParagraphAttrs(node));
|
|
334
524
|
const DELETION_MARK = "deletion";
|
|
335
525
|
const HIDDEN_MARK = "hidden";
|
|
336
526
|
const RUN_FORMATTING_OVERRIDE_MARK = "runFormattingOverride";
|
|
337
527
|
const CHARACTER_STYLE_MARK = "characterStyle";
|
|
338
|
-
const getPreviewRuns = (node, styleResolver) => {
|
|
528
|
+
const getPreviewRuns = ({ node, nodeFrom, cleanBlock, styleResolver }) => {
|
|
339
529
|
const runs = [];
|
|
340
530
|
const defaultStyle = getDefaultPreviewRunStyle(node);
|
|
341
531
|
let paragraphStyleContext;
|
|
342
|
-
|
|
343
|
-
|
|
532
|
+
let cleanOffset = 0;
|
|
533
|
+
node.descendants((child, relativePosition) => {
|
|
534
|
+
const text = child.isText ? child.text : runFormattingInlineControlCharacter(child);
|
|
535
|
+
if (text === void 0 || text === null) return true;
|
|
344
536
|
if (child.marks.some((mark) => mark.type.name === DELETION_MARK || mark.type.name === HIDDEN_MARK)) return false;
|
|
537
|
+
const start = nodeFrom + 1 + relativePosition;
|
|
538
|
+
while ((cleanBlock.offsets[cleanOffset] ?? Number.POSITIVE_INFINITY) < start) cleanOffset++;
|
|
539
|
+
const endOffset = cleanOffset + text.length - 1;
|
|
540
|
+
if (cleanBlock.offsets[cleanOffset] !== start || cleanBlock.offsets[endOffset] !== start + text.length - 1) return false;
|
|
541
|
+
cleanOffset += text.length;
|
|
345
542
|
const style = getPreviewRunStyle(child.marks, defaultStyle);
|
|
346
543
|
const hasAuthorshipCarrier = child.marks.some(({ type }) => type.name === RUN_FORMATTING_OVERRIDE_MARK || type.name === CHARACTER_STYLE_MARK);
|
|
347
544
|
let directFormatting;
|
|
@@ -359,11 +556,11 @@ const getPreviewRuns = (node, styleResolver) => {
|
|
|
359
556
|
}
|
|
360
557
|
const previous = runs.at(-1);
|
|
361
558
|
if (previous && samePreviewRunStyle(previous, style) && sameDirectFormatting(previous.directFormatting, directFormatting)) {
|
|
362
|
-
previous.text +=
|
|
559
|
+
previous.text += text;
|
|
363
560
|
return false;
|
|
364
561
|
}
|
|
365
562
|
runs.push({
|
|
366
|
-
text
|
|
563
|
+
text,
|
|
367
564
|
...style,
|
|
368
565
|
...!isEmptyPreviewRunStyle(directFormatting) && { directFormatting }
|
|
369
566
|
});
|
|
@@ -504,6 +701,6 @@ const getColorFromAttrs = (attrs) => {
|
|
|
504
701
|
const samePreviewRunStyle = (run, style) => run.bold === style.bold && run.italic === style.italic && run.underline === style.underline && run.strike === style.strike && run.fontFamily === style.fontFamily && run.fontSizePt === style.fontSizePt && run.color === style.color;
|
|
505
702
|
const isEmptyPreviewRunStyle = ({ bold, italic, underline, strike, fontFamily, fontSizePt, color }) => bold === void 0 && italic === void 0 && underline === void 0 && strike === void 0 && fontFamily === void 0 && fontSizePt === void 0 && color === void 0;
|
|
506
703
|
const sameDirectFormatting = (left, right) => left === void 0 && isEmptyPreviewRunStyle(right) || left !== void 0 && left.bold === right.bold && left.italic === right.italic && left.underline === right.underline && left.strike === right.strike && left.fontFamily === right.fontFamily && left.fontSizePt === right.fontSizePt && left.color === right.color;
|
|
507
|
-
const isUnstyledPreviewRun = ({
|
|
704
|
+
const isUnstyledPreviewRun = ({ directFormatting, ...style }) => isEmptyPreviewRunStyle(style) && (directFormatting === void 0 || isEmptyPreviewRunStyle(directFormatting));
|
|
508
705
|
//#endregion
|
|
509
|
-
export { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, folioStoryTables, hashFolioAIBlockStructuralBoundaries, hashFolioAIBlockText, isFolioAIContentBlock, isHiddenTableRow, normalizeFolioAIBlockText, numberingReferenceKeysOf, projectFolioAIBlockStructuralBoundaries, sourceDocumentOf, storyTablesOf, trailingBodyBlockId };
|
|
706
|
+
export { createFolioAIEditSnapshot, createFolioAIEditSnapshotWithStyleResolver, createFolioAITextRangeHandle, detachFolioAIEditSnapshotExternalHyperlinks, folioStoryTables, hashFolioAIBlockStructuralBoundaries, hashFolioAIBlockText, isFolioAIContentBlock, isHiddenTableRow, normalizeFolioAIBlockText, numberingReferenceKeysOf, projectFolioAIBlockStructuralBoundaries, remapFolioAIEditSnapshotNumberingReferences, remapFolioAIEditSnapshotStyleReferences, sourceDocumentOf, storyTablesOf, styleResolverOf, trailingBodyBlockId };
|
|
@@ -2,13 +2,6 @@ import { FolioStoryTable } from "./snapshot.js";
|
|
|
2
2
|
import { Transaction } from "prosemirror-state";
|
|
3
3
|
import { Node } from "prosemirror-model";
|
|
4
4
|
//#region src/ai-edits/table-geometry.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* One line per table, in the document order tables are numbered in: the
|
|
7
|
-
* table's own properties, then each row's and each cell's. Nested tables get
|
|
8
|
-
* their own lines rather than being folded into their parent's, so a
|
|
9
|
-
* difference names the table it is in.
|
|
10
|
-
*/
|
|
11
|
-
declare const projectTableGeometry: (tables: readonly FolioStoryTable[]) => string[];
|
|
12
5
|
/** Where a cell sits: which table, which row of it, which cell of that row. */
|
|
13
6
|
type TableCellCoordinate = {
|
|
14
7
|
tableIndex: number;
|
|
@@ -39,6 +32,13 @@ type MatchTableGeometryResult = {
|
|
|
39
32
|
/** Tables, rows and cells whose properties the match moved. */
|
|
40
33
|
matched: number;
|
|
41
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* One line per table, in the document order tables are numbered in: the
|
|
37
|
+
* table's own properties, then each row's and each cell's. Nested tables get
|
|
38
|
+
* their own lines rather than being folded into their parent's, so a
|
|
39
|
+
* difference names the table it is in.
|
|
40
|
+
*/
|
|
41
|
+
declare const projectTableGeometry: (tables: readonly FolioStoryTable[]) => string[];
|
|
42
42
|
/**
|
|
43
43
|
* Copy a paired table's, row's and cell's properties from the document it was
|
|
44
44
|
* compared against, recording the previous set so a reject restores it.
|
|
@@ -36,31 +36,6 @@ const scopedAttrs = (attrs, keys) => {
|
|
|
36
36
|
}
|
|
37
37
|
return scoped;
|
|
38
38
|
};
|
|
39
|
-
const cellProjection = (cell) => canonicalJson({
|
|
40
|
-
colspan: cell.attrs["colspan"],
|
|
41
|
-
rowspan: cell.attrs["rowspan"],
|
|
42
|
-
...scopedAttrs(cell.attrs, CELL_SCOPED_ATTRS)
|
|
43
|
-
});
|
|
44
|
-
const rowProjection = (row) => {
|
|
45
|
-
const cells = [];
|
|
46
|
-
row.forEach((cell) => {
|
|
47
|
-
cells.push(cellProjection(cell));
|
|
48
|
-
});
|
|
49
|
-
return `${canonicalJson(scopedAttrs(row.attrs, ROW_SCOPED_ATTRS))}|${cells.join("|")}`;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* One line per table, in the document order tables are numbered in: the
|
|
53
|
-
* table's own properties, then each row's and each cell's. Nested tables get
|
|
54
|
-
* their own lines rather than being folded into their parent's, so a
|
|
55
|
-
* difference names the table it is in.
|
|
56
|
-
*/
|
|
57
|
-
const projectTableGeometry = (tables) => tables.map(({ node }) => {
|
|
58
|
-
const rows = [];
|
|
59
|
-
node.forEach((row) => {
|
|
60
|
-
rows.push(rowProjection(row));
|
|
61
|
-
});
|
|
62
|
-
return `${canonicalJson(scopedAttrs(node.attrs, TABLE_SCOPED_ATTRS))}#${rows.join("#")}`;
|
|
63
|
-
});
|
|
64
39
|
const childPositions = (node, start) => {
|
|
65
40
|
const positions = [];
|
|
66
41
|
let offset = start + 1;
|
|
@@ -99,6 +74,7 @@ const effectiveAttrs = (node) => ({
|
|
|
99
74
|
});
|
|
100
75
|
const TABLE_SCOPE = {
|
|
101
76
|
keys: TABLE_SCOPED_ATTRS,
|
|
77
|
+
signatureOf: (node) => formattingProjection(tableAttrsToFormatting(effectiveAttrs(node))),
|
|
102
78
|
formattingOf: (node) => tableAttrsToFormatting(effectiveAttrs(node)),
|
|
103
79
|
rejectPatch: (previousFormatting) => tableRejectAttrPatch(previousFormatting),
|
|
104
80
|
changeAttr: "tblPrChange",
|
|
@@ -106,6 +82,7 @@ const TABLE_SCOPE = {
|
|
|
106
82
|
};
|
|
107
83
|
const ROW_SCOPE = {
|
|
108
84
|
keys: ROW_SCOPED_ATTRS,
|
|
85
|
+
signatureOf: (node) => scopedValues(node.attrs, ROW_SCOPED_ATTRS),
|
|
109
86
|
formattingOf: (node) => tableRowAttrsToFormatting(node.attrs),
|
|
110
87
|
rejectPatch: (previousFormatting) => tableRowRejectAttrPatch(previousFormatting),
|
|
111
88
|
changeAttr: "trPrChange",
|
|
@@ -113,6 +90,7 @@ const ROW_SCOPE = {
|
|
|
113
90
|
};
|
|
114
91
|
const CELL_SCOPE = {
|
|
115
92
|
keys: CELL_SCOPED_ATTRS,
|
|
93
|
+
signatureOf: (node) => scopedValues(node.attrs, CELL_SCOPED_ATTRS),
|
|
116
94
|
formattingOf: (node) => tableCellAttrsToFormatting(cellAttrsOf(node)),
|
|
117
95
|
rejectPatch: (previousFormatting, liveFormatting) => tableCellRejectAttrPatch(previousFormatting, liveFormatting),
|
|
118
96
|
changeAttr: "tcPrChange",
|
|
@@ -120,6 +98,43 @@ const CELL_SCOPE = {
|
|
|
120
98
|
};
|
|
121
99
|
const scopedValues = (attrs, keys) => canonicalJson(scopedAttrs(attrs, keys));
|
|
122
100
|
/**
|
|
101
|
+
* `sourceXml` and `gridSourceXml` record byte-exact captures; they are
|
|
102
|
+
* deliberately excluded from a tracked formatting decision. Every other
|
|
103
|
+
* parsed property is serializer-supported and belongs in the complete old
|
|
104
|
+
* property set Word stores in a property-change element.
|
|
105
|
+
*/
|
|
106
|
+
const semanticFormatting = (formatting) => {
|
|
107
|
+
if (!formatting) return {};
|
|
108
|
+
const { sourceXml: _sourceXml, gridSourceXml: _gridSourceXml, ...properties } = formatting;
|
|
109
|
+
return properties;
|
|
110
|
+
};
|
|
111
|
+
const formattingProjection = (formatting) => canonicalJson(semanticFormatting(formatting));
|
|
112
|
+
const cellProjection = (cell) => canonicalJson({
|
|
113
|
+
colspan: cell.attrs["colspan"],
|
|
114
|
+
rowspan: cell.attrs["rowspan"],
|
|
115
|
+
...scopedAttrs(cell.attrs, CELL_SCOPED_ATTRS)
|
|
116
|
+
});
|
|
117
|
+
const rowProjection = (row) => {
|
|
118
|
+
const cells = [];
|
|
119
|
+
row.forEach((cell) => {
|
|
120
|
+
cells.push(cellProjection(cell));
|
|
121
|
+
});
|
|
122
|
+
return `${canonicalJson(scopedAttrs(row.attrs, ROW_SCOPED_ATTRS))}|${cells.join("|")}`;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* One line per table, in the document order tables are numbered in: the
|
|
126
|
+
* table's own properties, then each row's and each cell's. Nested tables get
|
|
127
|
+
* their own lines rather than being folded into their parent's, so a
|
|
128
|
+
* difference names the table it is in.
|
|
129
|
+
*/
|
|
130
|
+
const projectTableGeometry = (tables) => tables.map(({ node }) => {
|
|
131
|
+
const rows = [];
|
|
132
|
+
node.forEach((row) => {
|
|
133
|
+
rows.push(rowProjection(row));
|
|
134
|
+
});
|
|
135
|
+
return `${formattingProjection(TABLE_SCOPE.formattingOf(node))}#${rows.join("#")}`;
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
123
138
|
* One node's properties, matched to the node it was paired with, or `null`
|
|
124
139
|
* when the difference cannot be recorded.
|
|
125
140
|
*
|
|
@@ -136,14 +151,15 @@ const scopedValues = (attrs, keys) => canonicalJson(scopedAttrs(attrs, keys));
|
|
|
136
151
|
*/
|
|
137
152
|
const propertyChangeFor = (base, target, position, scope) => {
|
|
138
153
|
const live = scopedValues(base.attrs, scope.keys);
|
|
139
|
-
if (live === scopedValues(target.attrs, scope.keys)) return null;
|
|
140
154
|
const previousFormatting = scope.formattingOf(base);
|
|
155
|
+
const targetFormatting = scope.formattingOf(target);
|
|
156
|
+
if (scope.signatureOf(base) === scope.signatureOf(target)) return null;
|
|
141
157
|
if (scopedValues(scope.rejectPatch(previousFormatting, previousFormatting), scope.keys) !== live) return null;
|
|
142
158
|
return {
|
|
143
159
|
position,
|
|
144
160
|
attrs: {
|
|
145
161
|
...scopedAttrs(target.attrs, scope.keys),
|
|
146
|
-
[ORIGINAL_FORMATTING]:
|
|
162
|
+
[ORIGINAL_FORMATTING]: targetFormatting ?? null
|
|
147
163
|
},
|
|
148
164
|
changeAttr: scope.changeAttr,
|
|
149
165
|
changeType: scope.changeType,
|
|
@@ -3,6 +3,7 @@ import { Node, Schema } from "prosemirror-model";
|
|
|
3
3
|
//#region src/ai-edits/table-template.d.ts
|
|
4
4
|
/** The node an operation should place, by the id of the operation placing it. */
|
|
5
5
|
type FolioTableTemplates = ReadonlyMap<string, Node>;
|
|
6
|
+
type HyperlinkPortability = "strict" | "rebind-external";
|
|
6
7
|
/**
|
|
7
8
|
* Whether a target table can cross into the base package without semantic
|
|
8
9
|
* content being stripped from its template.
|
|
@@ -12,7 +13,7 @@ type FolioTableTemplates = ReadonlyMap<string, Node>;
|
|
|
12
13
|
* bookmarks and unresolved revision metadata are not portable and therefore
|
|
13
14
|
* make a replacement unsafe. Callers can retain their granular plan instead.
|
|
14
15
|
*/
|
|
15
|
-
declare const tableTemplateCanCrossPackageLosslessly: (template: Node) => boolean;
|
|
16
|
+
declare const tableTemplateCanCrossPackageLosslessly: (template: Node, hyperlinkPortability?: HyperlinkPortability) => boolean;
|
|
16
17
|
/**
|
|
17
18
|
* A structural tracked change on a table row.
|
|
18
19
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cloneTableCellsWithParagraphPropertyCaptures, decodeTableCellParagraphSourcePayload, recreateProseNodeWithDetachedParagraphPropertySource } from "../docx/paragraphPropertySource.js";
|
|
2
|
-
import { expectTableCellAttrs } from "../prosemirror/attrs/index.js";
|
|
2
|
+
import { expectHyperlinkMarkAttrs, expectTableCellAttrs } from "../prosemirror/attrs/index.js";
|
|
3
3
|
import { stripBlockIdentityAttrs } from "./block-identity.js";
|
|
4
4
|
import { Fragment } from "prosemirror-model";
|
|
5
5
|
//#region src/ai-edits/table-template.ts
|
|
@@ -50,6 +50,12 @@ const PACKAGE_BOUND_MARK_NAMES = /* @__PURE__ */ new Set([
|
|
|
50
50
|
"deletion",
|
|
51
51
|
"runPropertyChange"
|
|
52
52
|
]);
|
|
53
|
+
const canRebindExternalHyperlink = (mark) => {
|
|
54
|
+
if (mark.type.name !== "hyperlink") return false;
|
|
55
|
+
const { href, rId } = expectHyperlinkMarkAttrs(mark);
|
|
56
|
+
const hasRelationshipId = typeof rId === "string" && rId.length > 0;
|
|
57
|
+
return href.length > 0 && !href.startsWith("#") || href.length === 0 && !hasRelationshipId;
|
|
58
|
+
};
|
|
53
59
|
/**
|
|
54
60
|
* Paragraph attrs cleared on a copied paragraph: its identity, the bookmarks
|
|
55
61
|
* and empty hyperlinks that name package-scoped ids, the section it ended, and
|
|
@@ -98,10 +104,10 @@ const losesAuthoredAttrs = (node) => clearedAttrsOf(node).some((name) => hasAuth
|
|
|
98
104
|
* bookmarks and unresolved revision metadata are not portable and therefore
|
|
99
105
|
* make a replacement unsafe. Callers can retain their granular plan instead.
|
|
100
106
|
*/
|
|
101
|
-
const tableTemplateCanCrossPackageLosslessly = (template) => {
|
|
107
|
+
const tableTemplateCanCrossPackageLosslessly = (template, hyperlinkPortability = "strict") => {
|
|
102
108
|
let portable = true;
|
|
103
109
|
const inspect = (node) => {
|
|
104
|
-
if (PACKAGE_BOUND_NODE_NAMES.has(node.type.name) || node.marks.some((
|
|
110
|
+
if (PACKAGE_BOUND_NODE_NAMES.has(node.type.name) || node.marks.some((mark) => PACKAGE_BOUND_MARK_NAMES.has(mark.type.name) && !(hyperlinkPortability === "rebind-external" && canRebindExternalHyperlink(mark))) || losesAuthoredAttrs(node)) {
|
|
105
111
|
portable = false;
|
|
106
112
|
return false;
|
|
107
113
|
}
|
package/dist/ai-edits/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
-
import { FolioContentBlock, FolioContentInlineBooleanProperty, FolioContentInlineFormatting, FolioContentInlineFormattingPatch, FolioContentParagraphKind, FolioContentParagraphSpacing, FolioContentRun, FolioContentSnapshot, FolioContentTableLocation } from "../compare/content-types.js";
|
|
2
|
+
import { FolioContentBlock, FolioContentInlineBooleanProperty, FolioContentInlineFormatting, FolioContentInlineFormattingPatch, FolioContentListReference, FolioContentParagraphIndentation, FolioContentParagraphKind, FolioContentParagraphSpacing, FolioContentRun, FolioContentSnapshot, FolioContentTableLocation } from "../compare/content-types.js";
|
|
3
3
|
//#region src/ai-edits/types.d.ts
|
|
4
4
|
type FolioAIBlockKind = FolioContentParagraphKind;
|
|
5
5
|
/** Boolean run properties supported by snapshots and range-formatting mutations. */
|
|
@@ -40,6 +40,9 @@ type FolioAIBlock = FolioContentBlock<FolioAIBlockKind> & {
|
|
|
40
40
|
* an explicit zero or false value.
|
|
41
41
|
*/
|
|
42
42
|
type FolioAIParagraphSpacing = FolioContentParagraphSpacing;
|
|
43
|
+
/** The complete modeled attribute set of one direct `w:pPr/w:ind` child. */
|
|
44
|
+
type FolioAIParagraphIndentation = FolioContentParagraphIndentation;
|
|
45
|
+
type FolioAIListReference = FolioContentListReference;
|
|
43
46
|
/**
|
|
44
47
|
* The paragraph properties an operation may set. A subset of `w:pPrChange`'s
|
|
45
48
|
* scope: properties a comparison can see in a block projection and an agent
|
|
@@ -49,14 +52,18 @@ type FolioAIBlockParagraphProperties = {
|
|
|
49
52
|
/** `w:pStyle`. `null` clears the style back to the default. */
|
|
50
53
|
styleId?: string | null;
|
|
51
54
|
/**
|
|
52
|
-
* `w:numPr/w:ilvl`, zero-based. `null` removes `
|
|
53
|
-
*
|
|
55
|
+
* `w:numPr/w:ilvl`, zero-based. `null` removes numbering unless `numbering`
|
|
56
|
+
* supplies a concrete instance; together they retain that instance without
|
|
57
|
+
* an authored level.
|
|
54
58
|
*/
|
|
55
59
|
listLevel?: number | null;
|
|
60
|
+
numbering?: FolioAIListReference | null;
|
|
56
61
|
/** Direct `w:jc`. `null` clears the override and restores style inheritance. */
|
|
57
62
|
alignment?: document_d_exports.ParagraphAlignment | null;
|
|
58
63
|
/** Direct `w:spacing` attributes. `null` removes the whole direct child. */
|
|
59
64
|
spacing?: FolioAIParagraphSpacing | null;
|
|
65
|
+
/** Direct `w:ind` attributes. `null` removes the whole direct child. */
|
|
66
|
+
indentation?: FolioAIParagraphIndentation | null;
|
|
60
67
|
};
|
|
61
68
|
/**
|
|
62
69
|
* Every paragraph of one story, blank ones included.
|
|
@@ -203,12 +210,13 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
|
|
|
203
210
|
type: "insertAfterBlock" | "insertBeforeBlock";
|
|
204
211
|
blockId: string;
|
|
205
212
|
/**
|
|
206
|
-
* The paragraph text to insert.
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* formatting. Blank lines are dropped
|
|
211
|
-
* `splitMultilineText` normalization
|
|
213
|
+
* The paragraph text to insert. With the default `lineBreakMode:
|
|
214
|
+
* "paragraph"`, a line break splits `text` into consecutive
|
|
215
|
+
* paragraphs at the same anchor: only the first paragraph gets
|
|
216
|
+
* `styleId` / `alignment` / `inheritFormatting`, later ones use
|
|
217
|
+
* body formatting. Blank lines are dropped and reported as a
|
|
218
|
+
* `splitMultilineText` normalization. `"inline"` retains the
|
|
219
|
+
* control inside one paragraph.
|
|
212
220
|
*
|
|
213
221
|
* `""` inserts a BLANK paragraph, and is a real edit: adding an empty
|
|
214
222
|
* line is a change a reader sees, and a document that has one where
|
|
@@ -216,6 +224,11 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
|
|
|
216
224
|
* with a tracked paragraph mark, so rejecting closes it away.
|
|
217
225
|
*/
|
|
218
226
|
text: string;
|
|
227
|
+
/**
|
|
228
|
+
* `"paragraph"` (the default) splits newlines into consecutive blocks.
|
|
229
|
+
* `"inline"` retains tabs and hard breaks inside this inserted block.
|
|
230
|
+
*/
|
|
231
|
+
lineBreakMode?: "paragraph" | "inline";
|
|
219
232
|
inheritFormatting?: boolean;
|
|
220
233
|
/**
|
|
221
234
|
* Links this insertion to the deletion that carries the same
|
|
@@ -229,6 +242,13 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
|
|
|
229
242
|
* new page. Use for explicit page-break inserts.
|
|
230
243
|
*/
|
|
231
244
|
pageBreakBefore?: boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Insert one standalone authored `<w:br w:type="page"/>` carrier.
|
|
247
|
+
* This differs from `pageBreakBefore`, which is a paragraph property.
|
|
248
|
+
*/
|
|
249
|
+
hardPageBreak?: {
|
|
250
|
+
clear?: document_d_exports.BreakContent["clear"];
|
|
251
|
+
};
|
|
232
252
|
/**
|
|
233
253
|
* Override the paragraph `styleId` attr of the inserted
|
|
234
254
|
* block (e.g. `ClauseHeading1`). When omitted the inserted
|
|
@@ -242,10 +262,11 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
|
|
|
242
262
|
* anchor's `w:numId`. Without it the inserted paragraph takes the
|
|
243
263
|
* anchor's level, which is the wrong one whenever the new item sits
|
|
244
264
|
* beside a list item at a different depth. `null` gives it no
|
|
245
|
-
* numbering
|
|
246
|
-
*
|
|
265
|
+
* numbering unless `numbering` supplies a concrete instance; together
|
|
266
|
+
* they retain that instance without an authored level.
|
|
247
267
|
*/
|
|
248
268
|
listLevel?: number | null;
|
|
269
|
+
numbering?: FolioAIListReference | null;
|
|
249
270
|
/**
|
|
250
271
|
* Direct `w:jc` for the inserted block. `null` clears alignment copied
|
|
251
272
|
* from the anchor and lets the inserted paragraph's style decide.
|
|
@@ -256,6 +277,8 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & {
|
|
|
256
277
|
* copied from the anchor and lets the inserted paragraph's style decide.
|
|
257
278
|
*/
|
|
258
279
|
spacing?: FolioAIParagraphSpacing | null;
|
|
280
|
+
/** Direct `w:ind` for the inserted block. `null` clears copied indentation. */
|
|
281
|
+
indentation?: FolioAIParagraphIndentation | null;
|
|
259
282
|
comment?: FolioAIComment;
|
|
260
283
|
} | {
|
|
261
284
|
id: string;
|
|
@@ -545,9 +568,8 @@ type FolioAIEditSkippedOperation = {
|
|
|
545
568
|
*/
|
|
546
569
|
type FolioAIEditNormalization =
|
|
547
570
|
/**
|
|
548
|
-
* A line-break in `insertAfterBlock` /
|
|
549
|
-
*
|
|
550
|
-
* lines); the applier split it into one paragraph per non-blank line.
|
|
571
|
+
* A line-break in paragraph-mode `insertAfterBlock` /
|
|
572
|
+
* `insertBeforeBlock` text was split into one paragraph per non-blank line.
|
|
551
573
|
*/
|
|
552
574
|
{
|
|
553
575
|
id: string;
|
|
@@ -574,4 +596,4 @@ type FolioAIEditApplyResult = {
|
|
|
574
596
|
normalizations?: FolioAIEditNormalization[];
|
|
575
597
|
};
|
|
576
598
|
//#endregion
|
|
577
|
-
export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockParagraphProperties, FolioAIBlockPreviewRun, FolioAIBlockStructuralBoundary, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineBooleanProperty, FolioAIInlineFormatting, FolioAIInlineFormattingPatch, FolioAIParagraphSpacing, FolioAISignatureParty, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult };
|
|
599
|
+
export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockParagraphProperties, FolioAIBlockPreviewRun, FolioAIBlockStructuralBoundary, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineBooleanProperty, FolioAIInlineFormatting, FolioAIInlineFormattingPatch, FolioAIListReference, FolioAIParagraphIndentation, FolioAIParagraphSpacing, FolioAISignatureParty, FolioAITextRangeHandle, FolioDocumentNavigationTarget, FolioDocumentOutline, FolioDocumentOutlineEntry, FolioDocumentSection, FolioDocumentSectionHandle, FolioDocumentSectionReadResult };
|