@manuscripts/track-changes-plugin 1.7.2 → 1.7.3-LEAN-2832-v4
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/cjs/ChangeSet.js +154 -0
- package/dist/cjs/actions.js +23 -0
- package/dist/cjs/change-steps/diffChangeSteps.js +63 -0
- package/dist/cjs/change-steps/matchInserted.js +70 -0
- package/dist/cjs/change-steps/processChangeSteps.js +142 -0
- package/dist/cjs/changes/applyChanges.js +85 -0
- package/dist/cjs/changes/findChanges.js +72 -0
- package/dist/cjs/changes/fixInconsistentChanges.js +21 -0
- package/dist/cjs/changes/updateChangeAttrs.js +65 -0
- package/dist/cjs/commands.js +47 -0
- package/dist/cjs/compute/nodeHelpers.js +73 -0
- package/dist/cjs/compute/setFragmentAsInserted.js +53 -0
- package/dist/cjs/compute/splitSliceIntoMergedParts.js +55 -0
- package/dist/cjs/index.js +41 -0
- package/dist/cjs/mutate/deleteAndMergeSplitNodes.js +99 -0
- package/dist/cjs/mutate/deleteNode.js +41 -0
- package/dist/cjs/mutate/deleteText.js +29 -0
- package/dist/cjs/mutate/mergeNode.js +21 -0
- package/dist/cjs/mutate/mergeTrackedMarks.js +25 -0
- package/dist/cjs/plugin.js +125 -0
- package/dist/cjs/steps/trackReplaceAroundStep.js +72 -0
- package/dist/cjs/steps/trackReplaceStep.js +81 -0
- package/dist/cjs/steps/trackTransaction.js +88 -0
- package/dist/cjs/types/change.js +15 -0
- package/dist/cjs/types/pm.js +2 -0
- package/dist/cjs/types/step.js +2 -0
- package/dist/cjs/types/track.js +9 -0
- package/dist/cjs/utils/logger.js +43 -0
- package/dist/cjs/utils/track-utils.js +28 -0
- package/dist/cjs/utils/uuidv4.js +10 -0
- package/dist/es/ChangeSet.js +150 -0
- package/dist/es/actions.js +17 -0
- package/dist/es/change-steps/diffChangeSteps.js +59 -0
- package/dist/es/change-steps/matchInserted.js +66 -0
- package/dist/es/change-steps/processChangeSteps.js +115 -0
- package/dist/es/changes/applyChanges.js +81 -0
- package/dist/es/changes/findChanges.js +68 -0
- package/dist/es/changes/fixInconsistentChanges.js +17 -0
- package/dist/es/changes/updateChangeAttrs.js +60 -0
- package/dist/es/commands.js +39 -0
- package/dist/es/compute/nodeHelpers.js +63 -0
- package/dist/es/compute/setFragmentAsInserted.js +49 -0
- package/dist/es/compute/splitSliceIntoMergedParts.js +51 -0
- package/dist/es/index.js +7 -0
- package/dist/es/mutate/deleteAndMergeSplitNodes.js +72 -0
- package/dist/es/mutate/deleteNode.js +36 -0
- package/dist/es/mutate/deleteText.js +25 -0
- package/dist/es/mutate/mergeNode.js +17 -0
- package/dist/es/mutate/mergeTrackedMarks.js +21 -0
- package/dist/es/plugin.js +121 -0
- package/dist/es/steps/trackReplaceAroundStep.js +45 -0
- package/dist/es/steps/trackReplaceStep.js +54 -0
- package/dist/es/steps/trackTransaction.js +84 -0
- package/dist/es/types/change.js +12 -0
- package/dist/es/types/pm.js +1 -0
- package/dist/es/types/step.js +1 -0
- package/dist/es/types/track.js +6 -0
- package/dist/es/utils/logger.js +36 -0
- package/dist/es/utils/track-utils.js +22 -0
- package/dist/es/utils/uuidv4.js +6 -0
- package/dist/types/ChangeSet.d.ts +28 -0
- package/dist/{actions.d.ts → types/actions.d.ts} +27 -60
- package/dist/{change-steps → types/change-steps}/diffChangeSteps.d.ts +2 -2
- package/dist/types/change-steps/matchInserted.d.ts +3 -0
- package/dist/types/change-steps/processChangeSteps.d.ts +6 -0
- package/dist/types/changes/applyChanges.d.ts +5 -0
- package/dist/types/changes/findChanges.d.ts +3 -0
- package/dist/types/changes/fixInconsistentChanges.d.ts +4 -0
- package/dist/types/changes/updateChangeAttrs.d.ts +6 -0
- package/dist/types/commands.d.ts +8 -0
- package/dist/{compute → types/compute}/nodeHelpers.d.ts +13 -28
- package/dist/types/compute/setFragmentAsInserted.d.ts +3 -0
- package/dist/types/compute/splitSliceIntoMergedParts.d.ts +13 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/mutate/deleteAndMergeSplitNodes.d.ts +13 -0
- package/dist/types/mutate/deleteNode.d.ts +5 -0
- package/dist/types/mutate/deleteText.d.ts +4 -0
- package/dist/types/mutate/mergeNode.d.ts +3 -0
- package/dist/types/mutate/mergeTrackedMarks.d.ts +3 -0
- package/dist/types/plugin.d.ts +4 -0
- package/dist/{steps → types/steps}/trackReplaceAroundStep.d.ts +5 -5
- package/dist/types/steps/trackReplaceStep.d.ts +6 -0
- package/dist/types/steps/trackTransaction.d.ts +2 -0
- package/dist/types/types/change.d.ts +62 -0
- package/dist/types/types/pm.d.ts +12 -0
- package/dist/types/{step.d.ts → types/step.d.ts} +38 -53
- package/dist/types/types/track.d.ts +30 -0
- package/dist/types/utils/logger.d.ts +8 -0
- package/dist/{utils → types/utils}/track-utils.d.ts +4 -4
- package/dist/types/utils/uuidv4.d.ts +1 -0
- package/package.json +41 -40
- package/LICENSE +0 -201
- package/dist/ChangeSet.d.ts +0 -71
- package/dist/change-steps/matchInserted.d.ts +0 -13
- package/dist/change-steps/processChangeSteps.d.ts +0 -21
- package/dist/changes/applyChanges.d.ts +0 -28
- package/dist/changes/findChanges.d.ts +0 -27
- package/dist/changes/fixInconsistentChanges.d.ts +0 -29
- package/dist/changes/updateChangeAttrs.d.ts +0 -21
- package/dist/commands.d.ts +0 -47
- package/dist/compute/setFragmentAsInserted.d.ts +0 -18
- package/dist/compute/splitSliceIntoMergedParts.d.ts +0 -41
- package/dist/index.cjs +0 -2026
- package/dist/index.d.ts +0 -22
- package/dist/index.js +0 -2013
- package/dist/mutate/deleteAndMergeSplitNodes.d.ts +0 -53
- package/dist/mutate/deleteNode.d.ts +0 -36
- package/dist/mutate/deleteText.d.ts +0 -33
- package/dist/mutate/mergeNode.d.ts +0 -25
- package/dist/mutate/mergeTrackedMarks.d.ts +0 -29
- package/dist/plugin.d.ts +0 -25
- package/dist/steps/trackReplaceStep.d.ts +0 -21
- package/dist/steps/trackTransaction.d.ts +0 -17
- package/dist/types/change.d.ts +0 -76
- package/dist/types/pm.d.ts +0 -27
- package/dist/types/track.d.ts +0 -45
- package/dist/utils/logger.d.ts +0 -27
- package/dist/utils/uuidv4.d.ts +0 -16
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Fragment, Slice } from 'prosemirror-model';
|
|
2
|
+
import { log } from '../utils/logger';
|
|
3
|
+
import { matchInserted } from './matchInserted';
|
|
4
|
+
function cutFragment(matched, deleted, content) {
|
|
5
|
+
const newContent = [];
|
|
6
|
+
for (let i = 0; matched <= deleted && i < content.childCount; i += 1) {
|
|
7
|
+
const child = content.child(i);
|
|
8
|
+
if (!child.isText && child.content.size > 0) {
|
|
9
|
+
const cut = cutFragment(matched + 1, deleted, child.content);
|
|
10
|
+
matched = cut[0];
|
|
11
|
+
newContent.push(...cut[1].content);
|
|
12
|
+
}
|
|
13
|
+
else if (child.isText && matched + child.nodeSize > deleted) {
|
|
14
|
+
if (deleted - matched > 0) {
|
|
15
|
+
newContent.push(child.cut(deleted - matched));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
newContent.push(child);
|
|
19
|
+
}
|
|
20
|
+
matched = deleted + 1;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
matched += child.nodeSize;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return [matched, Fragment.fromArray(newContent)];
|
|
27
|
+
}
|
|
28
|
+
export function diffChangeSteps(deleted, inserted) {
|
|
29
|
+
const updated = [];
|
|
30
|
+
let updatedDeleted = [...deleted];
|
|
31
|
+
inserted.forEach((ins) => {
|
|
32
|
+
log.info('DIFF ins ', ins);
|
|
33
|
+
if (ins.sliceWasSplit) {
|
|
34
|
+
updated.push(ins);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const deleteStart = updatedDeleted.reduce((acc, cur) => {
|
|
38
|
+
if (cur.type === 'delete-node') {
|
|
39
|
+
return Math.min(acc, cur.pos);
|
|
40
|
+
}
|
|
41
|
+
else if (cur.type === 'delete-text') {
|
|
42
|
+
return Math.min(acc, cur.from);
|
|
43
|
+
}
|
|
44
|
+
return acc;
|
|
45
|
+
}, Number.MAX_SAFE_INTEGER);
|
|
46
|
+
const [matchedDeleted, updatedDel] = matchInserted(deleteStart, updatedDeleted, ins.slice.content);
|
|
47
|
+
if (matchedDeleted === deleteStart) {
|
|
48
|
+
updated.push(ins);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
updatedDeleted = updatedDel;
|
|
52
|
+
const [_, newInserted] = cutFragment(0, matchedDeleted - deleteStart, ins.slice.content);
|
|
53
|
+
if (newInserted.size > 0) {
|
|
54
|
+
updated.push(Object.assign(Object.assign({}, ins), { slice: new Slice(newInserted, ins.slice.openStart, ins.slice.openEnd) }));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
log.info('FINISH DIFF: ', [...updatedDeleted, ...updated]);
|
|
58
|
+
return [...updatedDeleted, ...updated];
|
|
59
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
13
|
+
const { pos, from, to, node: delNode } = adjDeleted;
|
|
14
|
+
let j = offset, d = from - pos, maxSteps = to - Math.max(pos, from);
|
|
15
|
+
for (; maxSteps !== j && insNode.text[j] !== undefined && insNode.text[j] === delNode.text[d]; j += 1, d += 1) {
|
|
16
|
+
matchedDeleted += 1;
|
|
17
|
+
}
|
|
18
|
+
deleted = deleted.filter((d) => d !== adjDeleted);
|
|
19
|
+
if (maxSteps !== j) {
|
|
20
|
+
deleted.push({
|
|
21
|
+
pos,
|
|
22
|
+
from: from + j - offset,
|
|
23
|
+
to,
|
|
24
|
+
type: 'delete-text',
|
|
25
|
+
node: delNode,
|
|
26
|
+
});
|
|
27
|
+
return [matchedDeleted, deleted];
|
|
28
|
+
}
|
|
29
|
+
const nextTextDelete = deleted.find((d) => d.type === 'delete-text' && d.pos === to);
|
|
30
|
+
if (nextTextDelete) {
|
|
31
|
+
return matchText(nextTextDelete, insNode, j, matchedDeleted, deleted);
|
|
32
|
+
}
|
|
33
|
+
return [matchedDeleted, deleted];
|
|
34
|
+
}
|
|
35
|
+
export function matchInserted(matchedDeleted, deleted, inserted) {
|
|
36
|
+
var _a;
|
|
37
|
+
let matched = [matchedDeleted, deleted];
|
|
38
|
+
for (let i = 0;; i += 1) {
|
|
39
|
+
if (inserted.childCount === i) {
|
|
40
|
+
return matched;
|
|
41
|
+
}
|
|
42
|
+
const insNode = inserted.child(i);
|
|
43
|
+
const adjDeleted = matched[1].find((d) => (d.type === 'delete-text' && Math.max(d.pos, d.from) === matched[0]) ||
|
|
44
|
+
(d.type === 'delete-node' && d.pos === matched[0]));
|
|
45
|
+
if (insNode.type !== ((_a = adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
46
|
+
return matched;
|
|
47
|
+
}
|
|
48
|
+
else if (insNode.isText && (adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node)) {
|
|
49
|
+
matched = matchText(adjDeleted, insNode, 0, matched[0], matched[1]);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
else if (insNode.content.size > 0 || (adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node.content.size) > 0) {
|
|
53
|
+
matched = matchInserted(matched[0] + 1, matched[1].filter((d) => d !== adjDeleted), insNode.content);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
matched = [matched[0] + insNode.nodeSize, matched[1].filter((d) => d !== adjDeleted)];
|
|
57
|
+
}
|
|
58
|
+
const _b = insNode.attrs || {}, { dataTracked } = _b, newAttrs = __rest(_b, ["dataTracked"]);
|
|
59
|
+
matched[1].push({
|
|
60
|
+
pos: adjDeleted.pos,
|
|
61
|
+
type: 'update-node-attrs',
|
|
62
|
+
node: adjDeleted.node,
|
|
63
|
+
newAttrs,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { Mapping, ReplaceStep } from 'prosemirror-transform';
|
|
13
|
+
import { addTrackIdIfDoesntExist, getBlockInlineTrackedData } from '../compute/nodeHelpers';
|
|
14
|
+
import { deleteOrSetNodeDeleted } from '../mutate/deleteNode';
|
|
15
|
+
import { deleteTextIfInserted } from '../mutate/deleteText';
|
|
16
|
+
import { mergeTrackedMarks } from '../mutate/mergeTrackedMarks';
|
|
17
|
+
import { CHANGE_OPERATION, CHANGE_STATUS } from '../types/change';
|
|
18
|
+
import { log } from '../utils/logger';
|
|
19
|
+
import * as trackUtils from '../utils/track-utils';
|
|
20
|
+
export function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
21
|
+
const mapping = new Mapping();
|
|
22
|
+
const deleteAttrs = trackUtils.createNewDeleteAttrs(emptyAttrs);
|
|
23
|
+
let selectionPos = startPos;
|
|
24
|
+
let deletesCounter = 0;
|
|
25
|
+
let isInserted = false;
|
|
26
|
+
changes.forEach((c) => {
|
|
27
|
+
let step = newTr.steps[newTr.steps.length - 1];
|
|
28
|
+
switch (c.type) {
|
|
29
|
+
case 'delete-node':
|
|
30
|
+
deletesCounter++;
|
|
31
|
+
const trackedData = getBlockInlineTrackedData(c.node);
|
|
32
|
+
const inserted = trackedData === null || trackedData === void 0 ? void 0 : trackedData.find((d) => d.operation === CHANGE_OPERATION.insert);
|
|
33
|
+
isInserted = !!inserted || (!trackedData && isInserted);
|
|
34
|
+
if (isInserted && deletesCounter > 1) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
deleteOrSetNodeDeleted(c.node, mapping.map(c.pos), newTr, deleteAttrs);
|
|
38
|
+
const newestStep = newTr.steps[newTr.steps.length - 1];
|
|
39
|
+
if (step !== newestStep) {
|
|
40
|
+
mapping.appendMap(newestStep.getMap());
|
|
41
|
+
step = newestStep;
|
|
42
|
+
}
|
|
43
|
+
mergeTrackedMarks(mapping.map(c.pos), newTr.doc, newTr, schema);
|
|
44
|
+
break;
|
|
45
|
+
case 'delete-text':
|
|
46
|
+
const node = newTr.doc.nodeAt(mapping.map(c.pos));
|
|
47
|
+
if (!node) {
|
|
48
|
+
log.error(`processChangeSteps: no text node found for text-change`, c);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const where = deleteTextIfInserted(node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
|
|
52
|
+
mergeTrackedMarks(where, newTr.doc, newTr, schema);
|
|
53
|
+
break;
|
|
54
|
+
case 'merge-fragment':
|
|
55
|
+
let insertPos = mapping.map(c.mergePos);
|
|
56
|
+
if (c.node.isText) {
|
|
57
|
+
insertPos = deleteTextIfInserted(c.node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
|
|
58
|
+
const newestStep = newTr.steps[newTr.steps.length - 1];
|
|
59
|
+
if (step !== newestStep) {
|
|
60
|
+
mapping.appendMap(newestStep.getMap());
|
|
61
|
+
step = newestStep;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (c.fragment.size > 0) {
|
|
65
|
+
newTr.insert(insertPos, c.fragment);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case 'insert-slice':
|
|
69
|
+
const newStep = new ReplaceStep(mapping.map(c.from), mapping.map(c.to), c.slice, false);
|
|
70
|
+
const stepResult = newTr.maybeStep(newStep);
|
|
71
|
+
if (stepResult.failed) {
|
|
72
|
+
log.error(`processChangeSteps: insert-slice ReplaceStep failed "${stepResult.failed}"`, newStep);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
mergeTrackedMarks(mapping.map(c.from), newTr.doc, newTr, schema);
|
|
76
|
+
const to = mapping.map(c.to) + c.slice.size;
|
|
77
|
+
mergeTrackedMarks(mapping.map(c.to) + (to < newTr.doc.nodeSize ? c.slice.size : 0), newTr.doc, newTr, schema);
|
|
78
|
+
selectionPos = mapping.map(c.to) + c.slice.size;
|
|
79
|
+
break;
|
|
80
|
+
case 'update-node-attrs':
|
|
81
|
+
const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
|
|
82
|
+
const oldUpdate = oldDataTracked.reverse().find((d) => {
|
|
83
|
+
if (d.operation === CHANGE_OPERATION.set_node_attributes &&
|
|
84
|
+
(d.status === CHANGE_STATUS.pending || d.status === CHANGE_STATUS.rejected)) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
});
|
|
89
|
+
const lastChangeRejected = oldUpdate && oldUpdate.status === CHANGE_STATUS.rejected;
|
|
90
|
+
const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
|
|
91
|
+
const { dataTracked } = sourceAttrs, restAttrs = __rest(sourceAttrs, ["dataTracked"]);
|
|
92
|
+
const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
|
|
93
|
+
const newDataTracked = [
|
|
94
|
+
...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
|
|
95
|
+
];
|
|
96
|
+
const newUpdate = oldUpdate && oldUpdate.status !== CHANGE_STATUS.rejected
|
|
97
|
+
? Object.assign(Object.assign({}, oldUpdate), { updatedAt: emptyAttrs.updatedAt }) : addTrackIdIfDoesntExist(trackUtils.createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
|
|
98
|
+
if ((JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) ||
|
|
99
|
+
c.node.type === c.node.type.schema.nodes.citation) &&
|
|
100
|
+
!oldDataTracked.find((d) => d.operation === CHANGE_OPERATION.insert && d.status === CHANGE_STATUS.pending)) {
|
|
101
|
+
newDataTracked.push(newUpdate);
|
|
102
|
+
}
|
|
103
|
+
newTr.setNodeMarkup(mapping.map(c.pos), undefined, Object.assign(Object.assign({}, c.newAttrs), { dataTracked: newDataTracked.length > 0 ? newDataTracked : null }), c.node.marks);
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
log.error(`processChangeSteps: unknown change type`, c);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const newestStep = newTr.steps[newTr.steps.length - 1];
|
|
110
|
+
if (step !== newestStep) {
|
|
111
|
+
mapping.appendMap(newestStep.getMap());
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return [mapping, selectionPos];
|
|
115
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { Mapping } from 'prosemirror-transform';
|
|
13
|
+
import { ChangeSet } from '../ChangeSet';
|
|
14
|
+
import { deleteNode } from '../mutate/deleteNode';
|
|
15
|
+
import { mergeNode } from '../mutate/mergeNode';
|
|
16
|
+
import { CHANGE_STATUS } from '../types/change';
|
|
17
|
+
import { log } from '../utils/logger';
|
|
18
|
+
import { updateChangeChildrenAttributes } from './updateChangeAttrs';
|
|
19
|
+
function getUpdatedDataTracked(dataTracked, changeId) {
|
|
20
|
+
if (!dataTracked) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
console.log(dataTracked);
|
|
24
|
+
const newDataTracked = dataTracked.filter((c) => c.id !== changeId);
|
|
25
|
+
return newDataTracked.length ? newDataTracked : null;
|
|
26
|
+
}
|
|
27
|
+
export function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mapping()) {
|
|
28
|
+
const attrsChangesLog = new Map();
|
|
29
|
+
function addAttrLog(nodeId, changeId) {
|
|
30
|
+
const arr = attrsChangesLog.get(nodeId) || attrsChangesLog.set(nodeId, []).get(nodeId);
|
|
31
|
+
arr.push(changeId);
|
|
32
|
+
}
|
|
33
|
+
changes.forEach((change) => {
|
|
34
|
+
const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || !ChangeSet.shouldDeleteChange(change);
|
|
35
|
+
if (!node) {
|
|
36
|
+
!deleted && log.warn('no node found to update for change', change);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (change.dataTracked.status === CHANGE_STATUS.pending) {
|
|
40
|
+
if (ChangeSet.isNodeAttrChange(change)) {
|
|
41
|
+
const _a = change.newAttrs, { dataTracked } = _a, attrs = __rest(_a, ["dataTracked"]);
|
|
42
|
+
const changeLog = attrsChangesLog.get(node.attrs.id);
|
|
43
|
+
const newDataTracked = changeLog && changeLog.length
|
|
44
|
+
? dataTracked.filter((c) => !changeLog.includes(c.id))
|
|
45
|
+
: dataTracked;
|
|
46
|
+
tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, attrs), { dataTracked: newDataTracked.length ? newDataTracked : null }), node.marks);
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (ChangeSet.isTextChange(change) && noChangeNeeded) {
|
|
51
|
+
tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_insert);
|
|
52
|
+
tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_delete);
|
|
53
|
+
}
|
|
54
|
+
else if (ChangeSet.isTextChange(change)) {
|
|
55
|
+
tr.delete(from, deleteMap.map(change.to));
|
|
56
|
+
deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
|
|
57
|
+
}
|
|
58
|
+
else if (ChangeSet.isNodeChange(change) && noChangeNeeded) {
|
|
59
|
+
const attrs = Object.assign(Object.assign({}, node.attrs), { dataTracked: null });
|
|
60
|
+
tr.setNodeMarkup(from, undefined, attrs, node.marks);
|
|
61
|
+
updateChangeChildrenAttributes(change.children, tr, deleteMap);
|
|
62
|
+
}
|
|
63
|
+
else if (ChangeSet.isNodeChange(change)) {
|
|
64
|
+
const merged = mergeNode(node, from, tr);
|
|
65
|
+
if (merged === undefined) {
|
|
66
|
+
deleteNode(node, from, tr);
|
|
67
|
+
}
|
|
68
|
+
deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
|
|
69
|
+
}
|
|
70
|
+
else if (ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === CHANGE_STATUS.accepted) {
|
|
71
|
+
tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, change.newAttrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
|
|
72
|
+
addAttrLog(node.attrs.id, change.dataTracked.id);
|
|
73
|
+
}
|
|
74
|
+
else if (ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === CHANGE_STATUS.rejected) {
|
|
75
|
+
console.log('GETTING IN ---- CHANGE_STATUS.rejected');
|
|
76
|
+
tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, change.oldAttrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
|
|
77
|
+
addAttrLog(node.attrs.id, change.dataTracked.id);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return deleteMap;
|
|
81
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ChangeSet } from '../ChangeSet';
|
|
2
|
+
import { equalMarks, getNodeTrackedData } from '../compute/nodeHelpers';
|
|
3
|
+
import { CHANGE_OPERATION, } from '../types/change';
|
|
4
|
+
export function findChanges(state) {
|
|
5
|
+
const changes = [];
|
|
6
|
+
let current;
|
|
7
|
+
state.doc.descendants((node, pos) => {
|
|
8
|
+
const tracked = getNodeTrackedData(node, state.schema) || [];
|
|
9
|
+
for (let i = 0; i < tracked.length; i += 1) {
|
|
10
|
+
const dataTracked = tracked[i];
|
|
11
|
+
const id = dataTracked.id || '';
|
|
12
|
+
if (current &&
|
|
13
|
+
current.change.id === id &&
|
|
14
|
+
current.node.isText &&
|
|
15
|
+
node.isText &&
|
|
16
|
+
!equalMarks(node, current.node)) {
|
|
17
|
+
current.change.to = pos + node.nodeSize;
|
|
18
|
+
current.node = node;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
current && changes.push(current.change);
|
|
22
|
+
let change;
|
|
23
|
+
if (node.isText) {
|
|
24
|
+
change = {
|
|
25
|
+
id,
|
|
26
|
+
type: 'text-change',
|
|
27
|
+
from: pos,
|
|
28
|
+
to: pos + node.nodeSize,
|
|
29
|
+
dataTracked,
|
|
30
|
+
text: node.text,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
else if (dataTracked.operation === CHANGE_OPERATION.set_node_attributes) {
|
|
34
|
+
change = {
|
|
35
|
+
id,
|
|
36
|
+
type: 'node-attr-change',
|
|
37
|
+
from: pos,
|
|
38
|
+
to: pos + node.nodeSize,
|
|
39
|
+
dataTracked,
|
|
40
|
+
nodeType: node.type.name,
|
|
41
|
+
newAttrs: node.attrs,
|
|
42
|
+
oldAttrs: dataTracked.oldAttrs,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
change = {
|
|
47
|
+
id,
|
|
48
|
+
type: 'node-change',
|
|
49
|
+
from: pos,
|
|
50
|
+
to: pos + node.nodeSize,
|
|
51
|
+
dataTracked,
|
|
52
|
+
nodeType: node.type.name,
|
|
53
|
+
children: [],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
current = {
|
|
57
|
+
change,
|
|
58
|
+
node,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (tracked.length === 0 && current) {
|
|
62
|
+
changes.push(current.change);
|
|
63
|
+
current = undefined;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
current && changes.push(current.change);
|
|
67
|
+
return new ChangeSet(changes);
|
|
68
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CHANGE_STATUS } from '../types/change';
|
|
2
|
+
import { uuidv4 } from '../utils/uuidv4';
|
|
3
|
+
import { updateChangeAttrs } from './updateChangeAttrs';
|
|
4
|
+
export function fixInconsistentChanges(changeSet, currentUserID, newTr, schema) {
|
|
5
|
+
const iteratedIds = new Set();
|
|
6
|
+
let changed = false;
|
|
7
|
+
changeSet.invalidChanges.forEach((c) => {
|
|
8
|
+
const { id, authorID, operation, reviewedByID, status, createdAt, statusUpdateAt, updatedAt } = c.dataTracked;
|
|
9
|
+
const newAttrs = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, ((!id || iteratedIds.has(id) || id.length === 0) && { id: uuidv4() })), (!authorID && { authorID: currentUserID })), (!reviewedByID && { reviewedByID: null })), (!status && { status: CHANGE_STATUS.pending })), (!createdAt && { createdAt: Date.now() })), (!updatedAt && { updatedAt: Date.now() })), (!statusUpdateAt && { statusUpdateAt: 0 }));
|
|
10
|
+
if (Object.keys(newAttrs).length > 0) {
|
|
11
|
+
updateChangeAttrs(newTr, c, Object.assign(Object.assign({}, c.dataTracked), newAttrs), schema);
|
|
12
|
+
changed = true;
|
|
13
|
+
}
|
|
14
|
+
iteratedIds.add(newAttrs.id || id);
|
|
15
|
+
});
|
|
16
|
+
return changed;
|
|
17
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ChangeSet } from '../ChangeSet';
|
|
2
|
+
import { getBlockInlineTrackedData, getTextNodeTrackedMarkData, } from '../compute/nodeHelpers';
|
|
3
|
+
import { log } from '../utils/logger';
|
|
4
|
+
export function updateChangeAttrs(tr, change, trackedAttrs, schema) {
|
|
5
|
+
const node = tr.doc.nodeAt(change.from);
|
|
6
|
+
if (!node) {
|
|
7
|
+
log.error('updateChangeAttrs: no node at the from of change ', change);
|
|
8
|
+
return tr;
|
|
9
|
+
}
|
|
10
|
+
const { operation } = trackedAttrs;
|
|
11
|
+
const oldTrackData = change.type === 'text-change' ? getTextNodeTrackedMarkData(node, schema) : getBlockInlineTrackedData(node);
|
|
12
|
+
if (!operation) {
|
|
13
|
+
log.warn('updateChangeAttrs: unable to determine operation of change ', change);
|
|
14
|
+
}
|
|
15
|
+
else if (!oldTrackData) {
|
|
16
|
+
log.warn('updateChangeAttrs: no old dataTracked for change ', change);
|
|
17
|
+
}
|
|
18
|
+
if (change.type === 'text-change') {
|
|
19
|
+
const oldMark = node.marks.find((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete);
|
|
20
|
+
if (!oldMark) {
|
|
21
|
+
log.warn('updateChangeAttrs: no track marks for a text-change ', change);
|
|
22
|
+
return tr;
|
|
23
|
+
}
|
|
24
|
+
tr.addMark(change.from, change.to, oldMark.type.create(Object.assign(Object.assign({}, oldMark.attrs), { dataTracked: Object.assign(Object.assign({}, oldTrackData), trackedAttrs) })));
|
|
25
|
+
}
|
|
26
|
+
else if ((change.type === 'node-change' || change.type === 'node-attr-change') && !operation) {
|
|
27
|
+
tr.setNodeMarkup(change.from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: null }), node.marks);
|
|
28
|
+
}
|
|
29
|
+
else if (change.type === 'node-change' || change.type === 'node-attr-change') {
|
|
30
|
+
const trackedDataSource = getBlockInlineTrackedData(node) || [];
|
|
31
|
+
const targetDataTracked = trackedDataSource.find((t) => change.id === t.id);
|
|
32
|
+
const newDataTracked = trackedDataSource.map((oldTrack) => {
|
|
33
|
+
if (targetDataTracked) {
|
|
34
|
+
if (oldTrack.id === targetDataTracked.id) {
|
|
35
|
+
return Object.assign(Object.assign({}, oldTrack), trackedAttrs);
|
|
36
|
+
}
|
|
37
|
+
return oldTrack;
|
|
38
|
+
}
|
|
39
|
+
if (oldTrack.operation === operation) {
|
|
40
|
+
return Object.assign(Object.assign({}, oldTrack), trackedAttrs);
|
|
41
|
+
}
|
|
42
|
+
return oldTrack;
|
|
43
|
+
});
|
|
44
|
+
tr.setNodeMarkup(change.from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: newDataTracked.length === 0 ? null : newDataTracked }), node.marks);
|
|
45
|
+
}
|
|
46
|
+
return tr;
|
|
47
|
+
}
|
|
48
|
+
export function updateChangeChildrenAttributes(changes, tr, mapping) {
|
|
49
|
+
changes.forEach((c) => {
|
|
50
|
+
if (c.type === 'node-change' && !ChangeSet.shouldDeleteChange(c)) {
|
|
51
|
+
const from = mapping.map(c.from);
|
|
52
|
+
const node = tr.doc.nodeAt(from);
|
|
53
|
+
if (!node) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const attrs = Object.assign(Object.assign({}, node.attrs), { dataTracked: null });
|
|
57
|
+
tr.setNodeMarkup(from, undefined, attrs, node.marks);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { setAction, TrackChangesAction } from './actions';
|
|
2
|
+
import { trackChangesPluginKey } from './plugin';
|
|
3
|
+
import { TrackChangesStatus } from './types/track';
|
|
4
|
+
export const setTrackingStatus = (status) => (state, dispatch) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const currentStatus = (_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status;
|
|
7
|
+
if (currentStatus) {
|
|
8
|
+
let newStatus = status;
|
|
9
|
+
if (newStatus === undefined) {
|
|
10
|
+
newStatus =
|
|
11
|
+
currentStatus === TrackChangesStatus.enabled
|
|
12
|
+
? TrackChangesStatus.disabled
|
|
13
|
+
: TrackChangesStatus.enabled;
|
|
14
|
+
}
|
|
15
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.setPluginStatus, newStatus));
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
};
|
|
20
|
+
export const setChangeStatuses = (status, ids) => (state, dispatch) => {
|
|
21
|
+
dispatch &&
|
|
22
|
+
dispatch(setAction(state.tr, TrackChangesAction.setChangeStatuses, {
|
|
23
|
+
status,
|
|
24
|
+
ids,
|
|
25
|
+
}));
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
28
|
+
export const setUserID = (userID) => (state, dispatch) => {
|
|
29
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.setUserID, userID));
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
export const applyAndRemoveChanges = () => (state, dispatch) => {
|
|
33
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.applyAndRemoveChanges, true));
|
|
34
|
+
return true;
|
|
35
|
+
};
|
|
36
|
+
export const refreshChanges = () => (state, dispatch) => {
|
|
37
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.refreshChanges, true));
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CHANGE_OPERATION } from '../types/change';
|
|
2
|
+
import { log } from '../utils/logger';
|
|
3
|
+
import { uuidv4 } from '../utils/uuidv4';
|
|
4
|
+
export function addTrackIdIfDoesntExist(attrs) {
|
|
5
|
+
if (!attrs.id) {
|
|
6
|
+
return Object.assign({ id: uuidv4() }, attrs);
|
|
7
|
+
}
|
|
8
|
+
return attrs;
|
|
9
|
+
}
|
|
10
|
+
export function getTextNodeTrackedMarkData(node, schema) {
|
|
11
|
+
if (!node || !node.isText) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const marksTrackedData = [];
|
|
15
|
+
node.marks.forEach((mark) => {
|
|
16
|
+
if (mark.type === schema.marks.tracked_insert || mark.type === schema.marks.tracked_delete) {
|
|
17
|
+
const operation = mark.type === schema.marks.tracked_insert ? CHANGE_OPERATION.insert : CHANGE_OPERATION.delete;
|
|
18
|
+
marksTrackedData.push(Object.assign(Object.assign({}, mark.attrs.dataTracked), { operation }));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
if (marksTrackedData.length > 1) {
|
|
22
|
+
log.warn('inline node with more than 1 of tracked marks', marksTrackedData);
|
|
23
|
+
}
|
|
24
|
+
return marksTrackedData[0] || undefined;
|
|
25
|
+
}
|
|
26
|
+
export function getBlockInlineTrackedData(node) {
|
|
27
|
+
const { dataTracked } = node.attrs;
|
|
28
|
+
if (dataTracked && !Array.isArray(dataTracked)) {
|
|
29
|
+
return [dataTracked];
|
|
30
|
+
}
|
|
31
|
+
return dataTracked;
|
|
32
|
+
}
|
|
33
|
+
export function getNodeTrackedData(node, schema) {
|
|
34
|
+
let tracked;
|
|
35
|
+
if (node && !node.isText) {
|
|
36
|
+
tracked = getBlockInlineTrackedData(node);
|
|
37
|
+
}
|
|
38
|
+
else if (node === null || node === void 0 ? void 0 : node.isText) {
|
|
39
|
+
tracked = getTextNodeTrackedMarkData(node, schema);
|
|
40
|
+
}
|
|
41
|
+
if (tracked && !Array.isArray(tracked)) {
|
|
42
|
+
tracked = [tracked];
|
|
43
|
+
}
|
|
44
|
+
return tracked;
|
|
45
|
+
}
|
|
46
|
+
export function equalMarks(n1, n2) {
|
|
47
|
+
return (n1.marks.length === n2.marks.length &&
|
|
48
|
+
n1.marks.every((mark) => n1.marks.find((m) => m.type === mark.type)));
|
|
49
|
+
}
|
|
50
|
+
export function shouldMergeTrackedAttributes(left, right) {
|
|
51
|
+
if (!left || !right) {
|
|
52
|
+
log.warn('passed undefined dataTracked attributes to shouldMergeTrackedAttributes', {
|
|
53
|
+
left,
|
|
54
|
+
right,
|
|
55
|
+
});
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return (left.status === right.status && left.operation === right.operation && left.authorID === right.authorID);
|
|
59
|
+
}
|
|
60
|
+
export function getMergeableMarkTrackedAttrs(node, attrs, schema) {
|
|
61
|
+
const nodeAttrs = getTextNodeTrackedMarkData(node, schema);
|
|
62
|
+
return nodeAttrs && shouldMergeTrackedAttributes(nodeAttrs, attrs) ? nodeAttrs : null;
|
|
63
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Fragment } from 'prosemirror-model';
|
|
2
|
+
import { CHANGE_OPERATION } from '../types/change';
|
|
3
|
+
import { log } from '../utils/logger';
|
|
4
|
+
import { addTrackIdIfDoesntExist, equalMarks, getTextNodeTrackedMarkData } from './nodeHelpers';
|
|
5
|
+
function markInlineNodeChange(node, newTrackAttrs, schema) {
|
|
6
|
+
const filtered = node.marks.filter((m) => m.type !== schema.marks.tracked_insert && m.type !== schema.marks.tracked_delete);
|
|
7
|
+
const mark = newTrackAttrs.operation === CHANGE_OPERATION.insert
|
|
8
|
+
? schema.marks.tracked_insert
|
|
9
|
+
: schema.marks.tracked_delete;
|
|
10
|
+
const createdMark = mark.create({
|
|
11
|
+
dataTracked: addTrackIdIfDoesntExist(newTrackAttrs),
|
|
12
|
+
});
|
|
13
|
+
return node.mark(filtered.concat(createdMark));
|
|
14
|
+
}
|
|
15
|
+
function loopContentAndMergeText(content, newTrackAttrs, schema) {
|
|
16
|
+
var _a;
|
|
17
|
+
const updatedChildren = [];
|
|
18
|
+
for (let i = 0; i < content.childCount; i += 1) {
|
|
19
|
+
const recursed = recurseNodeContent(content.child(i), newTrackAttrs, schema);
|
|
20
|
+
const prev = i > 0 ? updatedChildren[i - 1] : null;
|
|
21
|
+
if ((prev === null || prev === void 0 ? void 0 : prev.isText) &&
|
|
22
|
+
recursed.isText &&
|
|
23
|
+
equalMarks(prev, recursed) &&
|
|
24
|
+
((_a = getTextNodeTrackedMarkData(prev, schema)) === null || _a === void 0 ? void 0 : _a.operation) === CHANGE_OPERATION.insert) {
|
|
25
|
+
updatedChildren.splice(i - 1, 1, schema.text('' + prev.text + recursed.text, prev.marks));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
updatedChildren.push(recursed);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return updatedChildren;
|
|
32
|
+
}
|
|
33
|
+
function recurseNodeContent(node, newTrackAttrs, schema) {
|
|
34
|
+
if (node.isText) {
|
|
35
|
+
return markInlineNodeChange(node, newTrackAttrs, schema);
|
|
36
|
+
}
|
|
37
|
+
else if (node.isBlock || node.isInline) {
|
|
38
|
+
const updatedChildren = loopContentAndMergeText(node.content, newTrackAttrs, schema);
|
|
39
|
+
return node.type.create(Object.assign(Object.assign({}, node.attrs), { dataTracked: [addTrackIdIfDoesntExist(newTrackAttrs)] }), Fragment.fromArray(updatedChildren), node.marks);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
log.error(`unhandled node type: "${node.type.name}"`, node);
|
|
43
|
+
return node;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function setFragmentAsInserted(inserted, insertAttrs, schema) {
|
|
47
|
+
const updatedInserted = loopContentAndMergeText(inserted, insertAttrs, schema);
|
|
48
|
+
return updatedInserted.length === 0 ? Fragment.empty : Fragment.fromArray(updatedInserted);
|
|
49
|
+
}
|