docx-diff-editor 1.0.41 → 1.0.43
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/README.md +35 -2
- package/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +893 -393
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +893 -394
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -460,6 +460,76 @@ function isProseMirrorJSON(content) {
|
|
|
460
460
|
const obj = content;
|
|
461
461
|
return typeof obj.type === "string" && (obj.type === "doc" || Array.isArray(obj.content));
|
|
462
462
|
}
|
|
463
|
+
async function parseHtmlToJson(html, SuperDoc) {
|
|
464
|
+
const container = document.createElement("div");
|
|
465
|
+
container.style.cssText = "position:absolute;top:-9999px;left:-9999px;width:800px;height:600px;visibility:hidden;";
|
|
466
|
+
document.body.appendChild(container);
|
|
467
|
+
return new Promise((resolve, reject) => {
|
|
468
|
+
let superdoc = null;
|
|
469
|
+
let resolved = false;
|
|
470
|
+
const cleanup = () => {
|
|
471
|
+
setTimeout(() => {
|
|
472
|
+
if (superdoc) {
|
|
473
|
+
try {
|
|
474
|
+
const sd = superdoc;
|
|
475
|
+
superdoc = null;
|
|
476
|
+
sd.destroy?.();
|
|
477
|
+
} catch {
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (container.parentNode) {
|
|
481
|
+
container.parentNode.removeChild(container);
|
|
482
|
+
}
|
|
483
|
+
}, TIMEOUTS.CLEANUP_DELAY);
|
|
484
|
+
};
|
|
485
|
+
setTimeout(async () => {
|
|
486
|
+
if (resolved) return;
|
|
487
|
+
try {
|
|
488
|
+
superdoc = new SuperDoc({
|
|
489
|
+
selector: container,
|
|
490
|
+
html,
|
|
491
|
+
documentMode: "viewing",
|
|
492
|
+
rulers: false,
|
|
493
|
+
user: { name: "Parser", email: "parser@local" },
|
|
494
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
495
|
+
onReady: ({ superdoc: sd }) => {
|
|
496
|
+
if (resolved) return;
|
|
497
|
+
try {
|
|
498
|
+
const editor = sd?.activeEditor;
|
|
499
|
+
if (!editor) {
|
|
500
|
+
throw new Error("No active editor found");
|
|
501
|
+
}
|
|
502
|
+
const json = editor.getJSON();
|
|
503
|
+
resolved = true;
|
|
504
|
+
cleanup();
|
|
505
|
+
resolve(json);
|
|
506
|
+
} catch (err) {
|
|
507
|
+
resolved = true;
|
|
508
|
+
cleanup();
|
|
509
|
+
reject(err);
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
onException: ({ error: err }) => {
|
|
513
|
+
if (resolved) return;
|
|
514
|
+
resolved = true;
|
|
515
|
+
cleanup();
|
|
516
|
+
reject(err);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
setTimeout(() => {
|
|
520
|
+
if (!resolved) {
|
|
521
|
+
resolved = true;
|
|
522
|
+
cleanup();
|
|
523
|
+
reject(new Error("HTML parsing timed out"));
|
|
524
|
+
}
|
|
525
|
+
}, TIMEOUTS.PARSE_TIMEOUT);
|
|
526
|
+
} catch (err) {
|
|
527
|
+
cleanup();
|
|
528
|
+
reject(err);
|
|
529
|
+
}
|
|
530
|
+
}, 50);
|
|
531
|
+
});
|
|
532
|
+
}
|
|
463
533
|
async function parseDocxFile(file, SuperDoc) {
|
|
464
534
|
const container = document.createElement("div");
|
|
465
535
|
container.style.cssText = "position:absolute;top:-9999px;left:-9999px;width:800px;height:600px;visibility:hidden;";
|
|
@@ -703,204 +773,6 @@ function diffDocuments(docA, docB) {
|
|
|
703
773
|
summary
|
|
704
774
|
};
|
|
705
775
|
}
|
|
706
|
-
function createTrackInsertMark(author = DEFAULT_AUTHOR, id) {
|
|
707
|
-
return {
|
|
708
|
-
type: "trackInsert",
|
|
709
|
-
attrs: {
|
|
710
|
-
id: id ?? v4(),
|
|
711
|
-
author: author.name,
|
|
712
|
-
authorEmail: author.email,
|
|
713
|
-
authorImage: "",
|
|
714
|
-
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
715
|
-
}
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
function createTrackDeleteMark(author = DEFAULT_AUTHOR, id) {
|
|
719
|
-
return {
|
|
720
|
-
type: "trackDelete",
|
|
721
|
-
attrs: {
|
|
722
|
-
id: id ?? v4(),
|
|
723
|
-
author: author.name,
|
|
724
|
-
authorEmail: author.email,
|
|
725
|
-
authorImage: "",
|
|
726
|
-
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
function createTrackFormatMark(before, after, author = DEFAULT_AUTHOR) {
|
|
731
|
-
return {
|
|
732
|
-
type: "trackFormat",
|
|
733
|
-
attrs: {
|
|
734
|
-
id: v4(),
|
|
735
|
-
author: author.name,
|
|
736
|
-
authorEmail: author.email,
|
|
737
|
-
authorImage: "",
|
|
738
|
-
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
739
|
-
before,
|
|
740
|
-
after
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// src/services/mergeDocuments.ts
|
|
746
|
-
function cloneNode(node) {
|
|
747
|
-
return JSON.parse(JSON.stringify(node));
|
|
748
|
-
}
|
|
749
|
-
function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
|
|
750
|
-
const merged = cloneNode(docA);
|
|
751
|
-
const charStates = [];
|
|
752
|
-
let insertions = [];
|
|
753
|
-
const formatChanges = diffResult.formatChanges || [];
|
|
754
|
-
function getFormatChangeAt(pos) {
|
|
755
|
-
for (const fc of formatChanges) {
|
|
756
|
-
if (pos >= fc.from && pos < fc.to) {
|
|
757
|
-
return fc;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
return null;
|
|
761
|
-
}
|
|
762
|
-
let docAOffset = 0;
|
|
763
|
-
const segments = diffResult.segments;
|
|
764
|
-
for (let segIdx = 0; segIdx < segments.length; segIdx++) {
|
|
765
|
-
const segment = segments[segIdx];
|
|
766
|
-
if (segment.type === "equal") {
|
|
767
|
-
for (let i = 0; i < segment.text.length; i++) {
|
|
768
|
-
charStates[docAOffset + i] = { type: "equal" };
|
|
769
|
-
}
|
|
770
|
-
docAOffset += segment.text.length;
|
|
771
|
-
} else if (segment.type === "delete") {
|
|
772
|
-
const nextSegment = segments[segIdx + 1];
|
|
773
|
-
const isReplacement = nextSegment && nextSegment.type === "insert";
|
|
774
|
-
const replacementId = isReplacement ? v4() : void 0;
|
|
775
|
-
for (let i = 0; i < segment.text.length; i++) {
|
|
776
|
-
charStates[docAOffset + i] = { type: "delete", replacementId };
|
|
777
|
-
}
|
|
778
|
-
docAOffset += segment.text.length;
|
|
779
|
-
if (isReplacement && nextSegment) {
|
|
780
|
-
insertions.push({
|
|
781
|
-
afterOffset: docAOffset,
|
|
782
|
-
text: nextSegment.text,
|
|
783
|
-
replacementId
|
|
784
|
-
});
|
|
785
|
-
segIdx++;
|
|
786
|
-
}
|
|
787
|
-
} else if (segment.type === "insert") {
|
|
788
|
-
insertions.push({
|
|
789
|
-
afterOffset: docAOffset,
|
|
790
|
-
text: segment.text
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
function transformNode(node, nodeOffset, path) {
|
|
795
|
-
if (node.type === "text" && node.text) {
|
|
796
|
-
const text = node.text;
|
|
797
|
-
const result = [];
|
|
798
|
-
let i = 0;
|
|
799
|
-
while (i < text.length) {
|
|
800
|
-
const charOffset = nodeOffset + i;
|
|
801
|
-
const charState = charStates[charOffset] || { type: "equal" };
|
|
802
|
-
const insertionsHere = insertions.filter((ins) => ins.afterOffset === charOffset);
|
|
803
|
-
for (const ins of insertionsHere) {
|
|
804
|
-
result.push({
|
|
805
|
-
type: "text",
|
|
806
|
-
text: ins.text,
|
|
807
|
-
marks: [...node.marks || [], createTrackInsertMark(author, ins.replacementId)]
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
const currentFormatChange = getFormatChangeAt(nodeOffset + i);
|
|
811
|
-
let j = i + 1;
|
|
812
|
-
while (j < text.length) {
|
|
813
|
-
const nextState = charStates[nodeOffset + j] || { type: "equal" };
|
|
814
|
-
if (nextState.type !== charState.type) break;
|
|
815
|
-
if (insertions.some((ins) => ins.afterOffset === nodeOffset + j)) break;
|
|
816
|
-
const nextFormatChange = getFormatChangeAt(nodeOffset + j);
|
|
817
|
-
if (currentFormatChange !== nextFormatChange) break;
|
|
818
|
-
j++;
|
|
819
|
-
}
|
|
820
|
-
const chunk = text.substring(i, j);
|
|
821
|
-
let marks = [...node.marks || []];
|
|
822
|
-
if (charState.type === "delete") {
|
|
823
|
-
marks.push(createTrackDeleteMark(author, charState.replacementId));
|
|
824
|
-
} else if (charState.type === "equal") {
|
|
825
|
-
if (currentFormatChange) {
|
|
826
|
-
const trackFormatMark = createTrackFormatMark(
|
|
827
|
-
currentFormatChange.before,
|
|
828
|
-
currentFormatChange.after,
|
|
829
|
-
author
|
|
830
|
-
);
|
|
831
|
-
marks = [...currentFormatChange.after, trackFormatMark];
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
result.push({
|
|
835
|
-
type: "text",
|
|
836
|
-
text: chunk,
|
|
837
|
-
marks: marks.length > 0 ? marks : void 0
|
|
838
|
-
});
|
|
839
|
-
i = j;
|
|
840
|
-
}
|
|
841
|
-
const endOffset = nodeOffset + text.length;
|
|
842
|
-
const endInsertions = insertions.filter((ins) => ins.afterOffset === endOffset);
|
|
843
|
-
for (const ins of endInsertions) {
|
|
844
|
-
result.push({
|
|
845
|
-
type: "text",
|
|
846
|
-
text: ins.text,
|
|
847
|
-
marks: [...node.marks || [], createTrackInsertMark(author, ins.replacementId)]
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
insertions = insertions.filter(
|
|
851
|
-
(ins) => ins.afterOffset < nodeOffset || ins.afterOffset > endOffset
|
|
852
|
-
);
|
|
853
|
-
return { nodes: result, consumedLength: text.length };
|
|
854
|
-
}
|
|
855
|
-
if (node.content && Array.isArray(node.content)) {
|
|
856
|
-
const newContent = [];
|
|
857
|
-
let offset = nodeOffset;
|
|
858
|
-
for (const child of node.content) {
|
|
859
|
-
const { nodes, consumedLength } = transformNode(child, offset);
|
|
860
|
-
newContent.push(...nodes);
|
|
861
|
-
offset += consumedLength;
|
|
862
|
-
}
|
|
863
|
-
return {
|
|
864
|
-
nodes: [{ ...node, content: newContent }],
|
|
865
|
-
consumedLength: offset - nodeOffset
|
|
866
|
-
};
|
|
867
|
-
}
|
|
868
|
-
return { nodes: [node], consumedLength: 0 };
|
|
869
|
-
}
|
|
870
|
-
if (merged.content && Array.isArray(merged.content)) {
|
|
871
|
-
const newContent = [];
|
|
872
|
-
let offset = 0;
|
|
873
|
-
for (let i = 0; i < merged.content.length; i++) {
|
|
874
|
-
const child = merged.content[i];
|
|
875
|
-
const { nodes, consumedLength } = transformNode(child, offset);
|
|
876
|
-
newContent.push(...nodes);
|
|
877
|
-
offset += consumedLength;
|
|
878
|
-
}
|
|
879
|
-
merged.content = newContent;
|
|
880
|
-
}
|
|
881
|
-
if (insertions.length > 0) {
|
|
882
|
-
for (const ins of insertions) {
|
|
883
|
-
const insertNode = {
|
|
884
|
-
type: "paragraph",
|
|
885
|
-
content: [
|
|
886
|
-
{
|
|
887
|
-
type: "run",
|
|
888
|
-
content: [
|
|
889
|
-
{
|
|
890
|
-
type: "text",
|
|
891
|
-
text: ins.text,
|
|
892
|
-
marks: [createTrackInsertMark(author, ins.replacementId)]
|
|
893
|
-
}
|
|
894
|
-
]
|
|
895
|
-
}
|
|
896
|
-
]
|
|
897
|
-
};
|
|
898
|
-
if (!merged.content) merged.content = [];
|
|
899
|
-
merged.content.push(insertNode);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
return merged;
|
|
903
|
-
}
|
|
904
776
|
|
|
905
777
|
// src/services/changeContextExtractor.ts
|
|
906
778
|
function extractEnrichedChanges(mergedJson) {
|
|
@@ -1159,6 +1031,44 @@ function groupReplacements(changes) {
|
|
|
1159
1031
|
}
|
|
1160
1032
|
return result;
|
|
1161
1033
|
}
|
|
1034
|
+
function createTrackInsertMark(author = DEFAULT_AUTHOR, id) {
|
|
1035
|
+
return {
|
|
1036
|
+
type: "trackInsert",
|
|
1037
|
+
attrs: {
|
|
1038
|
+
id: id ?? v4(),
|
|
1039
|
+
author: author.name,
|
|
1040
|
+
authorEmail: author.email,
|
|
1041
|
+
authorImage: "",
|
|
1042
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
function createTrackDeleteMark(author = DEFAULT_AUTHOR, id) {
|
|
1047
|
+
return {
|
|
1048
|
+
type: "trackDelete",
|
|
1049
|
+
attrs: {
|
|
1050
|
+
id: id ?? v4(),
|
|
1051
|
+
author: author.name,
|
|
1052
|
+
authorEmail: author.email,
|
|
1053
|
+
authorImage: "",
|
|
1054
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
function createTrackFormatMark(before, after, author = DEFAULT_AUTHOR) {
|
|
1059
|
+
return {
|
|
1060
|
+
type: "trackFormat",
|
|
1061
|
+
attrs: {
|
|
1062
|
+
id: v4(),
|
|
1063
|
+
author: author.name,
|
|
1064
|
+
authorEmail: author.email,
|
|
1065
|
+
authorImage: "",
|
|
1066
|
+
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1067
|
+
before,
|
|
1068
|
+
after
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1162
1072
|
|
|
1163
1073
|
// src/services/nodeAligner.ts
|
|
1164
1074
|
init_nodeFingerprint();
|
|
@@ -1337,7 +1247,165 @@ function alignListItems(listA, listB, listPathA, listPathB) {
|
|
|
1337
1247
|
for (const item of itemsB) {
|
|
1338
1248
|
item.fingerprint = generateFingerprint2(item.node);
|
|
1339
1249
|
}
|
|
1340
|
-
return alignNodes(itemsA, itemsB);
|
|
1250
|
+
return alignNodes(itemsA, itemsB);
|
|
1251
|
+
}
|
|
1252
|
+
function cloneNode(node) {
|
|
1253
|
+
return JSON.parse(JSON.stringify(node));
|
|
1254
|
+
}
|
|
1255
|
+
function mergeDocuments(docA, docB, diffResult, author = DEFAULT_AUTHOR) {
|
|
1256
|
+
const merged = cloneNode(docA);
|
|
1257
|
+
const charStates = [];
|
|
1258
|
+
let insertions = [];
|
|
1259
|
+
const formatChanges = diffResult.formatChanges || [];
|
|
1260
|
+
function getFormatChangeAt(pos) {
|
|
1261
|
+
for (const fc of formatChanges) {
|
|
1262
|
+
if (pos >= fc.from && pos < fc.to) {
|
|
1263
|
+
return fc;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
let docAOffset = 0;
|
|
1269
|
+
const segments = diffResult.segments;
|
|
1270
|
+
for (let segIdx = 0; segIdx < segments.length; segIdx++) {
|
|
1271
|
+
const segment = segments[segIdx];
|
|
1272
|
+
if (segment.type === "equal") {
|
|
1273
|
+
for (let i = 0; i < segment.text.length; i++) {
|
|
1274
|
+
charStates[docAOffset + i] = { type: "equal" };
|
|
1275
|
+
}
|
|
1276
|
+
docAOffset += segment.text.length;
|
|
1277
|
+
} else if (segment.type === "delete") {
|
|
1278
|
+
const nextSegment = segments[segIdx + 1];
|
|
1279
|
+
const isReplacement = nextSegment && nextSegment.type === "insert";
|
|
1280
|
+
const replacementId = isReplacement ? v4() : void 0;
|
|
1281
|
+
for (let i = 0; i < segment.text.length; i++) {
|
|
1282
|
+
charStates[docAOffset + i] = { type: "delete", replacementId };
|
|
1283
|
+
}
|
|
1284
|
+
docAOffset += segment.text.length;
|
|
1285
|
+
if (isReplacement && nextSegment) {
|
|
1286
|
+
insertions.push({
|
|
1287
|
+
afterOffset: docAOffset,
|
|
1288
|
+
text: nextSegment.text,
|
|
1289
|
+
replacementId
|
|
1290
|
+
});
|
|
1291
|
+
segIdx++;
|
|
1292
|
+
}
|
|
1293
|
+
} else if (segment.type === "insert") {
|
|
1294
|
+
insertions.push({
|
|
1295
|
+
afterOffset: docAOffset,
|
|
1296
|
+
text: segment.text
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
function transformNode(node, nodeOffset, path) {
|
|
1301
|
+
if (node.type === "text" && node.text) {
|
|
1302
|
+
const text = node.text;
|
|
1303
|
+
const result = [];
|
|
1304
|
+
let i = 0;
|
|
1305
|
+
while (i < text.length) {
|
|
1306
|
+
const charOffset = nodeOffset + i;
|
|
1307
|
+
const charState = charStates[charOffset] || { type: "equal" };
|
|
1308
|
+
const insertionsHere = insertions.filter((ins) => ins.afterOffset === charOffset);
|
|
1309
|
+
for (const ins of insertionsHere) {
|
|
1310
|
+
result.push({
|
|
1311
|
+
type: "text",
|
|
1312
|
+
text: ins.text,
|
|
1313
|
+
marks: [...node.marks || [], createTrackInsertMark(author, ins.replacementId)]
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
const currentFormatChange = getFormatChangeAt(nodeOffset + i);
|
|
1317
|
+
let j = i + 1;
|
|
1318
|
+
while (j < text.length) {
|
|
1319
|
+
const nextState = charStates[nodeOffset + j] || { type: "equal" };
|
|
1320
|
+
if (nextState.type !== charState.type) break;
|
|
1321
|
+
if (insertions.some((ins) => ins.afterOffset === nodeOffset + j)) break;
|
|
1322
|
+
const nextFormatChange = getFormatChangeAt(nodeOffset + j);
|
|
1323
|
+
if (currentFormatChange !== nextFormatChange) break;
|
|
1324
|
+
j++;
|
|
1325
|
+
}
|
|
1326
|
+
const chunk = text.substring(i, j);
|
|
1327
|
+
let marks = [...node.marks || []];
|
|
1328
|
+
if (charState.type === "delete") {
|
|
1329
|
+
marks.push(createTrackDeleteMark(author, charState.replacementId));
|
|
1330
|
+
} else if (charState.type === "equal") {
|
|
1331
|
+
if (currentFormatChange) {
|
|
1332
|
+
const trackFormatMark = createTrackFormatMark(
|
|
1333
|
+
currentFormatChange.before,
|
|
1334
|
+
currentFormatChange.after,
|
|
1335
|
+
author
|
|
1336
|
+
);
|
|
1337
|
+
marks = [...currentFormatChange.after, trackFormatMark];
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
result.push({
|
|
1341
|
+
type: "text",
|
|
1342
|
+
text: chunk,
|
|
1343
|
+
marks: marks.length > 0 ? marks : void 0
|
|
1344
|
+
});
|
|
1345
|
+
i = j;
|
|
1346
|
+
}
|
|
1347
|
+
const endOffset = nodeOffset + text.length;
|
|
1348
|
+
const endInsertions = insertions.filter((ins) => ins.afterOffset === endOffset);
|
|
1349
|
+
for (const ins of endInsertions) {
|
|
1350
|
+
result.push({
|
|
1351
|
+
type: "text",
|
|
1352
|
+
text: ins.text,
|
|
1353
|
+
marks: [...node.marks || [], createTrackInsertMark(author, ins.replacementId)]
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
insertions = insertions.filter(
|
|
1357
|
+
(ins) => ins.afterOffset < nodeOffset || ins.afterOffset > endOffset
|
|
1358
|
+
);
|
|
1359
|
+
return { nodes: result, consumedLength: text.length };
|
|
1360
|
+
}
|
|
1361
|
+
if (node.content && Array.isArray(node.content)) {
|
|
1362
|
+
const newContent = [];
|
|
1363
|
+
let offset = nodeOffset;
|
|
1364
|
+
for (const child of node.content) {
|
|
1365
|
+
const { nodes, consumedLength } = transformNode(child, offset);
|
|
1366
|
+
newContent.push(...nodes);
|
|
1367
|
+
offset += consumedLength;
|
|
1368
|
+
}
|
|
1369
|
+
return {
|
|
1370
|
+
nodes: [{ ...node, content: newContent }],
|
|
1371
|
+
consumedLength: offset - nodeOffset
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
return { nodes: [node], consumedLength: 0 };
|
|
1375
|
+
}
|
|
1376
|
+
if (merged.content && Array.isArray(merged.content)) {
|
|
1377
|
+
const newContent = [];
|
|
1378
|
+
let offset = 0;
|
|
1379
|
+
for (let i = 0; i < merged.content.length; i++) {
|
|
1380
|
+
const child = merged.content[i];
|
|
1381
|
+
const { nodes, consumedLength } = transformNode(child, offset);
|
|
1382
|
+
newContent.push(...nodes);
|
|
1383
|
+
offset += consumedLength;
|
|
1384
|
+
}
|
|
1385
|
+
merged.content = newContent;
|
|
1386
|
+
}
|
|
1387
|
+
if (insertions.length > 0) {
|
|
1388
|
+
for (const ins of insertions) {
|
|
1389
|
+
const insertNode = {
|
|
1390
|
+
type: "paragraph",
|
|
1391
|
+
content: [
|
|
1392
|
+
{
|
|
1393
|
+
type: "run",
|
|
1394
|
+
content: [
|
|
1395
|
+
{
|
|
1396
|
+
type: "text",
|
|
1397
|
+
text: ins.text,
|
|
1398
|
+
marks: [createTrackInsertMark(author, ins.replacementId)]
|
|
1399
|
+
}
|
|
1400
|
+
]
|
|
1401
|
+
}
|
|
1402
|
+
]
|
|
1403
|
+
};
|
|
1404
|
+
if (!merged.content) merged.content = [];
|
|
1405
|
+
merged.content.push(insertNode);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return merged;
|
|
1341
1409
|
}
|
|
1342
1410
|
|
|
1343
1411
|
// src/services/attrComparer.ts
|
|
@@ -1571,6 +1639,9 @@ function diffTables(tableA, tableB, tablePathA, tablePathB) {
|
|
|
1571
1639
|
function isTable(node) {
|
|
1572
1640
|
return node?.type === "table";
|
|
1573
1641
|
}
|
|
1642
|
+
function isTableRow(node) {
|
|
1643
|
+
return node?.type === "tableRow";
|
|
1644
|
+
}
|
|
1574
1645
|
function getRowLocation(tablePath, rowIndex, tableIndex) {
|
|
1575
1646
|
return `Table ${tableIndex + 1}, Row ${rowIndex + 1}`;
|
|
1576
1647
|
}
|
|
@@ -1607,6 +1678,9 @@ function extractCellText(cell) {
|
|
|
1607
1678
|
function isList(node) {
|
|
1608
1679
|
return node?.type === "bulletList" || node?.type === "orderedList";
|
|
1609
1680
|
}
|
|
1681
|
+
function isListItem(node) {
|
|
1682
|
+
return node?.type === "listItem";
|
|
1683
|
+
}
|
|
1610
1684
|
function extractListItemText(item) {
|
|
1611
1685
|
const texts = [];
|
|
1612
1686
|
function extract(node) {
|
|
@@ -1839,7 +1913,10 @@ function getImagePreview(node) {
|
|
|
1839
1913
|
return "(image)";
|
|
1840
1914
|
}
|
|
1841
1915
|
|
|
1842
|
-
// src/services/
|
|
1916
|
+
// src/services/structuralMerger.ts
|
|
1917
|
+
function cloneNode2(node) {
|
|
1918
|
+
return JSON.parse(JSON.stringify(node));
|
|
1919
|
+
}
|
|
1843
1920
|
function markAllTextAsInserted(node, sharedId, author) {
|
|
1844
1921
|
if (node.type === "text") {
|
|
1845
1922
|
return {
|
|
@@ -1855,7 +1932,7 @@ function markAllTextAsInserted(node, sharedId, author) {
|
|
|
1855
1932
|
)
|
|
1856
1933
|
};
|
|
1857
1934
|
}
|
|
1858
|
-
return node;
|
|
1935
|
+
return { ...node };
|
|
1859
1936
|
}
|
|
1860
1937
|
function markAllTextAsDeleted(node, sharedId, author) {
|
|
1861
1938
|
if (node.type === "text") {
|
|
@@ -1872,10 +1949,7 @@ function markAllTextAsDeleted(node, sharedId, author) {
|
|
|
1872
1949
|
)
|
|
1873
1950
|
};
|
|
1874
1951
|
}
|
|
1875
|
-
return node;
|
|
1876
|
-
}
|
|
1877
|
-
function cloneNode2(node) {
|
|
1878
|
-
return JSON.parse(JSON.stringify(node));
|
|
1952
|
+
return { ...node };
|
|
1879
1953
|
}
|
|
1880
1954
|
function extractTextPreview(node, maxLength = 50) {
|
|
1881
1955
|
const texts = [];
|
|
@@ -1896,197 +1970,361 @@ function extractTextPreview(node, maxLength = 50) {
|
|
|
1896
1970
|
}
|
|
1897
1971
|
return text || "(empty)";
|
|
1898
1972
|
}
|
|
1899
|
-
function
|
|
1900
|
-
|
|
1901
|
-
|
|
1973
|
+
function getNodeTypeDescription(node) {
|
|
1974
|
+
if (isTable(node)) return "Table";
|
|
1975
|
+
if (isList(node)) return "List";
|
|
1976
|
+
if (isListItem(node)) return "List item";
|
|
1977
|
+
if (isTableRow(node)) return "Table row";
|
|
1978
|
+
if (isImage(node)) return "Image";
|
|
1979
|
+
if (node.type === "heading") return `Heading ${node.attrs?.level || 1}`;
|
|
1980
|
+
if (node.type === "paragraph") return "Paragraph";
|
|
1981
|
+
if (node.type === "blockquote") return "Blockquote";
|
|
1982
|
+
if (node.type === "codeBlock") return "Code block";
|
|
1983
|
+
return node.type || "Block";
|
|
1984
|
+
}
|
|
1985
|
+
function mergeWithStructuralAwareness(docA, docB, author = DEFAULT_AUTHOR) {
|
|
1986
|
+
const structuralInfos = [];
|
|
1987
|
+
const summary = [];
|
|
1988
|
+
let textChangeCount = 0;
|
|
1902
1989
|
const alignment = alignDocuments(docA, docB);
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
let
|
|
1906
|
-
for (const
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1990
|
+
const operations = buildMergeOperations(alignment, docA, docB);
|
|
1991
|
+
const mergedContent = [];
|
|
1992
|
+
let blockIndex = 0;
|
|
1993
|
+
for (const op of operations) {
|
|
1994
|
+
blockIndex++;
|
|
1995
|
+
switch (op.type) {
|
|
1996
|
+
case "matched": {
|
|
1997
|
+
const { mergedNode, infos, changes } = mergeMatchedBlock(
|
|
1998
|
+
op.nodeA,
|
|
1999
|
+
op.nodeB,
|
|
2000
|
+
blockIndex,
|
|
2001
|
+
author
|
|
2002
|
+
);
|
|
2003
|
+
mergedContent.push(mergedNode);
|
|
2004
|
+
structuralInfos.push(...infos);
|
|
2005
|
+
textChangeCount += changes;
|
|
2006
|
+
break;
|
|
2007
|
+
}
|
|
2008
|
+
case "inserted": {
|
|
2009
|
+
const { markedNode, info } = createInsertedBlock(
|
|
2010
|
+
op.nodeB,
|
|
2011
|
+
blockIndex,
|
|
2012
|
+
author
|
|
2013
|
+
);
|
|
2014
|
+
mergedContent.push(markedNode);
|
|
2015
|
+
if (info) {
|
|
2016
|
+
structuralInfos.push(info);
|
|
2017
|
+
}
|
|
2018
|
+
break;
|
|
2019
|
+
}
|
|
2020
|
+
case "deleted": {
|
|
2021
|
+
const { markedNode, info } = createDeletedBlock(
|
|
2022
|
+
op.nodeA,
|
|
2023
|
+
blockIndex,
|
|
2024
|
+
author
|
|
2025
|
+
);
|
|
2026
|
+
mergedContent.push(markedNode);
|
|
2027
|
+
if (info) {
|
|
2028
|
+
structuralInfos.push(info);
|
|
2029
|
+
}
|
|
2030
|
+
break;
|
|
2031
|
+
}
|
|
1928
2032
|
}
|
|
1929
|
-
changes.push({
|
|
1930
|
-
id: sharedId,
|
|
1931
|
-
type,
|
|
1932
|
-
nodeType: node.type,
|
|
1933
|
-
path: inserted.path,
|
|
1934
|
-
node: markAllTextAsInserted(cloneNode2(node), sharedId, author)
|
|
1935
|
-
});
|
|
1936
|
-
infos.push({
|
|
1937
|
-
id: sharedId,
|
|
1938
|
-
type,
|
|
1939
|
-
nodeType: node.type,
|
|
1940
|
-
location,
|
|
1941
|
-
preview,
|
|
1942
|
-
author,
|
|
1943
|
-
date
|
|
1944
|
-
});
|
|
1945
2033
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
2034
|
+
const mergedDoc = {
|
|
2035
|
+
type: "doc",
|
|
2036
|
+
content: mergedContent
|
|
2037
|
+
};
|
|
2038
|
+
const insertCount = structuralInfos.filter((i) => i.type.includes("Insert")).length;
|
|
2039
|
+
const deleteCount = structuralInfos.filter((i) => i.type.includes("Delete")).length;
|
|
2040
|
+
if (insertCount > 0) summary.push(`${insertCount} block(s) inserted`);
|
|
2041
|
+
if (deleteCount > 0) summary.push(`${deleteCount} block(s) deleted`);
|
|
2042
|
+
if (textChangeCount > 0) summary.push(`${textChangeCount} text change(s)`);
|
|
2043
|
+
return {
|
|
2044
|
+
mergedDoc,
|
|
2045
|
+
structuralInfos,
|
|
2046
|
+
summary,
|
|
2047
|
+
textChangeCount
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
function buildMergeOperations(alignment, docA, docB) {
|
|
2051
|
+
const operations = [];
|
|
2052
|
+
const matchedFromA = /* @__PURE__ */ new Map();
|
|
2053
|
+
const matchedFromB = /* @__PURE__ */ new Map();
|
|
2054
|
+
for (const match of alignment.matched) {
|
|
2055
|
+
const idxA = match.pathA[0];
|
|
2056
|
+
const idxB = match.pathB[0];
|
|
2057
|
+
matchedFromA.set(idxA, { pathB: match.pathB, similarity: match.similarity });
|
|
2058
|
+
matchedFromB.set(idxB, { pathA: match.pathA, similarity: match.similarity });
|
|
2059
|
+
}
|
|
2060
|
+
const deletedIndices = new Set(alignment.deletions.map((d) => d.path[0]));
|
|
2061
|
+
const processedDeletions = /* @__PURE__ */ new Set();
|
|
2062
|
+
const contentB = docB.content || [];
|
|
2063
|
+
const contentA = docA.content || [];
|
|
2064
|
+
for (let idxB = 0; idxB < contentB.length; idxB++) {
|
|
2065
|
+
const nodeB = contentB[idxB];
|
|
2066
|
+
const match = matchedFromB.get(idxB);
|
|
2067
|
+
if (match) {
|
|
2068
|
+
const idxA = match.pathA[0];
|
|
2069
|
+
const nodeA = contentA[idxA];
|
|
2070
|
+
for (let checkIdx = 0; checkIdx < idxA; checkIdx++) {
|
|
2071
|
+
if (deletedIndices.has(checkIdx) && !processedDeletions.has(checkIdx)) {
|
|
2072
|
+
operations.push({
|
|
2073
|
+
type: "deleted",
|
|
2074
|
+
nodeA: contentA[checkIdx],
|
|
2075
|
+
pathA: [checkIdx]
|
|
2076
|
+
});
|
|
2077
|
+
processedDeletions.add(checkIdx);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
operations.push({
|
|
2081
|
+
type: "matched",
|
|
2082
|
+
nodeA,
|
|
2083
|
+
nodeB,
|
|
2084
|
+
pathA: match.pathA,
|
|
2085
|
+
pathB: [idxB]
|
|
2086
|
+
});
|
|
1961
2087
|
} else {
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2088
|
+
operations.push({
|
|
2089
|
+
type: "inserted",
|
|
2090
|
+
nodeB,
|
|
2091
|
+
pathB: [idxB]
|
|
2092
|
+
});
|
|
1965
2093
|
}
|
|
1966
|
-
changes.push({
|
|
1967
|
-
id: sharedId,
|
|
1968
|
-
type,
|
|
1969
|
-
nodeType: node.type,
|
|
1970
|
-
path: deleted.path,
|
|
1971
|
-
node: markAllTextAsDeleted(cloneNode2(node), sharedId, author)
|
|
1972
|
-
});
|
|
1973
|
-
infos.push({
|
|
1974
|
-
id: sharedId,
|
|
1975
|
-
type,
|
|
1976
|
-
nodeType: node.type,
|
|
1977
|
-
location,
|
|
1978
|
-
preview,
|
|
1979
|
-
author,
|
|
1980
|
-
date
|
|
1981
|
-
});
|
|
1982
2094
|
}
|
|
1983
|
-
for (const
|
|
1984
|
-
const
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
const sharedId = rowChange.id;
|
|
1992
|
-
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
1993
|
-
const rowIndex = rowChange.path[rowChange.path.length - 1];
|
|
1994
|
-
const isInsert = rowChange.type === "rowInsert";
|
|
1995
|
-
const location = getRowLocation(rowChange.path, rowIndex, tableIndex - 1);
|
|
1996
|
-
const preview = getRowPreview(rowChange.node);
|
|
1997
|
-
const markedNode = isInsert ? markAllTextAsInserted(cloneNode2(rowChange.node), sharedId, author) : markAllTextAsDeleted(cloneNode2(rowChange.node), sharedId, author);
|
|
1998
|
-
changes.push({
|
|
1999
|
-
...rowChange,
|
|
2000
|
-
node: markedNode
|
|
2001
|
-
});
|
|
2002
|
-
infos.push({
|
|
2003
|
-
id: sharedId,
|
|
2004
|
-
type: rowChange.type,
|
|
2005
|
-
nodeType: "tableRow",
|
|
2006
|
-
location,
|
|
2007
|
-
preview,
|
|
2008
|
-
author,
|
|
2009
|
-
date
|
|
2010
|
-
});
|
|
2011
|
-
}
|
|
2095
|
+
for (const deletion of alignment.deletions) {
|
|
2096
|
+
const idxA = deletion.path[0];
|
|
2097
|
+
if (!processedDeletions.has(idxA)) {
|
|
2098
|
+
operations.push({
|
|
2099
|
+
type: "deleted",
|
|
2100
|
+
nodeA: deletion.node,
|
|
2101
|
+
pathA: deletion.path
|
|
2102
|
+
});
|
|
2012
2103
|
}
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2104
|
+
}
|
|
2105
|
+
return operations;
|
|
2106
|
+
}
|
|
2107
|
+
function mergeMatchedBlock(nodeA, nodeB, blockIndex, author) {
|
|
2108
|
+
const infos = [];
|
|
2109
|
+
let changes = 0;
|
|
2110
|
+
if (isTable(nodeA) && isTable(nodeB)) {
|
|
2111
|
+
const { mergedTable, tableInfos, changeCount } = mergeMatchedTable(
|
|
2112
|
+
nodeA,
|
|
2113
|
+
nodeB,
|
|
2114
|
+
blockIndex,
|
|
2115
|
+
author
|
|
2116
|
+
);
|
|
2117
|
+
return { mergedNode: mergedTable, infos: tableInfos, changes: changeCount };
|
|
2118
|
+
}
|
|
2119
|
+
if (isList(nodeA) && isList(nodeB)) {
|
|
2120
|
+
const { mergedList, listInfos, changeCount } = mergeMatchedList(
|
|
2121
|
+
nodeA,
|
|
2122
|
+
nodeB,
|
|
2123
|
+
blockIndex,
|
|
2124
|
+
author
|
|
2125
|
+
);
|
|
2126
|
+
return { mergedNode: mergedList, infos: listInfos, changes: changeCount };
|
|
2127
|
+
}
|
|
2128
|
+
const diff = diffDocuments(
|
|
2129
|
+
{ type: "doc", content: [nodeA] },
|
|
2130
|
+
{ type: "doc", content: [nodeB] }
|
|
2131
|
+
);
|
|
2132
|
+
changes = diff.segments.filter((s) => s.type !== "equal").length;
|
|
2133
|
+
changes += diff.formatChanges?.length || 0;
|
|
2134
|
+
const merged = mergeDocuments(
|
|
2135
|
+
{ type: "doc", content: [nodeA] },
|
|
2136
|
+
{ },
|
|
2137
|
+
diff,
|
|
2138
|
+
author
|
|
2139
|
+
);
|
|
2140
|
+
const mergedNode = merged.content?.[0] || cloneNode2(nodeB);
|
|
2141
|
+
return { mergedNode, infos, changes };
|
|
2142
|
+
}
|
|
2143
|
+
function mergeMatchedTable(tableA, tableB, tableIndex, author) {
|
|
2144
|
+
const tableInfos = [];
|
|
2145
|
+
let changeCount = 0;
|
|
2146
|
+
const rowAlignment = alignTableRows(tableA, tableB, [tableIndex - 1], [tableIndex - 1]);
|
|
2147
|
+
const mergedRows = [];
|
|
2148
|
+
const matchedFromA = /* @__PURE__ */ new Map();
|
|
2149
|
+
const matchedFromB = /* @__PURE__ */ new Map();
|
|
2150
|
+
for (const match of rowAlignment.matched) {
|
|
2151
|
+
const idxA = match.pathA[match.pathA.length - 1];
|
|
2152
|
+
const idxB = match.pathB[match.pathB.length - 1];
|
|
2153
|
+
matchedFromA.set(idxA, idxB);
|
|
2154
|
+
matchedFromB.set(idxB, idxA);
|
|
2155
|
+
}
|
|
2156
|
+
const deletedIndices = new Set(rowAlignment.deletions.map((d) => d.path[d.path.length - 1]));
|
|
2157
|
+
const processedDeletions = /* @__PURE__ */ new Set();
|
|
2158
|
+
const rowsA = tableA.content || [];
|
|
2159
|
+
const rowsB = tableB.content || [];
|
|
2160
|
+
for (let idxB = 0; idxB < rowsB.length; idxB++) {
|
|
2161
|
+
const rowB = rowsB[idxB];
|
|
2162
|
+
const matchedIdxA = matchedFromB.get(idxB);
|
|
2163
|
+
if (matchedIdxA !== void 0) {
|
|
2164
|
+
const rowA = rowsA[matchedIdxA];
|
|
2165
|
+
for (let checkIdx = 0; checkIdx < matchedIdxA; checkIdx++) {
|
|
2166
|
+
if (deletedIndices.has(checkIdx) && !processedDeletions.has(checkIdx)) {
|
|
2167
|
+
const deletedRow = rowsA[checkIdx];
|
|
2168
|
+
const changeId = v4();
|
|
2169
|
+
mergedRows.push(markAllTextAsDeleted(cloneNode2(deletedRow), changeId, author));
|
|
2170
|
+
tableInfos.push({
|
|
2171
|
+
id: changeId,
|
|
2172
|
+
type: "rowDelete",
|
|
2173
|
+
nodeType: "tableRow",
|
|
2174
|
+
location: `Table ${tableIndex}, Row ${checkIdx + 1}`,
|
|
2175
|
+
preview: extractTextPreview(deletedRow),
|
|
2176
|
+
author,
|
|
2177
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2178
|
+
});
|
|
2179
|
+
processedDeletions.add(checkIdx);
|
|
2180
|
+
}
|
|
2037
2181
|
}
|
|
2182
|
+
const { mergedNode, changes } = mergeMatchedBlock(rowA, rowB, idxB, author);
|
|
2183
|
+
mergedRows.push(mergedNode);
|
|
2184
|
+
changeCount += changes;
|
|
2185
|
+
} else {
|
|
2186
|
+
const changeId = v4();
|
|
2187
|
+
mergedRows.push(markAllTextAsInserted(cloneNode2(rowB), changeId, author));
|
|
2188
|
+
tableInfos.push({
|
|
2189
|
+
id: changeId,
|
|
2190
|
+
type: "rowInsert",
|
|
2191
|
+
nodeType: "tableRow",
|
|
2192
|
+
location: `Table ${tableIndex}, Row ${idxB + 1}`,
|
|
2193
|
+
preview: extractTextPreview(rowB),
|
|
2194
|
+
author,
|
|
2195
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2196
|
+
});
|
|
2038
2197
|
}
|
|
2039
2198
|
}
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2199
|
+
for (const deletion of rowAlignment.deletions) {
|
|
2200
|
+
const idxA = deletion.path[deletion.path.length - 1];
|
|
2201
|
+
if (!processedDeletions.has(idxA)) {
|
|
2202
|
+
const changeId = v4();
|
|
2203
|
+
mergedRows.push(markAllTextAsDeleted(cloneNode2(deletion.node), changeId, author));
|
|
2204
|
+
tableInfos.push({
|
|
2205
|
+
id: changeId,
|
|
2206
|
+
type: "rowDelete",
|
|
2207
|
+
nodeType: "tableRow",
|
|
2208
|
+
location: `Table ${tableIndex}, Row ${idxA + 1}`,
|
|
2209
|
+
preview: extractTextPreview(deletion.node),
|
|
2210
|
+
author,
|
|
2211
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2054
2214
|
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2215
|
+
const mergedTable = {
|
|
2216
|
+
...tableB,
|
|
2217
|
+
content: mergedRows
|
|
2218
|
+
};
|
|
2219
|
+
return { mergedTable, tableInfos, changeCount };
|
|
2220
|
+
}
|
|
2221
|
+
function mergeMatchedList(listA, listB, listIndex, author) {
|
|
2222
|
+
const listInfos = [];
|
|
2223
|
+
let changeCount = 0;
|
|
2224
|
+
const itemAlignment = alignListItems(listA, listB, [listIndex - 1], [listIndex - 1]);
|
|
2225
|
+
const mergedItems = [];
|
|
2226
|
+
const matchedFromA = /* @__PURE__ */ new Map();
|
|
2227
|
+
const matchedFromB = /* @__PURE__ */ new Map();
|
|
2228
|
+
for (const match of itemAlignment.matched) {
|
|
2229
|
+
const idxA = match.pathA[match.pathA.length - 1];
|
|
2230
|
+
const idxB = match.pathB[match.pathB.length - 1];
|
|
2231
|
+
matchedFromA.set(idxA, idxB);
|
|
2232
|
+
matchedFromB.set(idxB, idxA);
|
|
2233
|
+
}
|
|
2234
|
+
const deletedIndices = new Set(itemAlignment.deletions.map((d) => d.path[d.path.length - 1]));
|
|
2235
|
+
const processedDeletions = /* @__PURE__ */ new Set();
|
|
2236
|
+
const itemsA = listA.content || [];
|
|
2237
|
+
const itemsB = listB.content || [];
|
|
2238
|
+
for (let idxB = 0; idxB < itemsB.length; idxB++) {
|
|
2239
|
+
const itemB = itemsB[idxB];
|
|
2240
|
+
const matchedIdxA = matchedFromB.get(idxB);
|
|
2241
|
+
if (matchedIdxA !== void 0) {
|
|
2242
|
+
const itemA = itemsA[matchedIdxA];
|
|
2243
|
+
for (let checkIdx = 0; checkIdx < matchedIdxA; checkIdx++) {
|
|
2244
|
+
if (deletedIndices.has(checkIdx) && !processedDeletions.has(checkIdx)) {
|
|
2245
|
+
const deletedItem = itemsA[checkIdx];
|
|
2246
|
+
const changeId = v4();
|
|
2247
|
+
mergedItems.push(markAllTextAsDeleted(cloneNode2(deletedItem), changeId, author));
|
|
2248
|
+
listInfos.push({
|
|
2249
|
+
id: changeId,
|
|
2250
|
+
type: "listItemDelete",
|
|
2251
|
+
nodeType: "listItem",
|
|
2252
|
+
location: `List ${listIndex}, Item ${checkIdx + 1}`,
|
|
2253
|
+
preview: extractTextPreview(deletedItem),
|
|
2254
|
+
author,
|
|
2255
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2256
|
+
});
|
|
2257
|
+
processedDeletions.add(checkIdx);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
const { mergedNode, changes } = mergeMatchedBlock(itemA, itemB, idxB, author);
|
|
2261
|
+
mergedItems.push(mergedNode);
|
|
2262
|
+
changeCount += changes;
|
|
2263
|
+
} else {
|
|
2264
|
+
const changeId = v4();
|
|
2265
|
+
mergedItems.push(markAllTextAsInserted(cloneNode2(itemB), changeId, author));
|
|
2266
|
+
listInfos.push({
|
|
2267
|
+
id: changeId,
|
|
2268
|
+
type: "listItemInsert",
|
|
2269
|
+
nodeType: "listItem",
|
|
2270
|
+
location: `List ${listIndex}, Item ${idxB + 1}`,
|
|
2271
|
+
preview: extractTextPreview(itemB),
|
|
2272
|
+
author,
|
|
2273
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2068
2276
|
}
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
return
|
|
2277
|
+
for (const deletion of itemAlignment.deletions) {
|
|
2278
|
+
const idxA = deletion.path[deletion.path.length - 1];
|
|
2279
|
+
if (!processedDeletions.has(idxA)) {
|
|
2280
|
+
const changeId = v4();
|
|
2281
|
+
mergedItems.push(markAllTextAsDeleted(cloneNode2(deletion.node), changeId, author));
|
|
2282
|
+
listInfos.push({
|
|
2283
|
+
id: changeId,
|
|
2284
|
+
type: "listItemDelete",
|
|
2285
|
+
nodeType: "listItem",
|
|
2286
|
+
location: `List ${listIndex}, Item ${idxA + 1}`,
|
|
2287
|
+
preview: extractTextPreview(deletion.node),
|
|
2288
|
+
author,
|
|
2289
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
const mergedList = {
|
|
2294
|
+
...listB,
|
|
2295
|
+
content: mergedItems
|
|
2296
|
+
};
|
|
2297
|
+
return { mergedList, listInfos, changeCount };
|
|
2298
|
+
}
|
|
2299
|
+
function createInsertedBlock(node, blockIndex, author) {
|
|
2300
|
+
const changeId = v4();
|
|
2301
|
+
const markedNode = markAllTextAsInserted(cloneNode2(node), changeId, author);
|
|
2302
|
+
const nodeDesc = getNodeTypeDescription(node);
|
|
2303
|
+
const info = {
|
|
2304
|
+
id: changeId,
|
|
2305
|
+
type: isTable(node) ? "rowInsert" : isList(node) ? "listItemInsert" : isImage(node) ? "imageInsert" : "paragraphInsert",
|
|
2306
|
+
nodeType: node.type || "unknown",
|
|
2307
|
+
location: `${nodeDesc} inserted at position ${blockIndex}`,
|
|
2308
|
+
preview: extractTextPreview(node),
|
|
2309
|
+
author,
|
|
2310
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2311
|
+
};
|
|
2312
|
+
return { markedNode, info };
|
|
2313
|
+
}
|
|
2314
|
+
function createDeletedBlock(node, blockIndex, author) {
|
|
2315
|
+
const changeId = v4();
|
|
2316
|
+
const markedNode = markAllTextAsDeleted(cloneNode2(node), changeId, author);
|
|
2317
|
+
const nodeDesc = getNodeTypeDescription(node);
|
|
2318
|
+
const info = {
|
|
2319
|
+
id: changeId,
|
|
2320
|
+
type: isTable(node) ? "rowDelete" : isList(node) ? "listItemDelete" : isImage(node) ? "imageDelete" : "paragraphDelete",
|
|
2321
|
+
nodeType: node.type || "unknown",
|
|
2322
|
+
location: `${nodeDesc} deleted from position ${blockIndex}`,
|
|
2323
|
+
preview: extractTextPreview(node),
|
|
2324
|
+
author,
|
|
2325
|
+
date: (/* @__PURE__ */ new Date()).toISOString()
|
|
2326
|
+
};
|
|
2327
|
+
return { markedNode, info };
|
|
2090
2328
|
}
|
|
2091
2329
|
var permissionResolver = ({ permission }) => {
|
|
2092
2330
|
return TRACK_CHANGE_PERMISSIONS.includes(permission) ? true : void 0;
|
|
@@ -2525,10 +2763,16 @@ var DocxDiffEditor = forwardRef(
|
|
|
2525
2763
|
}
|
|
2526
2764
|
newJson = content;
|
|
2527
2765
|
}
|
|
2766
|
+
const structuralResult = mergeWithStructuralAwareness(
|
|
2767
|
+
sourceJson,
|
|
2768
|
+
newJson,
|
|
2769
|
+
author
|
|
2770
|
+
);
|
|
2771
|
+
const merged = structuralResult.mergedDoc;
|
|
2772
|
+
const structInfos = structuralResult.structuralInfos;
|
|
2773
|
+
setMergedJson(merged);
|
|
2528
2774
|
const diff = diffDocuments(sourceJson, newJson);
|
|
2529
2775
|
setDiffResult(diff);
|
|
2530
|
-
const merged = mergeDocuments(sourceJson, newJson, diff, author);
|
|
2531
|
-
setMergedJson(merged);
|
|
2532
2776
|
if (superdocRef.current?.activeEditor) {
|
|
2533
2777
|
setEditorContent(superdocRef.current.activeEditor, merged);
|
|
2534
2778
|
enableReviewMode(superdocRef.current);
|
|
@@ -2549,19 +2793,16 @@ var DocxDiffEditor = forwardRef(
|
|
|
2549
2793
|
}, 50);
|
|
2550
2794
|
}
|
|
2551
2795
|
}
|
|
2552
|
-
const { changes: structChanges, infos: structInfos } = processStructuralChanges(
|
|
2553
|
-
sourceJson,
|
|
2554
|
-
newJson,
|
|
2555
|
-
author
|
|
2556
|
-
);
|
|
2557
2796
|
setStructuralChanges(structInfos);
|
|
2558
2797
|
setIsPaneDismissed(false);
|
|
2559
2798
|
const insertions = diff.segments.filter((s) => s.type === "insert").length;
|
|
2560
2799
|
const deletions = diff.segments.filter((s) => s.type === "delete").length;
|
|
2561
2800
|
const formatChanges = diff.formatChanges?.length || 0;
|
|
2562
2801
|
const structuralChangeCount = structInfos.length;
|
|
2563
|
-
const
|
|
2564
|
-
|
|
2802
|
+
const combinedSummary = [...structuralResult.summary];
|
|
2803
|
+
if (diff.summary.length > 0 && structuralResult.summary.length === 0) {
|
|
2804
|
+
combinedSummary.push(...diff.summary);
|
|
2805
|
+
}
|
|
2565
2806
|
const result = {
|
|
2566
2807
|
totalChanges: insertions + deletions + formatChanges + structuralChangeCount,
|
|
2567
2808
|
insertions,
|
|
@@ -2865,6 +3106,16 @@ var DocxDiffEditor = forwardRef(
|
|
|
2865
3106
|
console.warn("[DocxDiffEditor] Failed to set properties:", err);
|
|
2866
3107
|
return false;
|
|
2867
3108
|
}
|
|
3109
|
+
},
|
|
3110
|
+
/**
|
|
3111
|
+
* Parse HTML string to ProseMirror JSON using a hidden SuperDoc instance.
|
|
3112
|
+
* Useful for converting HTML content before using with other methods.
|
|
3113
|
+
*/
|
|
3114
|
+
async parseHtml(html) {
|
|
3115
|
+
if (!SuperDocRef.current) {
|
|
3116
|
+
throw new Error("Editor not initialized");
|
|
3117
|
+
}
|
|
3118
|
+
return parseHtmlToJson(html, SuperDocRef.current);
|
|
2868
3119
|
}
|
|
2869
3120
|
}),
|
|
2870
3121
|
[
|
|
@@ -2945,6 +3196,254 @@ var DocxDiffEditor_default = DocxDiffEditor;
|
|
|
2945
3196
|
|
|
2946
3197
|
// src/services/index.ts
|
|
2947
3198
|
init_nodeFingerprint();
|
|
3199
|
+
function markAllTextAsInserted2(node, sharedId, author) {
|
|
3200
|
+
if (node.type === "text") {
|
|
3201
|
+
return {
|
|
3202
|
+
...node,
|
|
3203
|
+
marks: [...node.marks || [], createTrackInsertMark(author, sharedId)]
|
|
3204
|
+
};
|
|
3205
|
+
}
|
|
3206
|
+
if (node.content && Array.isArray(node.content)) {
|
|
3207
|
+
return {
|
|
3208
|
+
...node,
|
|
3209
|
+
content: node.content.map(
|
|
3210
|
+
(child) => markAllTextAsInserted2(child, sharedId, author)
|
|
3211
|
+
)
|
|
3212
|
+
};
|
|
3213
|
+
}
|
|
3214
|
+
return node;
|
|
3215
|
+
}
|
|
3216
|
+
function markAllTextAsDeleted2(node, sharedId, author) {
|
|
3217
|
+
if (node.type === "text") {
|
|
3218
|
+
return {
|
|
3219
|
+
...node,
|
|
3220
|
+
marks: [...node.marks || [], createTrackDeleteMark(author, sharedId)]
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
if (node.content && Array.isArray(node.content)) {
|
|
3224
|
+
return {
|
|
3225
|
+
...node,
|
|
3226
|
+
content: node.content.map(
|
|
3227
|
+
(child) => markAllTextAsDeleted2(child, sharedId, author)
|
|
3228
|
+
)
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
return node;
|
|
3232
|
+
}
|
|
3233
|
+
function cloneNode3(node) {
|
|
3234
|
+
return JSON.parse(JSON.stringify(node));
|
|
3235
|
+
}
|
|
3236
|
+
function extractTextPreview2(node, maxLength = 50) {
|
|
3237
|
+
const texts = [];
|
|
3238
|
+
function extract(n) {
|
|
3239
|
+
if (n.type === "text") {
|
|
3240
|
+
texts.push(n.text || "");
|
|
3241
|
+
}
|
|
3242
|
+
if (n.content) {
|
|
3243
|
+
for (const child of n.content) {
|
|
3244
|
+
extract(child);
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
extract(node);
|
|
3249
|
+
const text = texts.join("").trim();
|
|
3250
|
+
if (text.length > maxLength) {
|
|
3251
|
+
return text.substring(0, maxLength - 3) + "...";
|
|
3252
|
+
}
|
|
3253
|
+
return text || "(empty)";
|
|
3254
|
+
}
|
|
3255
|
+
function processStructuralChanges(docA, docB, author = DEFAULT_AUTHOR) {
|
|
3256
|
+
const changes = [];
|
|
3257
|
+
const infos = [];
|
|
3258
|
+
const alignment = alignDocuments(docA, docB);
|
|
3259
|
+
let tableIndex = 0;
|
|
3260
|
+
let listIndex = 0;
|
|
3261
|
+
let paragraphIndex = 0;
|
|
3262
|
+
for (const inserted of alignment.insertions) {
|
|
3263
|
+
const node = inserted.node;
|
|
3264
|
+
const sharedId = v4();
|
|
3265
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
3266
|
+
let type = "paragraphInsert";
|
|
3267
|
+
let location = "";
|
|
3268
|
+
let preview = "";
|
|
3269
|
+
if (isTable(node)) {
|
|
3270
|
+
type = "rowInsert";
|
|
3271
|
+
location = `New table at position ${inserted.path[0] + 1}`;
|
|
3272
|
+
preview = `Table with ${node.content?.length || 0} rows`;
|
|
3273
|
+
tableIndex++;
|
|
3274
|
+
} else if (isList(node)) {
|
|
3275
|
+
type = "listItemInsert";
|
|
3276
|
+
location = `New list at position ${inserted.path[0] + 1}`;
|
|
3277
|
+
preview = `List with ${node.content?.length || 0} items`;
|
|
3278
|
+
listIndex++;
|
|
3279
|
+
} else {
|
|
3280
|
+
type = "paragraphInsert";
|
|
3281
|
+
paragraphIndex++;
|
|
3282
|
+
location = `Paragraph ${paragraphIndex}`;
|
|
3283
|
+
preview = extractTextPreview2(node);
|
|
3284
|
+
}
|
|
3285
|
+
changes.push({
|
|
3286
|
+
id: sharedId,
|
|
3287
|
+
type,
|
|
3288
|
+
nodeType: node.type,
|
|
3289
|
+
path: inserted.path,
|
|
3290
|
+
node: markAllTextAsInserted2(cloneNode3(node), sharedId, author)
|
|
3291
|
+
});
|
|
3292
|
+
infos.push({
|
|
3293
|
+
id: sharedId,
|
|
3294
|
+
type,
|
|
3295
|
+
nodeType: node.type,
|
|
3296
|
+
location,
|
|
3297
|
+
preview,
|
|
3298
|
+
author,
|
|
3299
|
+
date
|
|
3300
|
+
});
|
|
3301
|
+
}
|
|
3302
|
+
for (const deleted of alignment.deletions) {
|
|
3303
|
+
const node = deleted.node;
|
|
3304
|
+
const sharedId = v4();
|
|
3305
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
3306
|
+
let type = "paragraphDelete";
|
|
3307
|
+
let location = "";
|
|
3308
|
+
let preview = "";
|
|
3309
|
+
if (isTable(node)) {
|
|
3310
|
+
type = "rowDelete";
|
|
3311
|
+
location = `Deleted table at position ${deleted.path[0] + 1}`;
|
|
3312
|
+
preview = `Table with ${node.content?.length || 0} rows`;
|
|
3313
|
+
} else if (isList(node)) {
|
|
3314
|
+
type = "listItemDelete";
|
|
3315
|
+
location = `Deleted list at position ${deleted.path[0] + 1}`;
|
|
3316
|
+
preview = `List with ${node.content?.length || 0} items`;
|
|
3317
|
+
} else {
|
|
3318
|
+
type = "paragraphDelete";
|
|
3319
|
+
location = `Deleted paragraph`;
|
|
3320
|
+
preview = extractTextPreview2(node);
|
|
3321
|
+
}
|
|
3322
|
+
changes.push({
|
|
3323
|
+
id: sharedId,
|
|
3324
|
+
type,
|
|
3325
|
+
nodeType: node.type,
|
|
3326
|
+
path: deleted.path,
|
|
3327
|
+
node: markAllTextAsDeleted2(cloneNode3(node), sharedId, author)
|
|
3328
|
+
});
|
|
3329
|
+
infos.push({
|
|
3330
|
+
id: sharedId,
|
|
3331
|
+
type,
|
|
3332
|
+
nodeType: node.type,
|
|
3333
|
+
location,
|
|
3334
|
+
preview,
|
|
3335
|
+
author,
|
|
3336
|
+
date
|
|
3337
|
+
});
|
|
3338
|
+
}
|
|
3339
|
+
for (const match of alignment.matched) {
|
|
3340
|
+
const nodeA = docA.content?.[match.pathA[0]];
|
|
3341
|
+
const nodeB = docB.content?.[match.pathB[0]];
|
|
3342
|
+
if (!nodeA || !nodeB) continue;
|
|
3343
|
+
if (isTable(nodeA) && isTable(nodeB)) {
|
|
3344
|
+
tableIndex++;
|
|
3345
|
+
const tableResult = diffTables(nodeA, nodeB, match.pathA, match.pathB);
|
|
3346
|
+
for (const rowChange of tableResult.rowChanges) {
|
|
3347
|
+
const sharedId = rowChange.id;
|
|
3348
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
3349
|
+
const rowIndex = rowChange.path[rowChange.path.length - 1];
|
|
3350
|
+
const isInsert = rowChange.type === "rowInsert";
|
|
3351
|
+
const location = getRowLocation(rowChange.path, rowIndex, tableIndex - 1);
|
|
3352
|
+
const preview = getRowPreview(rowChange.node);
|
|
3353
|
+
const markedNode = isInsert ? markAllTextAsInserted2(cloneNode3(rowChange.node), sharedId, author) : markAllTextAsDeleted2(cloneNode3(rowChange.node), sharedId, author);
|
|
3354
|
+
changes.push({
|
|
3355
|
+
...rowChange,
|
|
3356
|
+
node: markedNode
|
|
3357
|
+
});
|
|
3358
|
+
infos.push({
|
|
3359
|
+
id: sharedId,
|
|
3360
|
+
type: rowChange.type,
|
|
3361
|
+
nodeType: "tableRow",
|
|
3362
|
+
location,
|
|
3363
|
+
preview,
|
|
3364
|
+
author,
|
|
3365
|
+
date
|
|
3366
|
+
});
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
if (isList(nodeA) && isList(nodeB)) {
|
|
3370
|
+
listIndex++;
|
|
3371
|
+
const listResult = diffLists(nodeA, nodeB, match.pathA, match.pathB);
|
|
3372
|
+
for (const itemChange of listResult.itemChanges) {
|
|
3373
|
+
const sharedId = itemChange.id;
|
|
3374
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
3375
|
+
const itemIndex = itemChange.path[itemChange.path.length - 1];
|
|
3376
|
+
const isInsert = itemChange.type === "listItemInsert";
|
|
3377
|
+
const location = getListItemLocation(itemChange.path, itemIndex, listIndex - 1);
|
|
3378
|
+
const preview = getListItemPreview(itemChange.node);
|
|
3379
|
+
const markedNode = isInsert ? markAllTextAsInserted2(cloneNode3(itemChange.node), sharedId, author) : markAllTextAsDeleted2(cloneNode3(itemChange.node), sharedId, author);
|
|
3380
|
+
changes.push({
|
|
3381
|
+
...itemChange,
|
|
3382
|
+
node: markedNode
|
|
3383
|
+
});
|
|
3384
|
+
infos.push({
|
|
3385
|
+
id: sharedId,
|
|
3386
|
+
type: itemChange.type,
|
|
3387
|
+
nodeType: "listItem",
|
|
3388
|
+
location,
|
|
3389
|
+
preview,
|
|
3390
|
+
author,
|
|
3391
|
+
date
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
const imageChanges = diffImages(docA, docB);
|
|
3397
|
+
for (const imgInsert of imageChanges.inserted) {
|
|
3398
|
+
const sharedId = imgInsert.id;
|
|
3399
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
3400
|
+
infos.push({
|
|
3401
|
+
id: sharedId,
|
|
3402
|
+
type: "imageInsert",
|
|
3403
|
+
nodeType: "image",
|
|
3404
|
+
location: getImageLocation(imgInsert.path),
|
|
3405
|
+
preview: getImagePreview(imgInsert.node),
|
|
3406
|
+
author,
|
|
3407
|
+
date
|
|
3408
|
+
});
|
|
3409
|
+
changes.push(imgInsert);
|
|
3410
|
+
}
|
|
3411
|
+
for (const imgDelete of imageChanges.deleted) {
|
|
3412
|
+
const sharedId = imgDelete.id;
|
|
3413
|
+
const date = (/* @__PURE__ */ new Date()).toISOString();
|
|
3414
|
+
infos.push({
|
|
3415
|
+
id: sharedId,
|
|
3416
|
+
type: "imageDelete",
|
|
3417
|
+
nodeType: "image",
|
|
3418
|
+
location: getImageLocation(imgDelete.path),
|
|
3419
|
+
preview: getImagePreview(imgDelete.node),
|
|
3420
|
+
author,
|
|
3421
|
+
date
|
|
3422
|
+
});
|
|
3423
|
+
changes.push(imgDelete);
|
|
3424
|
+
}
|
|
3425
|
+
return { changes, infos };
|
|
3426
|
+
}
|
|
3427
|
+
function generateStructuralChangeSummary(infos) {
|
|
3428
|
+
const summary = [];
|
|
3429
|
+
const rowInserts = infos.filter((i) => i.type === "rowInsert").length;
|
|
3430
|
+
const rowDeletes = infos.filter((i) => i.type === "rowDelete").length;
|
|
3431
|
+
const paragraphInserts = infos.filter((i) => i.type === "paragraphInsert").length;
|
|
3432
|
+
const paragraphDeletes = infos.filter((i) => i.type === "paragraphDelete").length;
|
|
3433
|
+
const listItemInserts = infos.filter((i) => i.type === "listItemInsert").length;
|
|
3434
|
+
const listItemDeletes = infos.filter((i) => i.type === "listItemDelete").length;
|
|
3435
|
+
const imageInserts = infos.filter((i) => i.type === "imageInsert").length;
|
|
3436
|
+
const imageDeletes = infos.filter((i) => i.type === "imageDelete").length;
|
|
3437
|
+
if (rowInserts > 0) summary.push(`${rowInserts} row(s) inserted`);
|
|
3438
|
+
if (rowDeletes > 0) summary.push(`${rowDeletes} row(s) deleted`);
|
|
3439
|
+
if (paragraphInserts > 0) summary.push(`${paragraphInserts} paragraph(s) inserted`);
|
|
3440
|
+
if (paragraphDeletes > 0) summary.push(`${paragraphDeletes} paragraph(s) deleted`);
|
|
3441
|
+
if (listItemInserts > 0) summary.push(`${listItemInserts} list item(s) inserted`);
|
|
3442
|
+
if (listItemDeletes > 0) summary.push(`${listItemDeletes} list item(s) deleted`);
|
|
3443
|
+
if (imageInserts > 0) summary.push(`${imageInserts} image(s) inserted`);
|
|
3444
|
+
if (imageDeletes > 0) summary.push(`${imageDeletes} image(s) deleted`);
|
|
3445
|
+
return summary;
|
|
3446
|
+
}
|
|
2948
3447
|
|
|
2949
3448
|
// src/blankTemplate.ts
|
|
2950
3449
|
var BLANK_DOCX_BASE64 = `UEsDBBQABgAIAAAAIQDfpNJsWgEAACAFAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0lMtuwjAQRfeV+g+Rt1Vi6KKqKgKLPpYtUukHGHsCVv2Sx7z+vhMCUVUBkQpsIiUz994zVsaD0dqabAkRtXcl6xc9loGTXmk3K9nX5C1/ZBkm4ZQw3kHJNoBsNLy9GUw2ATAjtcOSzVMKT5yjnIMVWPgAjiqVj1Ykeo0zHoT8FjPg973eA5feJXApT7UHGw5eoBILk7LXNX1uSCIYZNlz01hnlUyEYLQUiep86dSflHyXUJBy24NzHfCOGhg/mFBXjgfsdB90NFEryMYipndhqYuvfFRcebmwpCxO2xzg9FWlJbT62i1ELwGRztyaoq1Yod2e/ygHpo0BvDxF49sdDymR4BoAO+dOhBVMP69G8cu8E6Si3ImYGrg8RmvdCZFoA6F59s/m2NqciqTOcfQBaaPjP8ber2ytzmngADHp039dm0jWZ88H9W2gQB3I5tv7bfgDAAD//wMAUEsDBBQABgAIAAAAIQAekRq37wAAAE4CAAALAAgCX3JlbHMvLnJlbHMgogQCKKAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArJLBasMwDEDvg/2D0b1R2sEYo04vY9DbGNkHCFtJTBPb2GrX/v082NgCXelhR8vS05PQenOcRnXglF3wGpZVDYq9Cdb5XsNb+7x4AJWFvKUxeNZw4gyb5vZm/cojSSnKg4tZFYrPGgaR+IiYzcAT5SpE9uWnC2kiKc/UYySzo55xVdf3mH4zoJkx1dZqSFt7B6o9Rb6GHbrOGX4KZj+xlzMtkI/C3rJdxFTqk7gyjWop9SwabDAvJZyRYqwKGvC80ep6o7+nxYmFLAmhCYkv+3xmXBJa/ueK5hk/Nu8hWbRf4W8bnF1B8wEAAP//AwBQSwMEFAAGAAgAAAAhANZks1H0AAAAMQMAABwACAF3b3JkL19yZWxzL2RvY3VtZW50LnhtbC5yZWxzIKIEASigAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArJLLasMwEEX3hf6DmH0tO31QQuRsSiHb1v0ARR4/qCwJzfThv69ISevQYLrwcq6Yc8+ANtvPwYp3jNR7p6DIchDojK971yp4qR6v7kEQa1dr6x0qGJFgW15ebJ7Qak5L1PWBRKI4UtAxh7WUZDocNGU+oEsvjY+D5jTGVgZtXnWLcpXndzJOGVCeMMWuVhB39TWIagz4H7Zvmt7ggzdvAzo+UyE/cP+MzOk4SlgdW2QFkzBLRJDnRVZLitAfi2Myp1AsqsCjxanAYZ6rv12yntMu/rYfxu+wmHO4WdKh8Y4rvbcTj5/oKCFPPnr5BQAA//8DAFBLAwQUAAYACAAAACEARKNl8bMCAADNCgAAEQAAAHdvcmQvZG9jdW1lbnQueG1spJbbbpwwEIbvK/UdEPeJgT0GZZOLpo1yUSlq2gfwGgNW8EG2d9nt03fMuSWNWHKzxjb/N8N4Zta39ydeeEeqDZNi54fXge9RQWTCRLbzf/38drX1PWOxSHAhBd35Z2r8+7vPn27LOJHkwKmwHiCEiUtFdn5urYoRMiSnHJtrzoiWRqb2mkiOZJoyQlEpdYKiIAyqJ6UlocaAvS9YHLHxGxw5TaMlGpcgdsAlIjnWlp56RngxZIVu0HYMimaA4AujcIxaXIxaI+fVCLScBQKvRqTVPNIbH7eeR4rGpM080mJM2s4jjdKJjxNcKipgM5WaYwtTnSGO9etBXQFYYcv2rGD2DMxg3WIwE68zPAJVR+CL5GLCBnGZ0GKRtBS58w9axI3+qtM71+Na3wydghbTzIK5G0RPtjC21eopsavlD01jqaKGNC0gjlKYnKmuO/C5NNjMW8jxvQAcedG+V6pwYqn9r7U91MfQA6e435wdL2rP3yeGwYTTdIhOMcWFv222nnDI4N7wrNAMghtObD4tIBoB1oRO/LNoGduGgUhf3Y7DJpZVy6lPxXFYH9hwYg/815kBwCQ2yS+iRG1ckdNii3NsukR3RHqZU6sOd+aDGKnsY4XwqOVB9TT2MdpT3xJLdzm5gNUU1LDIzcececmxgk7JSfyUCanxvgCPoDw8yHCvOgH3C4nihuqRnqp1d9ae6zH+Hdyq9jI5u1F5ZQy3suTHzg+CzWrxNYCrWbP0QFN8KOxgBzmJocQ+6zd0FS97+Q1bUPZhFC0rFmRYuNouG7XKvmMnthK6U7gMN5U5luVgJ9wEoZvupbWS99sFTQe7OcUJhT6/CbZumkppB9PsYKtpY47IwsCqUZjQ+p1qGS6Vj9rFKC6YoM/MEvBysa5EqP3E6rEOFOrvoXd/AAAA//8DAFBLAwQUAAYACAAAACEApyWe8toGAADLIAAAFQAAAHdvcmQvdGhlbWUvdGhlbWUxLnhtbOxZW4sbNxR+L/Q/iHl3fJvxJcQp9thuLrtJyDopfdTa8oxizchI8m5MCZT0qS+FQlr60EDf+lBKCy009KU/JpDQpj+iRxrbM7Llpkk2EMquYa3Ld44+nXN0dDxz6YP7CUMnREjK045XvVDxEEnHfELTqOPdGQ1LLQ9JhdMJZjwlHW9JpPfB5fffu4QvqpgkBIF8Ki/ijhcrNb9YLssxDGN5gc9JCnNTLhKsoCui8kTgU9CbsHKtUmmUE0xTD6U4AbUjkEETgm5Op3RMvMtr9QMG/1Il9cCYiSOtnKxkCtjJrKq/5FKGTKATzDoerDThpyNyX3mIYalgouNVzJ9XvnypvBFiao9sQW5o/lZyK4HJrGbkRHS8EfT9wG90N/oNgKld3KA5aAwaG30GgMdj2GnGxdbZrIX+ClsAZU2H7n6zX69a+IL++g6+G+iPhTegrOnv4IfDMLdhAZQ1gx180Gv3+rZ+A8qajR18s9Lt+00Lb0Axo+lsB10JGvVwvdsNZMrZFSe8HfjDZm0Fz1HlQnRl8qnaF2sJvsfFEADGuVjRFKnlnEzxGHAhZvRYUHRAoxgCb45TLmG4UqsMK3X4rz++aRmP4osEF6SzobHcGdJ8kBwLOlcd7xpo9QqQZ0+ePH3469OHvz397LOnD39arb0rdwWnUVHuxfdf/v34U/TXL9+9ePSVGy+L+Oc/fv789z/+Tb2yaH398/Nff372zRd//vDIAe8KfFyEj2hCJLpBTtFtnsAGHQuQY/FqEqMY06JEN40kTrGWcaAHKrbQN5aYYQeuR2w73hWQLlzADxf3LMJHsVgo6gBejxMLeMg563Hh3NN1vVbRCos0ci8uFkXcbYxPXGuHW14eLOYQ99SlMoyJRfMWA5fjiKREIT3HZ4Q4xD6m1LLrIR0LLvlUoY8p6mHqNMmIHlvRlAtdoQn4ZekiCP62bHN4F/U4c6nvkxMbCWcDM5dKwiwzfogXCidOxjhhReQBVrGL5NFSjC2DSwWejgjjaDAhUrpkboqlRfc6pBm32w/ZMrGRQtGZC3mAOS8i+3wWxjiZOznTNC5ir8oZhChGt7hykuD2CdF98ANO97r7LiWWu19+tu9AGnIHiJ5ZCNeRINw+j0s2xcSlvCsSK8V2BXVGR28RWaF9QAjDp3hCCLpz1YXnc8vmOelrMWSVK8Rlm2vYjlXdT4kkyBQ3DsdSaYXsEYn4Hj6Hy63Es8RpgsU+zTdmdsgM4KpLnPHKxjMrlVKhD62bxE2ZWPvbq/VWjK2w0n3pjtelsPz3X84YyNx7DRnyyjKQ2P+zbUaYWQvkATPCUGW40i2IWO7PRfRxMmILp9zUPrS5G8pbRU9C05dWQFu1T/D2ah+oMJ59+9iBPZt6xw18k0pnXzLZrm/24barmpCLCX33i5o+XqS3CNwjDuh5TXNe0/zva5p95/m8kjmvZM4rGbfIW6hk8uLFPAJaP+gxWpK9T32mlLEjtWTkQJqyR8LZnwxh0HSM0OYh0zyG5mo5CxcJbNpIcPURVfFRjOewTNWsEMmV6kiiOZdQOJlhp249wRbJIZ9ko9Xq+rkmCGCVj0PhtR6HMk1lo41m/gBvo970IvOgdU1Ay74KicJiNom6g0RzPfgSEmZnZ8Ki7WDR0ur3sjBfK6/A5YSwfige+BkjCDcI6Yn2Uya/9u6Ze3qfMe1t1xzba2uuZ+Npi0Qh3GwShTCM4fLYHj5jX7dzl1r0tCl2aTRbb8PXOols5QaW2j10CmeuHoCaMZ53vCn8ZIJmMgd9UmcqzKK0443VytCvk1nmQqo+lnEGM1PZ/hOqiECMJhDrRTewNOdWrTX1Ht9Rcu3Ku2c581V0MplOyVjtGcm7MJcpcc6+IVh3+AJIH8WTU3TMFuI2BkMFzao24IRKtbHmhIpCcOdW3EpXq6NovW/Jjyhm8xivbpRiMs/gpr2hU9iHYbq9K7u/2sxxpJ30xrfuy4X0RCFp7rlA9K3pzh9v75IvsMrzvsUqS93bua69znX7bok3vxAK1PLFLGqasYNaPmpTO8OCoLDcJjT33RFnfRtsR62+INZ1pentvNjmx/cg8vtQrS6YkoYq/GoROFy/kswygRldZ5f7Ci0E7XifVIKuH9aCsFRpBYOSX/crpVbQrZe6QVCvDoJqpd+rPQCjqDipBtnaQ/ixz5arN/dmfOftfbIutS+MeVLmpg4uG2Hz9r5as97eZ3UyGul5D1GwzCeN2rBdb/capXa9Oyz5/V6r1A4bvVK/ETb7w34YtNrDBx46MWC/Ww/9xqBValTDsOQ3Kpp+q11q+rVa1292WwO/+2Bla9j5+nttXsPr8j8AAAD//wMAUEsDBBQABgAIAAAAIQCcvUET3gMAADwLAAARAAAAd29yZC9zZXR0aW5ncy54bWy0Vk1v4zYQvRfofzB0riLJtryOus7CjuMmi7hbrFwU6I2SKIsIPwSSsuNd9L93SImWiwQLO0UuCTVv5s1w+Dj0x0/PjA52WCoi+MyLrkJvgHkuCsK3M+/PzcqfegOlES8QFRzPvANW3qebn3/6uE8U1hrc1AAouEpYPvMqreskCFReYYbUlagxB7AUkiENn3IbMCSfmtrPBauRJhmhRB+CYRhOvI5GzLxG8qSj8BnJpVCi1CYkEWVJctz9cxHynLxtyFLkDcNc24yBxBRqEFxVpFaOjb2VDcDKkex+tIkdo85vH4VnbHcvZHGMOKc8E1BLkWOl4IAYdQUS3icevyA65r6C3N0WLRWER6FdnVYeX0YwfEEwyfHzZRzTjiOAyFMeUlzGMznykL6x0eRtxZwQqEIX1UUsQ9fXwMQijSqkjioyjPiyouIj3YH1PVL0HNW00CPJJJLtnewkw/LkYcuFRBmFckA6Azj9ga3O/IUmmn92iZ+t3fTBu4EZ8U0INtgnNZY5XBQYMJPYCwwA8hRlqpEGimQrEYPBMPNyihFvHQpcoobqDcpSLWpw2iHYxYdw2sLVoa4wt9f3bxhMDh8PO/68QhLlGsu0RjlcglvBtRTU+RXid6FvYQhJuCNdhB1J/SptxxtEcMRg3/8ZWWtRwPzZJ40k5x+QCbDZI1fkq4kEjGNJCrwx/U71geIVFJ+Sb3jOi8+N0gQY7c7/RwU/KgD6Cpm/gEI2hxqvMNINtOmdktmTWFFSr4mUQj7wAoTybslIWWIJCQgIbw3yIlLsbZ/vMSrgFXynvI3Cf4EzXNDRBmT5tBBaC3bfa/jteUOTNziVL7zlhXKLr0Loo2t4vQjnCxvRoj0yno+ju+FryId4dBe+GtOzBcesLDHv4B/SrYx0B6yNuEUskwQN1ualDIxHJp8WhDs8wzCO8CmSNpkDfb8FFEOUrqCJDrAFsKQgql7i0q7pGsltz9t5yFetMGc+H7nMkMLyNymaukX3EtWtJJ1LNB53kYTrR8KcXTVZ6qI4DNATqOHFl520ferbs080HLG92o/ISsX6YuXfPnZSojI1MsBrVNetmrJtNPMo2VY6MgLQ8FXADyr7kW2HHTa02LDF7AfKzc7Au1v0tqGznfiNnG3U28bONu5tsbPFvW3ibBNjgymNJSX8CYTtlsZeCkrFHhf3Pf7C5J6BnMCJpweW9dP7lxajRMFNq2HQayEd9qvFoti+ANreNujdV1wukMJFhxUifzCPVtzGfF+tpqvVJL7zw3l07UeL8Z0/j6ahHy+v76bz5Xi0WMb/dEJ3P3tv/gUAAP//AwBQSwMEFAAGAAgAAAAhAKvjju6GAQAAEQMAABEACAFkb2NQcm9wcy9jb3JlLnhtbCCiBAEooAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIySUW+CMBSF35fsP5C+Y0EztxDAZFt8monJXLbsrbYX7IS2aavIv18BwWF82Nu9ved+HE4bL05l4R1BGy5FgsJJgDwQVDIu8gR9bJb+E/KMJYKRQgpIUA0GLdL7u5iqiEoNay0VaMvBeI4kTERVgnbWqghjQ3dQEjNxCuGGmdQlsa7VOVaE7kkOeBoEc1yCJYxYghugrwYiOiMZHZDqoIsWwCiGAkoQ1uBwEuKL1oIuzc2FdvJHWXJbK7gp7YeD+mT4IKyqalLNWqnzH+Kv1dt7+6s+F01WFFAaMxpZbgtIY3wpXWUO2x+gtjseGldTDcRKnTJJTz7jWeYD4+6gFfbDJvY91JXUzDjEqHMyBoZqrqy7zO4DowOnLoixK3e7GQf2XKdrsi2k58yTLBOgW+CVpNnScOTNA0nDVjG08Tntzh4wz6UUdZn2k8/Zy+tmidJpMJ37QegHj5twHj3MoyD4bhyO9i/A8mzg/8THMbEHtP6pg+dS111iV93oEae/AAAA//8DAFBLAwQUAAYACAAAACEAC+v6E+4BAAB6BgAAEgAAAHdvcmQvZm9udFRhYmxlLnhtbNyTy46bMBSG95X6Dpb3EwwJmRQNGfUykSpVXYymD+AYA1Z9QT5OSN6+tiE0ajTS0EUXZWHs//h8PufHPDyelERHbkEYXeJ0QTDimplK6KbEP152dxuMwFFdUWk0L/GZA37cvn/30Be10Q6Qz9dQKFbi1rmuSBJgLVcUFqbj2gdrYxV1fmmbRFH789DdMaM66sReSOHOSUbIGo8Y+xaKqWvB+BfDDoprF/MTy6UnGg2t6OBC699C642tOmsYB/A9KznwFBV6wqSrG5ASzBowtVv4ZsaKIsqnpyTOlPwNyOcBshvAmvHTPMZmZCQ+85ojqnmc9cQR1RXn74q5AkDlqnYWJbv4moRc6mhLob0m8nlF5RPurIJHihVfG20s3UtP8l8d+Q+HIjiMvv/wilN+inpoAW/HXwH1habKZ36mUuytiIGOagM89bEjlSX2PexITkIvGVmRZRhxEjayllrgATJsJINcUyXk+aJCLwCGQCccay/6kVoRqh5CIBofOMCelPiJEJJ93O3woKS+uqCs7j+NShbOis+HUVlOCgkKi5y4TAcOi5xpjz8zGRy4ceJFKA7oO+/Rs1FUv+JIRtbeidz7EZxZznLERu5sR57+dOR+k/8TR8a7gb6JpnWv3pBwL/7TGzJOYPsLAAD//wMAUEsDBBQABgAIAAAAIQDvCilOTgEAAH4DAAAUAAAAd29yZC93ZWJTZXR0aW5ncy54bWyc019rwjAQAPD3wb5DybumyhQpVmEMx17GYNsHiOnVhiW5kour7tPv2qlz+GL3kv/34y4h8+XO2eQTAhn0uRgNU5GA11gYv8nF+9tqMBMJReULZdFDLvZAYrm4vZk3WQPrV4iRT1LCiqfM6VxUMdaZlKQrcIqGWIPnzRKDU5GnYSOdCh/beqDR1SqatbEm7uU4TafiwIRrFCxLo+EB9daBj128DGBZRE+VqemoNddoDYaiDqiBiOtx9sdzyvgTM7q7gJzRAQnLOORiDhl1FIeP0m7k7C8w6QeML4Cphl0/Y3YwJEeeO6bo50xPjinOnP8lcwZQEYuqlzI+3qtsY1VUlaLqXIR+SU1O3N61d+R09rTxGNTassSvnvDDJR3ctlx/23VD2HXrbQliwR8C62ic+YIVhvuADUGQ7bKyFpuX50eeyD+/ZvENAAD//wMAUEsDBBQABgAIAAAAIQAp8JFHkgsAAP1yAAAPAAAAd29yZC9zdHlsZXMueG1svJ1dd9u4EYbve07/A4+u2gtH/nbis949jhPXPrWz3pXTXEMkJKEGCRUkY7u/vgBISZSHoDjg1DeJRWkegHjxDjH8kH757SWV0U+uc6Gyi9HBh/1RxLNYJSKbX4y+P17vfRxFecGyhEmV8YvRK89Hv/3617/88nyeF6+S55EBZPl5Gl+MFkWxPB+P83jBU5Z/UEuemTdnSqesMC/1fJwy/VQu92KVLlkhpkKK4nV8uL9/Oqoxug9FzWYi5l9UXKY8K1z8WHNpiCrLF2KZr2jPfWjPSidLrWKe52anU1nxUiayNebgGIBSEWuVq1nxwexM3SOHMuEH++6vVG4AJzjAIQCcxvwFx/hYM8YmsskRCY5zuuaIpMEJ60wDkCdFskBRDlfjOraxrGALli+aRI7r1Mka95raMUrj89t5pjSbSkMyqkdGuMiB7b9m/+1/7k/+4rbbXRj9aryQqPgLn7FSFrl9qR90/bJ+5f67VlmRR8/nLI+FeDQdNK2kwjR4c5nlYmTe4SwvLnPBWt9c2D9a34nzorH5s0jEaGxbfOI6M2//ZPJidFhtyv+73nC82nJlO7W1TbJsvtrG872ru2bnzKZs7/vEbpqapi5GTO9NLl3gwfG5FHNWlNokBvvKEar8oZMrs//8pSiZtB8e1wNT/d8YruX6VfWpN2NrfG5cP6mSj3mXz+5U/MSTSWHeuBjt236Zjd9vH7RQ2iSYi9GnT/XGCU/FjUgSnjU+mC1Ewn8sePY958lm+x/XLknUG2JVZubvo7NTp7fMk68vMV/alGPezZgd/W82QNpPl2LTuAv/zwp2UA9wW/yCM5t3o4O3CNd9FOLQRuSNvW1nlm/23X0K1dDRezV0/F4NnbxXQ6fv1dDZezX08b0acpj/Z0MiS0yKd5+HzQDqLo7HjWiOx2xojsdLaI7HKmiOxwlojmeiozmeeYzmeKYpglOo2DcLG5P9yDPbu7m7jxFh3N2HhDDu7iNAGHd3wg/j7s7vYdzd6TyMuzt7h3F3J2s8t1pqRbfGZlkx2GUzpYpMFTyyy9PBNJYZlitGaXj2oMc1yU4SYKrMVh+IB9Ni5l7vniHOpOHH88LWdJGaRTMxt8XJ4I7z7CeXaskjliSGRwjU3JRPnhEJmdOaz7jmWcwpJzYdVIqMR1mZTgnm5pLNyVg8S4iHb0UkSQrrCc3KYmFNIggmdcpirYZ3TTGy/HAn8uFjZSHR51JKTsT6RjPFHGt4beAww0sDhxleGTjM8MKgoRnVENU0opGqaUQDVtOIxq2an1TjVtOIxq2mEY1bTRs+bo+ikC7FN1cdB/3P3V1JZS8fDO7HRMwzd/50MKk+Zxo9MM3mmi0XkT3/3I5t7jO2nc8qeY0eKY5paxLVut5NEXvWWWTl8AHdolGZa80jsteaR2SwNW+4xe7NMtku0G5o6plJOS1aTetIvUw7YbKsFrTD3caK4TNsY4BroXMyG7RjCWbwN7uctXJSZL5NL4d3bMMabqu3WYm0ezWSoJdSxU80afjmdcm1KcueBpOulZTqmSd0xEmhVTXXmpY/dJL0svzXdLlguXC10hai/6F+deNBdM+Wg3foQTKR0ej2dS9lQkZ0K4ibx/u76FEtbZlpB4YG+FkVhUrJmPWZwL/94NO/03Tw0hTB2SvR3l4SnR5ysCtBcJCpSCohIpllpsgEyTHU8f7JX6eK6YSG9qB5da9PwYmIE5Yuq0UHgbdMXnw2+YdgNeR4/2Ja2PNCVKZ6JIE1Thvm5fTfPB6e6r6piOTM0O9l4c4/uqWui6bDDV8mbOGGLxGcmubwYOcvwc5u4Ybv7BaOamevJMtz4b2EGsyj2t0Vj3p/hxd/NU9JpWelpBvAFZBsBFdAsiFUskyznHKPHY9whx2Pen8Jp4zjEZySc7x/aJGQieFgVEo4GJUMDkalgYORCjD8Dp0GbPhtOg3Y8Ht1KhjREqABo5pnpId/oqs8DRjVPHMwqnnmYFTzzMGo5tnRl4jPZmYRTHeIaSCp5lwDSXegyQqeLpVm+pUI+VXyOSM4QVrRHrSa2YdAVFbdxE2AtOeoJeFiu8JRifyDT8m6ZlmU/SI4I8qkVIro3NrmgOMit+9d2xXmntkY3IUHyWK+UDLh2rNP/lhTL0+WLK5P04PLfb1Oe96J+aKIJov12f4m5nR/Z+SqYN8K291g25if1g+ztIbd80SU6aqj8GGK06P+wW5GbwWvHpDpCN6sJLYiT3pGwjZPd0duVslbkWc9I2GbH3tGOp9uRXb54QvTT60T4axr/qxrPM/kO+uaRevg1ma7JtI6sm0KnnXNoi2rRJdxbK8WQHX6ecYf3888/niMi/wUjJ38lN6+8iO6DPYn/ynskR2TNF1767snQN53i+hemfOPUlXn7bcuOPV/qOvWLJyynEetnKP+F662sox/HHunGz+id97xI3onID+iVybyhqNSkp/SOzf5Eb2TlB+BzlbwiIDLVjAel61gfEi2gpSQbDVgFeBH9F4O+BFoo0IE2qgDVgp+BMqoIDzIqJCCNipEoI0KEWijwgUYzqgwHmdUGB9iVEgJMSqkoI0KEWijQgTaqBCBNipEoI0auLb3hgcZFVLQRoUItFEhAm1Ut14cYFQYjzMqjA8xKqSEGBVS0EaFCLRRIQJtVIhAGxUi0EaFCJRRQXiQUSEFbVSIQBsVItBGrR41DDcqjMcZFcaHGBVSQowKKWijQgTaqBCBNipEoI0KEWijQgTKqCA8yKiQgjYqRKCNChFoo7qLhQOMCuNxRoXxIUaFlBCjQgraqBCBNipEoI0KEWijQgTaqBCBMioIDzIqpKCNChFoo0JE1/ysL1H6brM/wJ/19N6x3//SVd2pP5uPcjdRR/1Rq175Wf2fRfis1FPU+uDhkas3+kHEVArlTlF7Lqs3ue6WCNSFz9+vup/wadIHfulS/SyEu2YK4Md9I8E5leOuKd+MBEXecddMb0aCVedxV/ZtRoLD4HFX0nW+XN2UYg5HILgrzTSCDzzhXdm6EQ6HuCtHNwLhCHdl5kYgHOCufNwIPIlscn4bfdJznE7X95cCQtd0bBDO/ISuaQm1WqVjaIy+ovkJfdXzE/rK6Ceg9PRi8ML6UWiF/agwqaHNsFKHG9VPwEoNCUFSA0y41BAVLDVEhUkNEyNWakjASh2enP2EIKkBJlxqiAqWGqLCpIaHMqzUkICVGhKwUg88IHsx4VJDVLDUEBUmNVzcYaWGBKzUkICVGhKCpAaYcKkhKlhqiAqTGlTJaKkhASs1JGClhoQgqQEmXGqICpYaorqkdmdRtqRGKdwIxy3CGoG4A3IjEJecG4EB1VIjOrBaahACqyWo1UpzXLXUFM1P6Kuen9BXRj8BpacXgxfWj0Ir7EeFSY2rltqkDjeqn4CVGlcteaXGVUudUuOqpU6pcdWSX2pctdQmNa5aapM6PDn7CUFS46qlTqlx1VKn1LhqyS81rlpqkxpXLbVJjauW2qQeeED2YsKlxlVLnVLjqiW/1LhqqU1qXLXUJjWuWmqTGlcteaXGVUudUuOqpU6pcdWSX2pctdQmNa5aapMaVy21SY2rlrxS46qlTqlx1VKn1Lhq6d6ECIKvgJqkTBcR3ffF3bB8UbDhX074PdM8V/InTyLaXb1D7eX4eevnryzb/Qqf+Xxhxsx+A3rjcaWk+gbYGug+eJusf6bKBtueRPXvfNWbXYfry7VViy4QNhUvTFtx/d1VnqauS9NXnvCl1mymltr8aQPeNu35qlrXlc0UXH26HtTNiFWf2xqvzp4Xdsp39NpagmVdo1S5xtfBT3Ua2NVD05+prH4bzvxxmyUG8Fz/YFjV0+SFVSjz/hWX8p5Vn1ZL/0clnxXVuwf77ksL3rw/rb5/zxuvXaL2Asbbnale1r/j5hnv6hv56zsIPGM+EZk06Yi1DLi7oWXoWG96t/or//V/AAAA//8DAFBLAwQUAAYACAAAACEAEmQ8ReQBAAAKBAAAEAAIAWRvY1Byb3BzL2FwcC54bWwgogQBKKAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcU8tu2zAQvBfoPwi8x5SDIigMWkHroMihaQxYSc4bamUTpUiCXBtx/6lf0R/rUqpVuc0pOs0MqdHsQ+r6pbPFAWMy3i3FfFaKAp32jXHbpXiov1x8FEUicA1Y73ApjpjEdfX+nVpHHzCSwVSwhUtLsSMKCymT3mEHacbHjk9aHzsgpnErfdsajTde7zt0JC/L8kriC6FrsLkIo6EYHBcHeqtp43XOlx7rY2C/StXYBQuE1bf8pp01njolR1XVnsDWpsNqzvJI1Bq2mLI2APXkY5OqUskBqNUOImji/mVxwtSnEKzRQNzX6s7o6JNvqbjvwxb5bSWnVxQXsEG9j4aO2WpK1VfjsP/AADhVhG2EsOvFCVMbDRZXXHrVgk2o5F9B3SLksa7B5HwHWhxQk49FMj94sJeieIaEuWFLcYBowJEYrg2kxzYkilX96yftrVdyVHo4vTjF5kPu4ADOL/akT8H4PF9tyGK6b7k6eiXufBq3zzCEncSZJjt94x/XO3A813wwopXvAjhuuhwRd/17egi1v8m78qex5+JkEZ4M7TYB9DCxV3W1YRUbnvE4plFQt1xStOz+mevLbTnnI01s7bbYnCz+P8g7+Dj82tX8alby0y/dSePVGf+56jcAAAD//wMAUEsBAi0AFAAGAAgAAAAhAN+k0mxaAQAAIAUAABMAAAAAAAAAAAAAAAAAAAAAAFtDb250ZW50X1R5cGVzXS54bWxQSwECLQAUAAYACAAAACEAHpEat+8AAABOAgAACwAAAAAAAAAAAAAAAACTAwAAX3JlbHMvLnJlbHNQSwECLQAUAAYACAAAACEA1mSzUfQAAAAxAwAAHAAAAAAAAAAAAAAAAACzBgAAd29yZC9fcmVscy9kb2N1bWVudC54bWwucmVsc1BLAQItABQABgAIAAAAIQBEo2XxswIAAM0KAAARAAAAAAAAAAAAAAAAAOkIAAB3b3JkL2RvY3VtZW50LnhtbFBLAQItABQABgAIAAAAIQCnJZ7y2gYAAMsgAAAVAAAAAAAAAAAAAAAAAMsLAAB3b3JkL3RoZW1lL3RoZW1lMS54bWxQSwECLQAUAAYACAAAACEAnL1BE94DAAA8CwAAEQAAAAAAAAAAAAAAAADYEgAAd29yZC9zZXR0aW5ncy54bWxQSwECLQAUAAYACAAAACEAq+OO7oYBAAARAwAAEQAAAAAAAAAAAAAAAADlFgAAZG9jUHJvcHMvY29yZS54bWxQSwECLQAUAAYACAAAACEAC+v6E+4BAAB6BgAAEgAAAAAAAAAAAAAAAACiGQAAd29yZC9mb250VGFibGUueG1sUEsBAi0AFAAGAAgAAAAhAO8KKU5OAQAAfgMAABQAAAAAAAAAAAAAAAAAwBsAAHdvcmQvd2ViU2V0dGluZ3MueG1sUEsBAi0AFAAGAAgAAAAhACnwkUeSCwAA/XIAAA8AAAAAAAAAAAAAAAAAQB0AAHdvcmQvc3R5bGVzLnhtbFBLAQItABQABgAIAAAAIQASZDxF5AEAAAoEAAAQAAAAAAAAAAAAAAAAAP8oAABkb2NQcm9wcy9hcHAueG1sUEsFBgAAAAALAAsAwQIAABksAAAAAA==`;
|
|
@@ -2982,6 +3481,6 @@ function isValidDocxFile(file) {
|
|
|
2982
3481
|
return validTypes.includes(file.type) || file.name.endsWith(".docx");
|
|
2983
3482
|
}
|
|
2984
3483
|
|
|
2985
|
-
export { CSS_PREFIX, DEFAULT_AUTHOR, DEFAULT_SUPERDOC_USER, DocxDiffEditor, StructuralChangesPane, alignDocuments, createTrackDeleteMark, createTrackFormatMark, createTrackInsertMark, DocxDiffEditor_default as default, detectContentType, diffDocuments, diffImages, diffLists, diffTables, extractEnrichedChanges, extractEnrichedChangesWithStructural, generateFingerprint, generateStructuralChangeSummary, getBlankTemplateBlob, getBlankTemplateFile, isAtomicNode, isImage, isList, isProseMirrorJSON, isTable, isValidDocxFile, mergeDocuments, parseDocxFile, processStructuralChanges };
|
|
3484
|
+
export { CSS_PREFIX, DEFAULT_AUTHOR, DEFAULT_SUPERDOC_USER, DocxDiffEditor, StructuralChangesPane, alignDocuments, createTrackDeleteMark, createTrackFormatMark, createTrackInsertMark, DocxDiffEditor_default as default, detectContentType, diffDocuments, diffImages, diffLists, diffTables, extractEnrichedChanges, extractEnrichedChangesWithStructural, generateFingerprint, generateStructuralChangeSummary, getBlankTemplateBlob, getBlankTemplateFile, isAtomicNode, isImage, isList, isProseMirrorJSON, isTable, isValidDocxFile, mergeDocuments, parseDocxFile, parseHtmlToJson, processStructuralChanges };
|
|
2986
3485
|
//# sourceMappingURL=index.mjs.map
|
|
2987
3486
|
//# sourceMappingURL=index.mjs.map
|