@atlaskit/editor-plugin-show-diff 10.1.23 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/calculate-diff/package.json +8 -0
- package/dist/cjs/entry-points/calculate-diff.js +12 -0
- package/dist/cjs/pm-plugins/calculateDiff/calculateDiffDecorations.js +132 -31
- package/dist/cjs/pm-plugins/calculateDiff/computeDiffChanges.js +112 -0
- package/dist/cjs/pm-plugins/calculateDiff/groupChangesByBlock.js +4 -2
- package/dist/cjs/pm-plugins/calculateDiff/smart/classifySmartChanges.js +841 -0
- package/dist/cjs/pm-plugins/calculateDiff/smart/helpers.js +135 -0
- package/dist/cjs/pm-plugins/calculateDiff/smart/segmentText.js +331 -0
- package/dist/cjs/pm-plugins/calculateDiff/smart/thresholds.js +46 -0
- package/dist/cjs/pm-plugins/decorations/createBlockChangedDecoration.js +24 -18
- package/dist/cjs/pm-plugins/decorations/createChangedRowDecorationWidgets.js +18 -12
- package/dist/cjs/pm-plugins/decorations/createInlineChangedDecoration.js +6 -5
- package/dist/cjs/pm-plugins/decorations/createNodeChangedDecorationWidget.js +30 -17
- package/dist/cjs/pm-plugins/decorations/decorationKeys.js +8 -5
- package/dist/cjs/pm-plugins/decorations/utils/wrapBlockNodeView.js +52 -30
- package/dist/cjs/pm-plugins/getScrollableDecorations.js +6 -6
- package/dist/cjs/pm-plugins/isExtendedEnabled.js +20 -0
- package/dist/cjs/pm-plugins/main.js +21 -16
- package/dist/es2019/entry-points/calculate-diff.js +2 -0
- package/dist/es2019/pm-plugins/calculateDiff/calculateDiffDecorations.js +119 -29
- package/dist/es2019/pm-plugins/calculateDiff/computeDiffChanges.js +94 -0
- package/dist/es2019/pm-plugins/calculateDiff/groupChangesByBlock.js +4 -3
- package/dist/es2019/pm-plugins/calculateDiff/smart/classifySmartChanges.js +689 -0
- package/dist/es2019/pm-plugins/calculateDiff/smart/helpers.js +106 -0
- package/dist/es2019/pm-plugins/calculateDiff/smart/segmentText.js +283 -0
- package/dist/es2019/pm-plugins/calculateDiff/smart/thresholds.js +45 -0
- package/dist/es2019/pm-plugins/decorations/createBlockChangedDecoration.js +24 -18
- package/dist/es2019/pm-plugins/decorations/createChangedRowDecorationWidgets.js +18 -12
- package/dist/es2019/pm-plugins/decorations/createInlineChangedDecoration.js +6 -5
- package/dist/es2019/pm-plugins/decorations/createNodeChangedDecorationWidget.js +31 -16
- package/dist/es2019/pm-plugins/decorations/decorationKeys.js +9 -5
- package/dist/es2019/pm-plugins/decorations/utils/wrapBlockNodeView.js +52 -34
- package/dist/es2019/pm-plugins/getScrollableDecorations.js +6 -6
- package/dist/es2019/pm-plugins/isExtendedEnabled.js +12 -0
- package/dist/es2019/pm-plugins/main.js +21 -16
- package/dist/esm/entry-points/calculate-diff.js +2 -0
- package/dist/esm/pm-plugins/calculateDiff/calculateDiffDecorations.js +132 -31
- package/dist/esm/pm-plugins/calculateDiff/computeDiffChanges.js +107 -0
- package/dist/esm/pm-plugins/calculateDiff/groupChangesByBlock.js +4 -3
- package/dist/esm/pm-plugins/calculateDiff/smart/classifySmartChanges.js +834 -0
- package/dist/esm/pm-plugins/calculateDiff/smart/helpers.js +128 -0
- package/dist/esm/pm-plugins/calculateDiff/smart/segmentText.js +325 -0
- package/dist/esm/pm-plugins/calculateDiff/smart/thresholds.js +39 -0
- package/dist/esm/pm-plugins/decorations/createBlockChangedDecoration.js +24 -18
- package/dist/esm/pm-plugins/decorations/createChangedRowDecorationWidgets.js +18 -12
- package/dist/esm/pm-plugins/decorations/createInlineChangedDecoration.js +6 -5
- package/dist/esm/pm-plugins/decorations/createNodeChangedDecorationWidget.js +30 -17
- package/dist/esm/pm-plugins/decorations/decorationKeys.js +9 -5
- package/dist/esm/pm-plugins/decorations/utils/wrapBlockNodeView.js +52 -30
- package/dist/esm/pm-plugins/getScrollableDecorations.js +6 -6
- package/dist/esm/pm-plugins/isExtendedEnabled.js +14 -0
- package/dist/esm/pm-plugins/main.js +21 -16
- package/dist/types/entry-points/calculate-diff.d.ts +2 -0
- package/dist/types/entry-points/show-diff-plugin-type.d.ts +1 -1
- package/dist/types/pm-plugins/calculateDiff/calculateDiffDecorations.d.ts +3 -1
- package/dist/types/pm-plugins/calculateDiff/computeDiffChanges.d.ts +46 -0
- package/dist/types/pm-plugins/calculateDiff/groupChangesByBlock.d.ts +9 -0
- package/dist/types/pm-plugins/calculateDiff/smart/classifySmartChanges.d.ts +26 -0
- package/dist/types/pm-plugins/calculateDiff/smart/helpers.d.ts +44 -0
- package/dist/types/pm-plugins/calculateDiff/smart/segmentText.d.ts +32 -0
- package/dist/types/pm-plugins/calculateDiff/smart/thresholds.d.ts +44 -0
- package/dist/types/pm-plugins/decorations/createBlockChangedDecoration.d.ts +3 -2
- package/dist/types/pm-plugins/decorations/createChangedRowDecorationWidgets.d.ts +3 -2
- package/dist/types/pm-plugins/decorations/createInlineChangedDecoration.d.ts +3 -2
- package/dist/types/pm-plugins/decorations/createNodeChangedDecorationWidget.d.ts +4 -2
- package/dist/types/pm-plugins/decorations/decorationKeys.d.ts +5 -3
- package/dist/types/pm-plugins/decorations/utils/wrapBlockNodeView.d.ts +6 -4
- package/dist/types/pm-plugins/getScrollableDecorations.d.ts +2 -1
- package/dist/types/pm-plugins/isExtendedEnabled.d.ts +11 -0
- package/dist/types/pm-plugins/main.d.ts +11 -1
- package/dist/types/showDiffPluginType.d.ts +20 -1
- package/docs/smart-diff-design.md +240 -0
- package/package.json +8 -3
|
@@ -11,10 +11,10 @@ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
|
11
11
|
var _state2 = require("@atlaskit/editor-prosemirror/state");
|
|
12
12
|
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
13
13
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
14
|
-
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
15
14
|
var _calculateDiffDecorations = require("./calculateDiff/calculateDiffDecorations");
|
|
16
15
|
var _enforceCustomStepRegisters = require("./enforceCustomStepRegisters");
|
|
17
16
|
var _getScrollableDecorations = require("./getScrollableDecorations");
|
|
17
|
+
var _isExtendedEnabled = require("./isExtendedEnabled");
|
|
18
18
|
var _NodeViewSerializer = require("./NodeViewSerializer");
|
|
19
19
|
var _scrollToDiff = require("./scrollToDiff");
|
|
20
20
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
@@ -38,7 +38,7 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
38
38
|
originalDoc: undefined,
|
|
39
39
|
decorations: _view.DecorationSet.empty,
|
|
40
40
|
isDisplayingChanges: false
|
|
41
|
-
}, (0,
|
|
41
|
+
}, (0, _isExtendedEnabled.isExtendedEnabled)() ? {
|
|
42
42
|
isInverted: false,
|
|
43
43
|
diffType: 'inline',
|
|
44
44
|
hideDeletedDiffs: false,
|
|
@@ -51,7 +51,7 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
51
51
|
var newPluginState = currentPluginState;
|
|
52
52
|
if (meta) {
|
|
53
53
|
if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'SHOW_DIFF') {
|
|
54
|
-
var _newPluginState, _newPluginState2, _newPluginState3, _newPluginState4;
|
|
54
|
+
var _newPluginState, _newPluginState2, _newPluginState3, _newPluginState4, _newPluginState5, _newPluginState6, _newPluginState7, _newPluginState8;
|
|
55
55
|
// Update the plugin state with the new metadata
|
|
56
56
|
newPluginState = _objectSpread(_objectSpread(_objectSpread({}, currentPluginState), meta), {}, {
|
|
57
57
|
isDisplayingChanges: true,
|
|
@@ -66,17 +66,19 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
66
66
|
intl: getIntl(),
|
|
67
67
|
activeIndexPos: newPluginState.activeIndexPos,
|
|
68
68
|
api: api
|
|
69
|
-
}, (0,
|
|
70
|
-
isInverted: (
|
|
71
|
-
diffType: (
|
|
72
|
-
hideDeletedDiffs: (
|
|
73
|
-
showIndicators: (
|
|
69
|
+
}, (0, _isExtendedEnabled.isExtendedEnabled)((_newPluginState = newPluginState) === null || _newPluginState === void 0 ? void 0 : _newPluginState.diffType) ? {
|
|
70
|
+
isInverted: (_newPluginState2 = newPluginState) === null || _newPluginState2 === void 0 ? void 0 : _newPluginState2.isInverted,
|
|
71
|
+
diffType: (_newPluginState3 = newPluginState) === null || _newPluginState3 === void 0 ? void 0 : _newPluginState3.diffType,
|
|
72
|
+
hideDeletedDiffs: (_newPluginState4 = newPluginState) === null || _newPluginState4 === void 0 ? void 0 : _newPluginState4.hideDeletedDiffs,
|
|
73
|
+
showIndicators: (_newPluginState5 = newPluginState) === null || _newPluginState5 === void 0 ? void 0 : _newPluginState5.showIndicators,
|
|
74
|
+
smartThresholds: (_newPluginState6 = newPluginState) === null || _newPluginState6 === void 0 ? void 0 : _newPluginState6.smartThresholds,
|
|
75
|
+
deletedDiffPlacement: (_newPluginState7 = newPluginState) === null || _newPluginState7 === void 0 ? void 0 : _newPluginState7.deletedDiffPlacement
|
|
74
76
|
} : {})),
|
|
75
77
|
decorations = _calculateDiffDecorat.decorations,
|
|
76
78
|
diffDescriptors = _calculateDiffDecorat.diffDescriptors;
|
|
77
79
|
// Update the decorations and their ids
|
|
78
80
|
newPluginState.decorations = decorations;
|
|
79
|
-
if ((0,
|
|
81
|
+
if ((0, _isExtendedEnabled.isExtendedEnabled)((_newPluginState8 = newPluginState) === null || _newPluginState8 === void 0 ? void 0 : _newPluginState8.diffType)) {
|
|
80
82
|
newPluginState.diffDescriptors = diffDescriptors;
|
|
81
83
|
}
|
|
82
84
|
} else if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'HIDE_DIFF') {
|
|
@@ -84,15 +86,16 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
84
86
|
decorations: _view.DecorationSet.empty,
|
|
85
87
|
isDisplayingChanges: false,
|
|
86
88
|
activeIndex: undefined
|
|
87
|
-
}, (0,
|
|
89
|
+
}, (0, _isExtendedEnabled.isExtendedEnabled)(currentPluginState.diffType) ? {
|
|
88
90
|
isInverted: false,
|
|
89
91
|
diffType: 'inline',
|
|
90
92
|
hideDeletedDiffs: false,
|
|
91
93
|
diffDescriptors: []
|
|
92
94
|
} : {});
|
|
93
95
|
} else if ((meta === null || meta === void 0 ? void 0 : meta.action) === 'SCROLL_TO_NEXT' || (meta === null || meta === void 0 ? void 0 : meta.action) === 'SCROLL_TO_PREVIOUS') {
|
|
96
|
+
var _newPluginState9;
|
|
94
97
|
// Update the active index in plugin state and recalculate decorations
|
|
95
|
-
var _decorations = (0, _getScrollableDecorations.getScrollableDecorations)(currentPluginState.decorations, newState.doc);
|
|
98
|
+
var _decorations = (0, _getScrollableDecorations.getScrollableDecorations)(currentPluginState.decorations, newState.doc, (_newPluginState9 = newPluginState) === null || _newPluginState9 === void 0 ? void 0 : _newPluginState9.diffType);
|
|
96
99
|
if (_decorations.length > 0) {
|
|
97
100
|
var _currentPluginState$a;
|
|
98
101
|
// Initialize to -1 if undefined so that the first "next" scroll takes us to index 0 (first change).
|
|
@@ -126,16 +129,18 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
126
129
|
intl: getIntl(),
|
|
127
130
|
activeIndexPos: newPluginState.activeIndexPos,
|
|
128
131
|
api: api
|
|
129
|
-
}, (0,
|
|
132
|
+
}, (0, _isExtendedEnabled.isExtendedEnabled)(newPluginState.diffType) ? {
|
|
130
133
|
isInverted: newPluginState.isInverted,
|
|
131
134
|
diffType: newPluginState.diffType,
|
|
132
135
|
hideDeletedDiffs: newPluginState.hideDeletedDiffs,
|
|
133
|
-
showIndicators: newPluginState.showIndicators
|
|
136
|
+
showIndicators: newPluginState.showIndicators,
|
|
137
|
+
smartThresholds: newPluginState.smartThresholds,
|
|
138
|
+
deletedDiffPlacement: newPluginState.deletedDiffPlacement
|
|
134
139
|
} : {})),
|
|
135
140
|
updatedDecorations = _calculateDiffDecorat2.decorations,
|
|
136
141
|
updatedDiffDescriptors = _calculateDiffDecorat2.diffDescriptors;
|
|
137
142
|
newPluginState.decorations = updatedDecorations;
|
|
138
|
-
if ((0,
|
|
143
|
+
if ((0, _isExtendedEnabled.isExtendedEnabled)(newPluginState.diffType)) {
|
|
139
144
|
newPluginState.diffDescriptors = updatedDiffDescriptors;
|
|
140
145
|
}
|
|
141
146
|
}
|
|
@@ -169,7 +174,7 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
169
174
|
var pluginState = showDiffPluginKey.getState(view.state);
|
|
170
175
|
|
|
171
176
|
// Scroll to the first decoration when scrollIntoView was requested
|
|
172
|
-
if (pluginState !== null && pluginState !== void 0 && pluginState.scrollIntoView && (0,
|
|
177
|
+
if (pluginState !== null && pluginState !== void 0 && pluginState.scrollIntoView && (0, _isExtendedEnabled.isExtendedEnabled)(pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType)) {
|
|
173
178
|
var _cancelPendingScrollT;
|
|
174
179
|
(_cancelPendingScrollT = cancelPendingScrollToDecoration) === null || _cancelPendingScrollT === void 0 || _cancelPendingScrollT();
|
|
175
180
|
cancelPendingScrollToDecoration = (0, _scrollToDiff.scrollToFirstDecoration)(view, pluginState.decorations);
|
|
@@ -186,7 +191,7 @@ var createPlugin = exports.createPlugin = function createPlugin(config, getIntl,
|
|
|
186
191
|
if ((pluginState === null || pluginState === void 0 ? void 0 : pluginState.activeIndex) !== undefined && activeIndexChanged) {
|
|
187
192
|
var _cancelPendingScrollT2, _api$expand;
|
|
188
193
|
(_cancelPendingScrollT2 = cancelPendingScrollToDecoration) === null || _cancelPendingScrollT2 === void 0 || _cancelPendingScrollT2();
|
|
189
|
-
var scrollableDecorations = (0, _getScrollableDecorations.getScrollableDecorations)(pluginState.decorations, view.state.doc);
|
|
194
|
+
var scrollableDecorations = (0, _getScrollableDecorations.getScrollableDecorations)(pluginState.decorations, view.state.doc, pluginState === null || pluginState === void 0 ? void 0 : pluginState.diffType);
|
|
190
195
|
var activeDecoration = scrollableDecorations[pluginState.activeIndex];
|
|
191
196
|
if (activeDecoration && api !== null && api !== void 0 && (_api$expand = api.expand) !== null && _api$expand !== void 0 && (_api$expand = _api$expand.commands) !== null && _api$expand !== void 0 && _api$expand.toggleExpandRange) {
|
|
192
197
|
api === null || api === void 0 || api.core.actions.execute(api.expand.commands.toggleExpandRange(activeDecoration.from, activeDecoration.to, true));
|
|
@@ -4,6 +4,7 @@ import memoizeOne from 'memoize-one';
|
|
|
4
4
|
import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
|
|
5
5
|
import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document';
|
|
6
6
|
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
7
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
8
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
8
9
|
import { areDocsEqualByBlockStructureAndText } from '../areDocsEqualByBlockStructureAndText';
|
|
9
10
|
import { createDocMarginAnchorWidget } from '../decorations/createAnchorDecorationWidgets';
|
|
@@ -14,19 +15,37 @@ import { createNodeChangedDecorationWidget } from '../decorations/createNodeChan
|
|
|
14
15
|
import { extractDiffDescriptors } from '../decorations/decorationKeys';
|
|
15
16
|
import { getAttrChangeRanges, stepIsValidAttrChange } from '../decorations/utils/getAttrChangeRanges';
|
|
16
17
|
import { getMarkChangeRanges } from '../decorations/utils/getMarkChangeRanges';
|
|
18
|
+
import { isExtendedEnabled } from '../isExtendedEnabled';
|
|
17
19
|
import { diffBySteps, getStepChanges } from './diffBySteps';
|
|
18
20
|
import { groupChangesByBlock } from './groupChangesByBlock';
|
|
19
21
|
import { optimizeChanges } from './optimizeChanges';
|
|
20
22
|
import { simplifySteps } from './simplifySteps';
|
|
23
|
+
import { classifySmartChanges } from './smart/classifySmartChanges';
|
|
24
|
+
import { smartChangeLevel } from './smart/helpers';
|
|
21
25
|
const getChanges = ({
|
|
22
26
|
changeset,
|
|
23
27
|
originalDoc,
|
|
24
28
|
steppedDoc,
|
|
25
29
|
diffType,
|
|
26
30
|
tr,
|
|
27
|
-
steps
|
|
31
|
+
steps,
|
|
32
|
+
intl,
|
|
33
|
+
smartThresholds
|
|
28
34
|
}) => {
|
|
29
|
-
if (
|
|
35
|
+
if (isExtendedEnabled(diffType)) {
|
|
36
|
+
// The `smart` diff type is gated behind `platform_editor_ai_smart_diff`. When the gate is
|
|
37
|
+
// off, `smart` falls through to the default (`inline`) path below so behaviour degrades
|
|
38
|
+
// gracefully (see docs/smart-diff-design.md §3).
|
|
39
|
+
if (diffType === 'smart' && fg('platform_editor_ai_smart_diff')) {
|
|
40
|
+
const changes = simplifyChanges(changeset.changes, tr.doc);
|
|
41
|
+
return classifySmartChanges({
|
|
42
|
+
changes,
|
|
43
|
+
originalDoc,
|
|
44
|
+
newDoc: tr.doc,
|
|
45
|
+
locale: intl.locale,
|
|
46
|
+
thresholds: smartThresholds
|
|
47
|
+
});
|
|
48
|
+
}
|
|
30
49
|
if (diffType === 'step') {
|
|
31
50
|
return diffBySteps(originalDoc, steps);
|
|
32
51
|
}
|
|
@@ -39,6 +58,29 @@ const getChanges = ({
|
|
|
39
58
|
const changes = simplifyChanges(changeset.changes, tr.doc);
|
|
40
59
|
return optimizeChanges(changes);
|
|
41
60
|
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Collect the inline-content ranges of every leaf text-bearing block (paragraph, heading, …)
|
|
64
|
+
* whose content overlaps `[from, to)`. Used to clip a node-level `smart` insertion highlight to
|
|
65
|
+
* the actual added text, so the inserted background/underline never spans structural gaps
|
|
66
|
+
* (list markers, empty item slots, cell/column boundaries) which would render as phantom rows.
|
|
67
|
+
*/
|
|
68
|
+
const leafTextblockRanges = (doc, from, to) => {
|
|
69
|
+
const ranges = [];
|
|
70
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
|
71
|
+
if (node.isTextblock && node.content.size > 0) {
|
|
72
|
+
const contentFrom = Math.max(pos + 1, from);
|
|
73
|
+
const contentTo = Math.min(pos + 1 + node.content.size, to);
|
|
74
|
+
if (contentTo > contentFrom) {
|
|
75
|
+
ranges.push([contentFrom, contentTo]);
|
|
76
|
+
}
|
|
77
|
+
// Textblocks have no block children to descend into.
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
return ranges;
|
|
83
|
+
};
|
|
42
84
|
const calculateNodesForBlockDecoration = ({
|
|
43
85
|
doc,
|
|
44
86
|
from,
|
|
@@ -47,12 +89,13 @@ const calculateNodesForBlockDecoration = ({
|
|
|
47
89
|
isInserted = true,
|
|
48
90
|
activeIndexPos,
|
|
49
91
|
shouldHideDeleted = false,
|
|
50
|
-
showIndicators = false
|
|
92
|
+
showIndicators = false,
|
|
93
|
+
diffType
|
|
51
94
|
}) => {
|
|
52
95
|
const decorations = [];
|
|
53
96
|
// Iterate over the document nodes within the range
|
|
54
97
|
doc.nodesBetween(from, to, (node, pos) => {
|
|
55
|
-
if (node.isBlock && (!
|
|
98
|
+
if (node.isBlock && (!isExtendedEnabled(diffType) || pos + node.nodeSize <= to)) {
|
|
56
99
|
const nodeEnd = pos + node.nodeSize;
|
|
57
100
|
const isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to;
|
|
58
101
|
decorations.push(...createBlockChangedDecoration({
|
|
@@ -66,7 +109,8 @@ const calculateNodesForBlockDecoration = ({
|
|
|
66
109
|
isActive,
|
|
67
110
|
shouldHideDeleted,
|
|
68
111
|
showIndicators,
|
|
69
|
-
doc
|
|
112
|
+
doc,
|
|
113
|
+
diffType
|
|
70
114
|
}));
|
|
71
115
|
}
|
|
72
116
|
});
|
|
@@ -83,7 +127,9 @@ const calculateDiffDecorationsInner = ({
|
|
|
83
127
|
isInverted = false,
|
|
84
128
|
diffType = 'inline',
|
|
85
129
|
hideDeletedDiffs = false,
|
|
86
|
-
showIndicators = false
|
|
130
|
+
showIndicators = false,
|
|
131
|
+
smartThresholds,
|
|
132
|
+
deletedDiffPlacement = 'top'
|
|
87
133
|
}) => {
|
|
88
134
|
const {
|
|
89
135
|
originalDoc,
|
|
@@ -143,14 +189,16 @@ const calculateDiffDecorationsInner = ({
|
|
|
143
189
|
steppedDoc,
|
|
144
190
|
diffType,
|
|
145
191
|
tr,
|
|
146
|
-
steps
|
|
192
|
+
steps,
|
|
193
|
+
intl,
|
|
194
|
+
smartThresholds
|
|
147
195
|
});
|
|
148
196
|
const decorations = [];
|
|
149
197
|
|
|
150
198
|
/**
|
|
151
199
|
* If showIndicators is on, we create an anchor widget here to mark the doc margin.
|
|
152
200
|
*/
|
|
153
|
-
if (showIndicators &&
|
|
201
|
+
if (showIndicators && isExtendedEnabled(diffType)) {
|
|
154
202
|
decorations.push(createDocMarginAnchorWidget());
|
|
155
203
|
}
|
|
156
204
|
|
|
@@ -162,34 +210,68 @@ const calculateDiffDecorationsInner = ({
|
|
|
162
210
|
// shouldHideDeleted for block/node decorations: suppressed when isInverted + hideDeletedDiffs,
|
|
163
211
|
// or when showGranularWithBlock (block reference widget is shown instead).
|
|
164
212
|
// isInverted gates both — on an inverted diff the inserted side is visually the deleted side.
|
|
165
|
-
const shouldHideDeleted =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
213
|
+
const shouldHideDeleted = isExtendedEnabled(diffType) ? isInverted && (hideDeletedDiffs || showGranularWithBlock) && change.deleted.length > 0 : false;
|
|
214
|
+
|
|
215
|
+
// For `smart` NODE-level promotions the change range spans a whole container
|
|
216
|
+
// (e.g. an entire list/table/layout, using outer node bounds). Applying a SINGLE
|
|
217
|
+
// inline decoration across that whole range would paint the inserted style across
|
|
218
|
+
// block boundaries and structural gaps (list markers, empty item slots), producing
|
|
219
|
+
// phantom "empty" rows above the real content. But skipping the inline highlight
|
|
220
|
+
// entirely leaves added text-bearing blocks (paragraphs/headings inside the added
|
|
221
|
+
// container) without the inserted background+underline, because block decorations
|
|
222
|
+
// return no style for paragraph/heading. So for node-level smart changes we instead
|
|
223
|
+
// emit ONE inline decoration per leaf text-bearing block within the range — the text
|
|
224
|
+
// gets highlighted, and structural gaps never do.
|
|
225
|
+
const isSmartNodeLevel = diffType === 'smart' && fg('platform_editor_ai_smart_diff') && smartChangeLevel(change) === 'node';
|
|
226
|
+
if (isSmartNodeLevel) {
|
|
227
|
+
for (const [from, to] of leafTextblockRanges(tr.doc, change.fromB, change.toB)) {
|
|
228
|
+
decorations.push(...createInlineChangedDecoration({
|
|
229
|
+
change: {
|
|
230
|
+
fromB: from,
|
|
231
|
+
toB: to
|
|
232
|
+
},
|
|
233
|
+
doc: tr.doc,
|
|
234
|
+
colorScheme,
|
|
235
|
+
isActive,
|
|
236
|
+
diffType,
|
|
237
|
+
...(isExtendedEnabled(diffType) && {
|
|
238
|
+
isInserted,
|
|
239
|
+
shouldHideDeleted,
|
|
240
|
+
showIndicators
|
|
241
|
+
})
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
decorations.push(...createInlineChangedDecoration({
|
|
246
|
+
change,
|
|
247
|
+
doc: tr.doc,
|
|
248
|
+
colorScheme,
|
|
249
|
+
isActive,
|
|
250
|
+
diffType,
|
|
251
|
+
...(isExtendedEnabled(diffType) && {
|
|
252
|
+
isInserted,
|
|
253
|
+
shouldHideDeleted,
|
|
254
|
+
showIndicators
|
|
255
|
+
})
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
177
258
|
decorations.push(...calculateNodesForBlockDecoration({
|
|
178
259
|
doc: tr.doc,
|
|
179
260
|
from: change.fromB,
|
|
180
261
|
to: change.toB,
|
|
181
262
|
colorScheme,
|
|
182
|
-
...(
|
|
263
|
+
...(isExtendedEnabled(diffType) && {
|
|
183
264
|
isInserted,
|
|
184
265
|
shouldHideDeleted,
|
|
185
266
|
showIndicators
|
|
186
267
|
}),
|
|
187
268
|
activeIndexPos,
|
|
188
|
-
intl
|
|
269
|
+
intl,
|
|
270
|
+
diffType
|
|
189
271
|
}));
|
|
190
272
|
}
|
|
191
273
|
if (change.deleted.length > 0) {
|
|
192
|
-
const shouldHideDeleted =
|
|
274
|
+
const shouldHideDeleted = isExtendedEnabled(diffType) ? !isInverted && (hideDeletedDiffs || showGranularWithBlock) && change.inserted.length > 0 : false;
|
|
193
275
|
if (!shouldHideDeleted) {
|
|
194
276
|
decorations.push(...createNodeChangedDecorationWidget({
|
|
195
277
|
change,
|
|
@@ -199,9 +281,13 @@ const calculateDiffDecorationsInner = ({
|
|
|
199
281
|
newDoc: tr.doc,
|
|
200
282
|
intl,
|
|
201
283
|
activeIndexPos,
|
|
202
|
-
...(
|
|
284
|
+
...(isExtendedEnabled(diffType) && {
|
|
203
285
|
isInserted: !isInserted,
|
|
204
|
-
diffType
|
|
286
|
+
diffType,
|
|
287
|
+
// For `smart` node- and paragraph-level changes, optionally render the
|
|
288
|
+
// deleted content below the new content (gray + strikethrough) instead
|
|
289
|
+
// of above it. Controlled by `deletedDiffPlacement` (default `'top'`).
|
|
290
|
+
placeBelow: deletedDiffPlacement === 'bottom' && diffType === 'smart' && fg('platform_editor_ai_smart_diff') && (smartChangeLevel(change) === 'node' || smartChangeLevel(change) === 'paragraph')
|
|
205
291
|
}),
|
|
206
292
|
showIndicators
|
|
207
293
|
}));
|
|
@@ -336,7 +422,9 @@ export const calculateDiffDecorations = memoizeOne(calculateDiffDecorationsInner
|
|
|
336
422
|
isInverted,
|
|
337
423
|
diffType,
|
|
338
424
|
hideDeletedDiffs,
|
|
339
|
-
showIndicators
|
|
425
|
+
showIndicators,
|
|
426
|
+
smartThresholds,
|
|
427
|
+
deletedDiffPlacement
|
|
340
428
|
}], [{
|
|
341
429
|
pluginState: lastPluginState,
|
|
342
430
|
state: lastState,
|
|
@@ -346,13 +434,15 @@ export const calculateDiffDecorations = memoizeOne(calculateDiffDecorationsInner
|
|
|
346
434
|
isInverted: lastIsInverted,
|
|
347
435
|
diffType: lastDiffType,
|
|
348
436
|
hideDeletedDiffs: lastHideDeletedDiffs,
|
|
349
|
-
showIndicators: lastShowIndicators
|
|
437
|
+
showIndicators: lastShowIndicators,
|
|
438
|
+
smartThresholds: lastSmartThresholds,
|
|
439
|
+
deletedDiffPlacement: lastDeletedDiffPlacement
|
|
350
440
|
}]) => {
|
|
351
441
|
var _ref2;
|
|
352
442
|
const originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
|
|
353
|
-
if (
|
|
443
|
+
if (isExtendedEnabled(diffType)) {
|
|
354
444
|
var _ref;
|
|
355
|
-
return (_ref = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && showIndicators === lastShowIndicators) !== null && _ref !== void 0 ? _ref : false;
|
|
445
|
+
return (_ref = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && showIndicators === lastShowIndicators && isEqual(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement) !== null && _ref !== void 0 ? _ref : false;
|
|
356
446
|
}
|
|
357
447
|
return (_ref2 = originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isEqual(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref2 !== void 0 ? _ref2 : false;
|
|
358
448
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, editor-state-free diff-change computation.
|
|
3
|
+
*
|
|
4
|
+
* Turns an `originalDoc` + forward `steps` into the classified `Change[]` for the
|
|
5
|
+
* requested `diffType`, plus the reconstructed new document — the same classifier
|
|
6
|
+
* the diff overlay uses (`calculateDiffDecorations` → `getChanges`), exposed as a
|
|
7
|
+
* reusable utility (e.g. to derive reviewable segments without rendering
|
|
8
|
+
* decorations). It runs the requested `diffType` DIRECTLY and does NOT apply the
|
|
9
|
+
* overlay's `platform_editor_ai_smart_diff` gate, so a `smart` result here can
|
|
10
|
+
* differ from what the overlay draws when that gate is off (the overlay falls back
|
|
11
|
+
* to inline); callers that need overlay parity must account for that gate.
|
|
12
|
+
*
|
|
13
|
+
* Pure: no `EditorState`, no transactions, no React. The new document is
|
|
14
|
+
* reconstructed by applying the (simplified) steps to `originalDoc`.
|
|
15
|
+
*/
|
|
16
|
+
import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
|
|
17
|
+
import { diffBySteps } from './diffBySteps';
|
|
18
|
+
import { groupChangesByBlock } from './groupChangesByBlock';
|
|
19
|
+
import { optimizeChanges } from './optimizeChanges';
|
|
20
|
+
import { simplifySteps } from './simplifySteps';
|
|
21
|
+
import { classifySmartChanges } from './smart/classifySmartChanges';
|
|
22
|
+
/**
|
|
23
|
+
* Apply the (simplified) steps to `originalDoc` to reconstruct the new doc, and
|
|
24
|
+
* compute the classified `Change[]` for the requested `diffType`. Mirrors the
|
|
25
|
+
* body of `calculateDiffDecorations` → `getChanges` so callers stay in lock-step
|
|
26
|
+
* with the rendered diff. Returns an empty change list (and `originalDoc` as the
|
|
27
|
+
* new doc) when there are no steps.
|
|
28
|
+
*/
|
|
29
|
+
export const computeDiffChanges = ({
|
|
30
|
+
originalDoc,
|
|
31
|
+
steps,
|
|
32
|
+
diffType = 'smart',
|
|
33
|
+
locale = 'en',
|
|
34
|
+
smartThresholds
|
|
35
|
+
}) => {
|
|
36
|
+
if (!steps || steps.length === 0) {
|
|
37
|
+
return {
|
|
38
|
+
changes: [],
|
|
39
|
+
newDoc: originalDoc
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const simplifiedSteps = simplifySteps(steps, originalDoc);
|
|
43
|
+
let steppedDoc = originalDoc;
|
|
44
|
+
const stepMaps = [];
|
|
45
|
+
try {
|
|
46
|
+
for (const step of simplifiedSteps) {
|
|
47
|
+
const result = step.apply(steppedDoc);
|
|
48
|
+
if (result.failed === null && result.doc) {
|
|
49
|
+
stepMaps.push(step.getMap());
|
|
50
|
+
steppedDoc = result.doc;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
// A step's positions fell outside the current doc — `ReplaceStep.apply`
|
|
55
|
+
// throws a RangeError (rather than returning a failed result) when a
|
|
56
|
+
// position exceeds the doc size. This can happen for pathological or
|
|
57
|
+
// inconsistent step sequences. Bail with no changes rather than letting the
|
|
58
|
+
// error propagate to the caller (which, for the PSR, would crash the
|
|
59
|
+
// toolbar); the consumer then falls back to its non-diff segmenting path.
|
|
60
|
+
return {
|
|
61
|
+
changes: [],
|
|
62
|
+
newDoc: originalDoc
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const changeset = ChangeSet.create(originalDoc).addSteps(steppedDoc, stepMaps, steppedDoc);
|
|
66
|
+
if (diffType === 'smart') {
|
|
67
|
+
return {
|
|
68
|
+
changes: classifySmartChanges({
|
|
69
|
+
changes: simplifyChanges(changeset.changes, steppedDoc),
|
|
70
|
+
originalDoc,
|
|
71
|
+
newDoc: steppedDoc,
|
|
72
|
+
locale,
|
|
73
|
+
thresholds: smartThresholds
|
|
74
|
+
}),
|
|
75
|
+
newDoc: steppedDoc
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (diffType === 'block') {
|
|
79
|
+
return {
|
|
80
|
+
changes: groupChangesByBlock(changeset.changes, originalDoc, steppedDoc),
|
|
81
|
+
newDoc: steppedDoc
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (diffType === 'step') {
|
|
85
|
+
return {
|
|
86
|
+
changes: diffBySteps(originalDoc, simplifiedSteps),
|
|
87
|
+
newDoc: steppedDoc
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
changes: optimizeChanges(simplifyChanges(changeset.changes, steppedDoc)),
|
|
92
|
+
newDoc: steppedDoc
|
|
93
|
+
};
|
|
94
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Finds the position range of the top-level block (direct child of doc) that
|
|
3
|
-
*
|
|
2
|
+
* Finds the position range (outer bounds) of the top-level block (direct child of doc) that
|
|
3
|
+
* contains the range [from, to]. Shared with the `smart` diff type so its block grouping is
|
|
4
|
+
* identical to the `block` diff type by construction.
|
|
4
5
|
*/
|
|
5
|
-
function getTopLevelBlockAt(doc, from, to) {
|
|
6
|
+
export function getTopLevelBlockAt(doc, from, to) {
|
|
6
7
|
return {
|
|
7
8
|
from: doc.resolve(from).before(1),
|
|
8
9
|
to: doc.resolve(to).after(1)
|