@atlaskit/editor-plugin-show-diff 14.1.0 → 14.2.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 14.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`391eb60fad28b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/391eb60fad28b) -
8
+ Export `ShowDiffParams` from the public show-diff type entry point.
9
+
10
+ ## 14.1.1
11
+
12
+ ### Patch Changes
13
+
14
+ - [`b1510eccd9729`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b1510eccd9729) -
15
+ Reduce false-positive attribute diff decorations behind
16
+ `platform_editor_reduce_diff_attr_sensitivity`.
17
+ - Updated dependencies
18
+
3
19
  ## 14.1.0
4
20
 
5
21
  ### Minor Changes
@@ -13,6 +13,7 @@ var _memoizeOne = _interopRequireDefault(require("memoize-one"));
13
13
  var _prosemirrorChangeset = require("prosemirror-changeset");
14
14
  var _deprecatedPlatformFeatureExperiments = require("@atlaskit/editor-common/deprecated-platform-feature-experiments");
15
15
  var _document = require("@atlaskit/editor-common/utils/document");
16
+ var _transform = require("@atlaskit/editor-prosemirror/transform");
16
17
  var _view = require("@atlaskit/editor-prosemirror/view");
17
18
  var _fg = require("@atlaskit/platform-feature-flags/fg");
18
19
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
@@ -294,7 +295,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
294
295
  } else {
295
296
  simplifiedSteps = (0, _simplifySteps.simplifySteps)(steps, originalDoc);
296
297
  }
297
- var attrSteps = [];
298
+ var pendingAttrSteps = [];
298
299
  var stepMaps = [];
299
300
  var _iterator = _createForOfIteratorHelper(simplifiedSteps),
300
301
  _step;
@@ -304,20 +305,56 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
304
305
  var result = step.apply(steppedDoc);
305
306
  if (result.failed === null && result.doc) {
306
307
  if ((0, _getAttrChangeRanges.stepIsValidAttrChange)(step, steppedDoc, result.doc)) {
307
- attrSteps.push(step);
308
+ pendingAttrSteps.push({
309
+ afterNode: result.doc.nodeAt(step.pos),
310
+ beforeNode: steppedDoc.nodeAt(step.pos),
311
+ mapIndex: stepMaps.length,
312
+ step: step
313
+ });
308
314
  }
309
315
  stepMaps.push(step.getMap());
310
316
  steppedDoc = result.doc;
311
317
  }
312
318
  }
313
-
314
- // Rather than using .eq() we use a custom function that only checks for structural
315
- // changes and ignores differences in attributes which don't affect decoration positions
319
+ // Gate the complete attribution fix: mapped positions and step-time nodes are used together.
320
+ // The fallback deliberately preserves the legacy raw-position lookups for rollout safety.
316
321
  } catch (err) {
317
322
  _iterator.e(err);
318
323
  } finally {
319
324
  _iterator.f();
320
325
  }
326
+ var attrStepContexts = (0, _fg.fg)('platform_editor_reduce_diff_attr_sensitivity') ? pendingAttrSteps.flatMap(function (_ref0) {
327
+ var afterNode = _ref0.afterNode,
328
+ beforeNode = _ref0.beforeNode,
329
+ mapIndex = _ref0.mapIndex,
330
+ step = _ref0.step;
331
+ var finalPosition = new _transform.Mapping(stepMaps.slice(mapIndex + 1)).mapResult(step.pos);
332
+ if (finalPosition.deleted) {
333
+ return [];
334
+ }
335
+ var originalPosition = new _transform.Mapping(stepMaps.slice(0, mapIndex)).invert().mapResult(step.pos);
336
+ return [_objectSpread(_objectSpread({
337
+ afterNode: afterNode,
338
+ beforeNode: beforeNode,
339
+ finalPos: finalPosition.pos
340
+ }, originalPosition.deleted ? {} : {
341
+ originalPos: originalPosition.pos
342
+ }), {}, {
343
+ step: step
344
+ })];
345
+ }) : pendingAttrSteps.map(function (_ref1) {
346
+ var step = _ref1.step;
347
+ return {
348
+ afterNode: tr.doc.nodeAt(step.pos),
349
+ beforeNode: originalDoc.nodeAt(step.pos),
350
+ finalPos: step.pos,
351
+ originalPos: step.pos,
352
+ step: step
353
+ };
354
+ });
355
+
356
+ // Rather than using .eq() we use a custom function that only checks for structural
357
+ // changes and ignores differences in attributes which don't affect decoration positions
321
358
  if (!(0, _document.areNodesEqualIgnoreAttrs)(steppedDoc, tr.doc)) {
322
359
  var _api$analytics;
323
360
  var recoveredViaContentEquality = (0, _areDocsEqualByBlockStructureAndText.areDocsEqualByBlockStructureAndText)(steppedDoc, tr.doc);
@@ -531,7 +568,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
531
568
  isInserted: true
532
569
  })));
533
570
  });
534
- (0, _getAttrChangeRanges.getAttrChangeRanges)(tr.doc, attrSteps, originalDoc).forEach(function (change) {
571
+ (0, _getAttrChangeRanges.getAttrChangeRanges)(tr.doc, attrStepContexts, originalDoc).forEach(function (change) {
535
572
  if (change.isInline) {
536
573
  // Inline nodes (e.g. date, emoji, mention, status) need an inline decoration rather than a block decoration
537
574
  var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
@@ -621,42 +658,42 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
621
658
  };
622
659
  var calculateDiffDecorations = exports.calculateDiffDecorations = (0, _memoizeOne.default)(calculateDiffDecorationsInner,
623
660
  // Cache results unless relevant inputs change
624
- function (_ref0, _ref1) {
625
- var _ref13;
626
- var _ref10 = (0, _slicedToArray2.default)(_ref0, 1),
627
- _ref10$ = _ref10[0],
628
- pluginState = _ref10$.pluginState,
629
- state = _ref10$.state,
630
- colorScheme = _ref10$.colorScheme,
631
- intl = _ref10$.intl,
632
- activeIndexPos = _ref10$.activeIndexPos,
633
- isInverted = _ref10$.isInverted,
634
- diffType = _ref10$.diffType,
635
- hideDeletedDiffs = _ref10$.hideDeletedDiffs,
636
- hideAddedDiffsUnderline = _ref10$.hideAddedDiffsUnderline,
637
- showIndicators = _ref10$.showIndicators,
638
- smartThresholds = _ref10$.smartThresholds,
639
- deletedDiffPlacement = _ref10$.deletedDiffPlacement,
640
- inlineDeletedDiffPlacement = _ref10$.inlineDeletedDiffPlacement;
641
- var _ref11 = (0, _slicedToArray2.default)(_ref1, 1),
642
- _ref11$ = _ref11[0],
643
- lastPluginState = _ref11$.pluginState,
644
- lastState = _ref11$.state,
645
- lastColorScheme = _ref11$.colorScheme,
646
- lastIntl = _ref11$.intl,
647
- lastActiveIndexPos = _ref11$.activeIndexPos,
648
- lastIsInverted = _ref11$.isInverted,
649
- lastDiffType = _ref11$.diffType,
650
- lastHideDeletedDiffs = _ref11$.hideDeletedDiffs,
651
- lastHideAddedDiffsUnderline = _ref11$.hideAddedDiffsUnderline,
652
- lastShowIndicators = _ref11$.showIndicators,
653
- lastSmartThresholds = _ref11$.smartThresholds,
654
- lastDeletedDiffPlacement = _ref11$.deletedDiffPlacement,
655
- lastInlineDeletedDiffPlacement = _ref11$.inlineDeletedDiffPlacement;
661
+ function (_ref10, _ref11) {
662
+ var _ref15;
663
+ var _ref12 = (0, _slicedToArray2.default)(_ref10, 1),
664
+ _ref12$ = _ref12[0],
665
+ pluginState = _ref12$.pluginState,
666
+ state = _ref12$.state,
667
+ colorScheme = _ref12$.colorScheme,
668
+ intl = _ref12$.intl,
669
+ activeIndexPos = _ref12$.activeIndexPos,
670
+ isInverted = _ref12$.isInverted,
671
+ diffType = _ref12$.diffType,
672
+ hideDeletedDiffs = _ref12$.hideDeletedDiffs,
673
+ hideAddedDiffsUnderline = _ref12$.hideAddedDiffsUnderline,
674
+ showIndicators = _ref12$.showIndicators,
675
+ smartThresholds = _ref12$.smartThresholds,
676
+ deletedDiffPlacement = _ref12$.deletedDiffPlacement,
677
+ inlineDeletedDiffPlacement = _ref12$.inlineDeletedDiffPlacement;
678
+ var _ref13 = (0, _slicedToArray2.default)(_ref11, 1),
679
+ _ref13$ = _ref13[0],
680
+ lastPluginState = _ref13$.pluginState,
681
+ lastState = _ref13$.state,
682
+ lastColorScheme = _ref13$.colorScheme,
683
+ lastIntl = _ref13$.intl,
684
+ lastActiveIndexPos = _ref13$.activeIndexPos,
685
+ lastIsInverted = _ref13$.isInverted,
686
+ lastDiffType = _ref13$.diffType,
687
+ lastHideDeletedDiffs = _ref13$.hideDeletedDiffs,
688
+ lastHideAddedDiffsUnderline = _ref13$.hideAddedDiffsUnderline,
689
+ lastShowIndicators = _ref13$.showIndicators,
690
+ lastSmartThresholds = _ref13$.smartThresholds,
691
+ lastDeletedDiffPlacement = _ref13$.deletedDiffPlacement,
692
+ lastInlineDeletedDiffPlacement = _ref13$.inlineDeletedDiffPlacement;
656
693
  var originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
657
694
  if ((0, _isExtendedEnabled.isExtendedEnabled)(diffType)) {
658
- var _ref12;
659
- return (_ref12 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && (0, _isEqual.default)(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref12 !== void 0 ? _ref12 : false;
695
+ var _ref14;
696
+ return (_ref14 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && (0, _isEqual.default)(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref14 !== void 0 ? _ref14 : false;
660
697
  }
661
- return (_ref13 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref13 !== void 0 ? _ref13 : false;
698
+ return (_ref15 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && (0, _isEqual.default)(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref15 !== void 0 ? _ref15 : false;
662
699
  });
@@ -6,10 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.stepIsValidAttrChange = exports.getAttrChangeRanges = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
10
+ var _omit = _interopRequireDefault(require("lodash/omit"));
9
11
  var _steps = require("@atlaskit/adf-schema/steps");
10
12
  var _deprecatedPlatformFeatureExperiments = require("@atlaskit/editor-common/deprecated-platform-feature-experiments");
11
13
  var _nodeTypeUtils = require("@atlaskit/editor-common/utils/node-type-utils");
12
14
  var _transform = require("@atlaskit/editor-prosemirror/transform");
15
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
13
16
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
14
17
  var _diffableAttrs = require("./diffableAttrs");
15
18
  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; }
@@ -41,33 +44,57 @@ var isInlineAttrChangeNodeName = function isInlineAttrChangeNodeName(nodeName) {
41
44
  // Extension node type names. Their "any attr except localId" exclude rule lives
42
45
  // in the shared `diffableAttrs` map and is applied via `isDiffableAttr` below.
43
46
  var extensionNodeNames = ['extension', 'inlineExtension', 'bodiedExtension'];
47
+ var transientExtensionAttrPaths = ['localId', 'parameters.macroParams._parentId'];
48
+
49
+ /**
50
+ * Removes extension metadata that can change between document versions without changing the
51
+ * extension's user-visible configuration.
52
+ */
53
+ var getComparableExtensionAttrs = function getComparableExtensionAttrs(node) {
54
+ return (0, _omit.default)(node.attrs, transientExtensionAttrPaths);
55
+ };
56
+ var haveSameRelevantExtensionAttrs = function haveSameRelevantExtensionAttrs(beforeNode, afterNode) {
57
+ return (0, _isEqual.default)(getComparableExtensionAttrs(beforeNode), getComparableExtensionAttrs(afterNode));
58
+ };
44
59
  var getStepAttrs = function getStepAttrs(step) {
45
60
  if (step instanceof _transform.AttrStep) {
46
61
  return [step.attr];
47
62
  }
48
- if (step instanceof _steps.SetAttrsStep && step.attrs) {
63
+ if (step.attrs) {
49
64
  return Object.keys(step.attrs);
50
65
  }
51
66
  return [];
52
67
  };
53
- var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRanges(doc, steps, originalDoc) {
54
- return steps.map(function (step) {
68
+ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRanges(doc, attrStepContexts, originalDoc) {
69
+ return attrStepContexts.map(function (attrStepContext) {
70
+ var afterNode = attrStepContext.afterNode,
71
+ beforeNode = attrStepContext.beforeNode,
72
+ finalPos = attrStepContext.finalPos,
73
+ originalPos = attrStepContext.originalPos,
74
+ step = attrStepContext.step;
55
75
  if (!(step instanceof _transform.AttrStep) && !(step instanceof _steps.SetAttrsStep)) {
56
76
  return undefined;
57
77
  }
58
78
  var stepAttrs = getStepAttrs(step);
59
- var $pos = doc.resolve(step.pos);
60
- var nodeAtPos = doc.nodeAt(step.pos);
79
+ // SetAttrsStep contains the complete replacement attrs, not only the attrs that changed.
80
+ // Keep the legacy payload-based checks until the rollout gate is enabled, and fall back
81
+ // to them if either step-time node is unavailable.
82
+ var attrsToCheck = (0, _fg.fg)('platform_editor_reduce_diff_attr_sensitivity') && beforeNode && afterNode ? stepAttrs.filter(function (attrName) {
83
+ return !(0, _isEqual.default)(beforeNode.attrs[attrName], afterNode.attrs[attrName]);
84
+ }) : stepAttrs;
85
+ var $pos = doc.resolve(finalPos);
86
+ var nodeAtPos = doc.nodeAt(finalPos);
87
+ var originalNodeAtPos = originalPos === undefined ? null : originalDoc.nodeAt(originalPos);
61
88
 
62
89
  // date node: timestamp attribute change — highlight the date node itself (inline)
63
- if (stepAttrs.some(function (v) {
90
+ if (attrsToCheck.some(function (v) {
64
91
  return dateAttrs.includes(v);
65
92
  }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !(0, _deprecatedPlatformFeatureExperiments.isExperimentEnabled)('platform_editor_improve_inline_diffs', function () {
66
93
  return (0, _expValEquals.expValEquals)('platform_editor_improve_inline_diffs', 'isEnabled', true);
67
94
  })) {
68
95
  return {
69
- fromB: step.pos,
70
- toB: step.pos + nodeAtPos.nodeSize,
96
+ fromB: finalPos,
97
+ toB: finalPos + nodeAtPos.nodeSize,
71
98
  isInline: true,
72
99
  inlineNodeName: 'date'
73
100
  };
@@ -82,30 +109,29 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
82
109
  var nodeName = nodeAtPos.type.name;
83
110
  if (isInlineAttrChangeNodeName(nodeName)) {
84
111
  var watchedAttrs = inlineNodeAttrMap[nodeName];
85
- if (stepAttrs.some(function (v) {
112
+ if (attrsToCheck.some(function (v) {
86
113
  return watchedAttrs.includes(v);
87
114
  })) {
88
- var originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
89
115
  return _objectSpread({
90
- fromB: step.pos,
91
- toB: step.pos + nodeAtPos.nodeSize,
116
+ fromB: finalPos,
117
+ toB: finalPos + nodeAtPos.nodeSize,
92
118
  isInline: true,
93
119
  inlineNodeName: nodeName
94
- }, originalNodeAtPos && {
95
- fromA: step.pos,
96
- toA: step.pos + originalNodeAtPos.nodeSize
120
+ }, originalPos !== undefined && originalNodeAtPos && {
121
+ fromA: originalPos,
122
+ toA: originalPos + originalNodeAtPos.nodeSize
97
123
  });
98
124
  }
99
125
  }
100
126
  }
101
127
 
102
128
  // taskItem node: state attribute change — highlight the taskItem node
103
- if (stepAttrs.some(function (v) {
129
+ if (attrsToCheck.some(function (v) {
104
130
  return taskItemAttrs.includes(v);
105
131
  }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') {
106
132
  return {
107
- fromB: step.pos,
108
- toB: step.pos + nodeAtPos.nodeSize
133
+ fromB: finalPos,
134
+ toB: finalPos + nodeAtPos.nodeSize
109
135
  };
110
136
  }
111
137
 
@@ -113,33 +139,36 @@ var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRa
113
139
  // (e.g. note -> warning) — highlight the new panel and, when the original node
114
140
  // is resolvable, expose its range (fromA/toA) so the caller can render the old
115
141
  // panel as a "deleted" widget for a before/after comparison.
116
- if (stepAttrs.some(function (v) {
142
+ if (attrsToCheck.some(function (v) {
117
143
  return panelAttrs.includes(v);
118
144
  }) && nodeAtPos && (0, _nodeTypeUtils.getBaseNodeTypeName)(nodeAtPos.type) === 'panel') {
119
- var _originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
120
145
  return _objectSpread({
121
- fromB: step.pos,
122
- toB: step.pos + nodeAtPos.nodeSize
123
- }, _originalNodeAtPos && {
124
- fromA: step.pos,
125
- toA: step.pos + _originalNodeAtPos.nodeSize
146
+ fromB: finalPos,
147
+ toB: finalPos + nodeAtPos.nodeSize
148
+ }, originalPos !== undefined && originalNodeAtPos && {
149
+ fromA: originalPos,
150
+ toA: originalPos + originalNodeAtPos.nodeSize
126
151
  });
127
152
  }
128
153
 
129
- // extension nodes: highlight on any diffable attr change (exclude rule in shared map)
130
- if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && stepAttrs.some(function (v) {
154
+ // Extension nodes: highlight changes to user-visible configuration. When enabled,
155
+ // transient extension metadata is ignored by the comparison below.
156
+ if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && attrsToCheck.some(function (v) {
131
157
  return (0, _diffableAttrs.isDiffableAttr)(nodeAtPos.type.name, v);
132
158
  })) {
159
+ if ((0, _fg.fg)('platform_editor_reduce_diff_attr_sensitivity') && beforeNode && afterNode && beforeNode.type === afterNode.type && haveSameRelevantExtensionAttrs(beforeNode, afterNode)) {
160
+ return undefined;
161
+ }
133
162
  var isInline = nodeAtPos.type.name === 'inlineExtension';
134
163
  return {
135
- fromB: step.pos,
136
- toB: step.pos + nodeAtPos.nodeSize,
164
+ fromB: finalPos,
165
+ toB: finalPos + nodeAtPos.nodeSize,
137
166
  isInline: isInline
138
167
  };
139
168
  }
140
169
 
141
170
  // media node: id/collection/url attribute change — highlight the mediaSingle parent
142
- if (stepAttrs.some(function (v) {
171
+ if (attrsToCheck.some(function (v) {
143
172
  return mediaAttrs.includes(v);
144
173
  }) && $pos.parent.type === doc.type.schema.nodes.mediaSingle) {
145
174
  var startPos = $pos.pos + $pos.parentOffset;
@@ -3,6 +3,7 @@ import memoizeOne from 'memoize-one';
3
3
  import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
4
4
  import { isExperimentEnabled } from '@atlaskit/editor-common/deprecated-platform-feature-experiments';
5
5
  import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document';
6
+ import { Mapping } from '@atlaskit/editor-prosemirror/transform';
6
7
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
8
  import { fg } from '@atlaskit/platform-feature-flags/fg';
8
9
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
@@ -268,18 +269,54 @@ const calculateDiffDecorationsInner = ({
268
269
  } else {
269
270
  simplifiedSteps = simplifySteps(steps, originalDoc);
270
271
  }
271
- const attrSteps = [];
272
+ const pendingAttrSteps = [];
272
273
  const stepMaps = [];
273
274
  for (const step of simplifiedSteps) {
274
275
  const result = step.apply(steppedDoc);
275
276
  if (result.failed === null && result.doc) {
276
277
  if (stepIsValidAttrChange(step, steppedDoc, result.doc)) {
277
- attrSteps.push(step);
278
+ pendingAttrSteps.push({
279
+ afterNode: result.doc.nodeAt(step.pos),
280
+ beforeNode: steppedDoc.nodeAt(step.pos),
281
+ mapIndex: stepMaps.length,
282
+ step
283
+ });
278
284
  }
279
285
  stepMaps.push(step.getMap());
280
286
  steppedDoc = result.doc;
281
287
  }
282
288
  }
289
+ // Gate the complete attribution fix: mapped positions and step-time nodes are used together.
290
+ // The fallback deliberately preserves the legacy raw-position lookups for rollout safety.
291
+ const attrStepContexts = fg('platform_editor_reduce_diff_attr_sensitivity') ? pendingAttrSteps.flatMap(({
292
+ afterNode,
293
+ beforeNode,
294
+ mapIndex,
295
+ step
296
+ }) => {
297
+ const finalPosition = new Mapping(stepMaps.slice(mapIndex + 1)).mapResult(step.pos);
298
+ if (finalPosition.deleted) {
299
+ return [];
300
+ }
301
+ const originalPosition = new Mapping(stepMaps.slice(0, mapIndex)).invert().mapResult(step.pos);
302
+ return [{
303
+ afterNode,
304
+ beforeNode,
305
+ finalPos: finalPosition.pos,
306
+ ...(originalPosition.deleted ? {} : {
307
+ originalPos: originalPosition.pos
308
+ }),
309
+ step
310
+ }];
311
+ }) : pendingAttrSteps.map(({
312
+ step
313
+ }) => ({
314
+ afterNode: tr.doc.nodeAt(step.pos),
315
+ beforeNode: originalDoc.nodeAt(step.pos),
316
+ finalPos: step.pos,
317
+ originalPos: step.pos,
318
+ step
319
+ }));
283
320
 
284
321
  // Rather than using .eq() we use a custom function that only checks for structural
285
322
  // changes and ignores differences in attributes which don't affect decoration positions
@@ -484,7 +521,7 @@ const calculateDiffDecorationsInner = ({
484
521
  isInserted: true
485
522
  }));
486
523
  });
487
- getAttrChangeRanges(tr.doc, attrSteps, originalDoc).forEach(change => {
524
+ getAttrChangeRanges(tr.doc, attrStepContexts, originalDoc).forEach(change => {
488
525
  if (change.isInline) {
489
526
  // Inline nodes (e.g. date, emoji, mention, status) need an inline decoration rather than a block decoration
490
527
  const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
@@ -1,7 +1,10 @@
1
+ import isEqual from 'lodash/isEqual';
2
+ import omit from 'lodash/omit';
1
3
  import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
2
4
  import { isExperimentEnabled } from '@atlaskit/editor-common/deprecated-platform-feature-experiments';
3
5
  import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
4
6
  import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
7
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
5
8
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
6
9
  import { getRequiredIncludedDiffableAttrs, isDiffableAttr } from './diffableAttrs';
7
10
  const filterUndefined = x => !!x;
@@ -27,29 +30,49 @@ const isInlineAttrChangeNodeName = nodeName => nodeName in inlineNodeAttrMap;
27
30
  // Extension node type names. Their "any attr except localId" exclude rule lives
28
31
  // in the shared `diffableAttrs` map and is applied via `isDiffableAttr` below.
29
32
  const extensionNodeNames = ['extension', 'inlineExtension', 'bodiedExtension'];
33
+ const transientExtensionAttrPaths = ['localId', 'parameters.macroParams._parentId'];
34
+
35
+ /**
36
+ * Removes extension metadata that can change between document versions without changing the
37
+ * extension's user-visible configuration.
38
+ */
39
+ const getComparableExtensionAttrs = node => omit(node.attrs, transientExtensionAttrPaths);
40
+ const haveSameRelevantExtensionAttrs = (beforeNode, afterNode) => isEqual(getComparableExtensionAttrs(beforeNode), getComparableExtensionAttrs(afterNode));
30
41
  const getStepAttrs = step => {
31
42
  if (step instanceof AttrStep) {
32
43
  return [step.attr];
33
44
  }
34
- if (step instanceof SetAttrsStep && step.attrs) {
45
+ if (step.attrs) {
35
46
  return Object.keys(step.attrs);
36
47
  }
37
48
  return [];
38
49
  };
39
- export const getAttrChangeRanges = (doc, steps, originalDoc) => {
40
- return steps.map(step => {
50
+ export const getAttrChangeRanges = (doc, attrStepContexts, originalDoc) => {
51
+ return attrStepContexts.map(attrStepContext => {
52
+ const {
53
+ afterNode,
54
+ beforeNode,
55
+ finalPos,
56
+ originalPos,
57
+ step
58
+ } = attrStepContext;
41
59
  if (!(step instanceof AttrStep) && !(step instanceof SetAttrsStep)) {
42
60
  return undefined;
43
61
  }
44
62
  const stepAttrs = getStepAttrs(step);
45
- const $pos = doc.resolve(step.pos);
46
- const nodeAtPos = doc.nodeAt(step.pos);
63
+ // SetAttrsStep contains the complete replacement attrs, not only the attrs that changed.
64
+ // Keep the legacy payload-based checks until the rollout gate is enabled, and fall back
65
+ // to them if either step-time node is unavailable.
66
+ const attrsToCheck = fg('platform_editor_reduce_diff_attr_sensitivity') && beforeNode && afterNode ? stepAttrs.filter(attrName => !isEqual(beforeNode.attrs[attrName], afterNode.attrs[attrName])) : stepAttrs;
67
+ const $pos = doc.resolve(finalPos);
68
+ const nodeAtPos = doc.nodeAt(finalPos);
69
+ const originalNodeAtPos = originalPos === undefined ? null : originalDoc.nodeAt(originalPos);
47
70
 
48
71
  // date node: timestamp attribute change — highlight the date node itself (inline)
49
- if (stepAttrs.some(v => dateAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !isExperimentEnabled('platform_editor_improve_inline_diffs', () => expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true))) {
72
+ if (attrsToCheck.some(v => dateAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !isExperimentEnabled('platform_editor_improve_inline_diffs', () => expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true))) {
50
73
  return {
51
- fromB: step.pos,
52
- toB: step.pos + nodeAtPos.nodeSize,
74
+ fromB: finalPos,
75
+ toB: finalPos + nodeAtPos.nodeSize,
53
76
  isInline: true,
54
77
  inlineNodeName: 'date'
55
78
  };
@@ -62,16 +85,15 @@ export const getAttrChangeRanges = (doc, steps, originalDoc) => {
62
85
  const nodeName = nodeAtPos.type.name;
63
86
  if (isInlineAttrChangeNodeName(nodeName)) {
64
87
  const watchedAttrs = inlineNodeAttrMap[nodeName];
65
- if (stepAttrs.some(v => watchedAttrs.includes(v))) {
66
- const originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
88
+ if (attrsToCheck.some(v => watchedAttrs.includes(v))) {
67
89
  return {
68
- fromB: step.pos,
69
- toB: step.pos + nodeAtPos.nodeSize,
90
+ fromB: finalPos,
91
+ toB: finalPos + nodeAtPos.nodeSize,
70
92
  isInline: true,
71
93
  inlineNodeName: nodeName,
72
- ...(originalNodeAtPos && {
73
- fromA: step.pos,
74
- toA: step.pos + originalNodeAtPos.nodeSize
94
+ ...(originalPos !== undefined && originalNodeAtPos && {
95
+ fromA: originalPos,
96
+ toA: originalPos + originalNodeAtPos.nodeSize
75
97
  })
76
98
  };
77
99
  }
@@ -79,10 +101,10 @@ export const getAttrChangeRanges = (doc, steps, originalDoc) => {
79
101
  }
80
102
 
81
103
  // taskItem node: state attribute change — highlight the taskItem node
82
- if (stepAttrs.some(v => taskItemAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') {
104
+ if (attrsToCheck.some(v => taskItemAttrs.includes(v)) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') {
83
105
  return {
84
- fromB: step.pos,
85
- toB: step.pos + nodeAtPos.nodeSize
106
+ fromB: finalPos,
107
+ toB: finalPos + nodeAtPos.nodeSize
86
108
  };
87
109
  }
88
110
 
@@ -90,30 +112,33 @@ export const getAttrChangeRanges = (doc, steps, originalDoc) => {
90
112
  // (e.g. note -> warning) — highlight the new panel and, when the original node
91
113
  // is resolvable, expose its range (fromA/toA) so the caller can render the old
92
114
  // panel as a "deleted" widget for a before/after comparison.
93
- if (stepAttrs.some(v => panelAttrs.includes(v)) && nodeAtPos && getBaseNodeTypeName(nodeAtPos.type) === 'panel') {
94
- const originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
115
+ if (attrsToCheck.some(v => panelAttrs.includes(v)) && nodeAtPos && getBaseNodeTypeName(nodeAtPos.type) === 'panel') {
95
116
  return {
96
- fromB: step.pos,
97
- toB: step.pos + nodeAtPos.nodeSize,
98
- ...(originalNodeAtPos && {
99
- fromA: step.pos,
100
- toA: step.pos + originalNodeAtPos.nodeSize
117
+ fromB: finalPos,
118
+ toB: finalPos + nodeAtPos.nodeSize,
119
+ ...(originalPos !== undefined && originalNodeAtPos && {
120
+ fromA: originalPos,
121
+ toA: originalPos + originalNodeAtPos.nodeSize
101
122
  })
102
123
  };
103
124
  }
104
125
 
105
- // extension nodes: highlight on any diffable attr change (exclude rule in shared map)
106
- if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && stepAttrs.some(v => isDiffableAttr(nodeAtPos.type.name, v))) {
126
+ // Extension nodes: highlight changes to user-visible configuration. When enabled,
127
+ // transient extension metadata is ignored by the comparison below.
128
+ if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && attrsToCheck.some(v => isDiffableAttr(nodeAtPos.type.name, v))) {
129
+ if (fg('platform_editor_reduce_diff_attr_sensitivity') && beforeNode && afterNode && beforeNode.type === afterNode.type && haveSameRelevantExtensionAttrs(beforeNode, afterNode)) {
130
+ return undefined;
131
+ }
107
132
  const isInline = nodeAtPos.type.name === 'inlineExtension';
108
133
  return {
109
- fromB: step.pos,
110
- toB: step.pos + nodeAtPos.nodeSize,
134
+ fromB: finalPos,
135
+ toB: finalPos + nodeAtPos.nodeSize,
111
136
  isInline
112
137
  };
113
138
  }
114
139
 
115
140
  // media node: id/collection/url attribute change — highlight the mediaSingle parent
116
- if (stepAttrs.some(v => mediaAttrs.includes(v)) && $pos.parent.type === doc.type.schema.nodes.mediaSingle) {
141
+ if (attrsToCheck.some(v => mediaAttrs.includes(v)) && $pos.parent.type === doc.type.schema.nodes.mediaSingle) {
117
142
  const startPos = $pos.pos + $pos.parentOffset;
118
143
  return {
119
144
  fromB: startPos,
@@ -11,6 +11,7 @@ import memoizeOne from 'memoize-one';
11
11
  import { ChangeSet, simplifyChanges } from 'prosemirror-changeset';
12
12
  import { isExperimentEnabled } from '@atlaskit/editor-common/deprecated-platform-feature-experiments';
13
13
  import { areNodesEqualIgnoreAttrs } from '@atlaskit/editor-common/utils/document';
14
+ import { Mapping } from '@atlaskit/editor-prosemirror/transform';
14
15
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
15
16
  import { fg } from '@atlaskit/platform-feature-flags/fg';
16
17
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
@@ -287,7 +288,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
287
288
  } else {
288
289
  simplifiedSteps = simplifySteps(steps, originalDoc);
289
290
  }
290
- var attrSteps = [];
291
+ var pendingAttrSteps = [];
291
292
  var stepMaps = [];
292
293
  var _iterator = _createForOfIteratorHelper(simplifiedSteps),
293
294
  _step;
@@ -297,20 +298,56 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
297
298
  var result = step.apply(steppedDoc);
298
299
  if (result.failed === null && result.doc) {
299
300
  if (stepIsValidAttrChange(step, steppedDoc, result.doc)) {
300
- attrSteps.push(step);
301
+ pendingAttrSteps.push({
302
+ afterNode: result.doc.nodeAt(step.pos),
303
+ beforeNode: steppedDoc.nodeAt(step.pos),
304
+ mapIndex: stepMaps.length,
305
+ step: step
306
+ });
301
307
  }
302
308
  stepMaps.push(step.getMap());
303
309
  steppedDoc = result.doc;
304
310
  }
305
311
  }
306
-
307
- // Rather than using .eq() we use a custom function that only checks for structural
308
- // changes and ignores differences in attributes which don't affect decoration positions
312
+ // Gate the complete attribution fix: mapped positions and step-time nodes are used together.
313
+ // The fallback deliberately preserves the legacy raw-position lookups for rollout safety.
309
314
  } catch (err) {
310
315
  _iterator.e(err);
311
316
  } finally {
312
317
  _iterator.f();
313
318
  }
319
+ var attrStepContexts = fg('platform_editor_reduce_diff_attr_sensitivity') ? pendingAttrSteps.flatMap(function (_ref0) {
320
+ var afterNode = _ref0.afterNode,
321
+ beforeNode = _ref0.beforeNode,
322
+ mapIndex = _ref0.mapIndex,
323
+ step = _ref0.step;
324
+ var finalPosition = new Mapping(stepMaps.slice(mapIndex + 1)).mapResult(step.pos);
325
+ if (finalPosition.deleted) {
326
+ return [];
327
+ }
328
+ var originalPosition = new Mapping(stepMaps.slice(0, mapIndex)).invert().mapResult(step.pos);
329
+ return [_objectSpread(_objectSpread({
330
+ afterNode: afterNode,
331
+ beforeNode: beforeNode,
332
+ finalPos: finalPosition.pos
333
+ }, originalPosition.deleted ? {} : {
334
+ originalPos: originalPosition.pos
335
+ }), {}, {
336
+ step: step
337
+ })];
338
+ }) : pendingAttrSteps.map(function (_ref1) {
339
+ var step = _ref1.step;
340
+ return {
341
+ afterNode: tr.doc.nodeAt(step.pos),
342
+ beforeNode: originalDoc.nodeAt(step.pos),
343
+ finalPos: step.pos,
344
+ originalPos: step.pos,
345
+ step: step
346
+ };
347
+ });
348
+
349
+ // Rather than using .eq() we use a custom function that only checks for structural
350
+ // changes and ignores differences in attributes which don't affect decoration positions
314
351
  if (!areNodesEqualIgnoreAttrs(steppedDoc, tr.doc)) {
315
352
  var _api$analytics;
316
353
  var recoveredViaContentEquality = areDocsEqualByBlockStructureAndText(steppedDoc, tr.doc);
@@ -524,7 +561,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
524
561
  isInserted: true
525
562
  })));
526
563
  });
527
- getAttrChangeRanges(tr.doc, attrSteps, originalDoc).forEach(function (change) {
564
+ getAttrChangeRanges(tr.doc, attrStepContexts, originalDoc).forEach(function (change) {
528
565
  if (change.isInline) {
529
566
  // Inline nodes (e.g. date, emoji, mention, status) need an inline decoration rather than a block decoration
530
567
  var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
@@ -614,42 +651,42 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref7
614
651
  };
615
652
  export var calculateDiffDecorations = memoizeOne(calculateDiffDecorationsInner,
616
653
  // Cache results unless relevant inputs change
617
- function (_ref0, _ref1) {
618
- var _ref13;
619
- var _ref10 = _slicedToArray(_ref0, 1),
620
- _ref10$ = _ref10[0],
621
- pluginState = _ref10$.pluginState,
622
- state = _ref10$.state,
623
- colorScheme = _ref10$.colorScheme,
624
- intl = _ref10$.intl,
625
- activeIndexPos = _ref10$.activeIndexPos,
626
- isInverted = _ref10$.isInverted,
627
- diffType = _ref10$.diffType,
628
- hideDeletedDiffs = _ref10$.hideDeletedDiffs,
629
- hideAddedDiffsUnderline = _ref10$.hideAddedDiffsUnderline,
630
- showIndicators = _ref10$.showIndicators,
631
- smartThresholds = _ref10$.smartThresholds,
632
- deletedDiffPlacement = _ref10$.deletedDiffPlacement,
633
- inlineDeletedDiffPlacement = _ref10$.inlineDeletedDiffPlacement;
634
- var _ref11 = _slicedToArray(_ref1, 1),
635
- _ref11$ = _ref11[0],
636
- lastPluginState = _ref11$.pluginState,
637
- lastState = _ref11$.state,
638
- lastColorScheme = _ref11$.colorScheme,
639
- lastIntl = _ref11$.intl,
640
- lastActiveIndexPos = _ref11$.activeIndexPos,
641
- lastIsInverted = _ref11$.isInverted,
642
- lastDiffType = _ref11$.diffType,
643
- lastHideDeletedDiffs = _ref11$.hideDeletedDiffs,
644
- lastHideAddedDiffsUnderline = _ref11$.hideAddedDiffsUnderline,
645
- lastShowIndicators = _ref11$.showIndicators,
646
- lastSmartThresholds = _ref11$.smartThresholds,
647
- lastDeletedDiffPlacement = _ref11$.deletedDiffPlacement,
648
- lastInlineDeletedDiffPlacement = _ref11$.inlineDeletedDiffPlacement;
654
+ function (_ref10, _ref11) {
655
+ var _ref15;
656
+ var _ref12 = _slicedToArray(_ref10, 1),
657
+ _ref12$ = _ref12[0],
658
+ pluginState = _ref12$.pluginState,
659
+ state = _ref12$.state,
660
+ colorScheme = _ref12$.colorScheme,
661
+ intl = _ref12$.intl,
662
+ activeIndexPos = _ref12$.activeIndexPos,
663
+ isInverted = _ref12$.isInverted,
664
+ diffType = _ref12$.diffType,
665
+ hideDeletedDiffs = _ref12$.hideDeletedDiffs,
666
+ hideAddedDiffsUnderline = _ref12$.hideAddedDiffsUnderline,
667
+ showIndicators = _ref12$.showIndicators,
668
+ smartThresholds = _ref12$.smartThresholds,
669
+ deletedDiffPlacement = _ref12$.deletedDiffPlacement,
670
+ inlineDeletedDiffPlacement = _ref12$.inlineDeletedDiffPlacement;
671
+ var _ref13 = _slicedToArray(_ref11, 1),
672
+ _ref13$ = _ref13[0],
673
+ lastPluginState = _ref13$.pluginState,
674
+ lastState = _ref13$.state,
675
+ lastColorScheme = _ref13$.colorScheme,
676
+ lastIntl = _ref13$.intl,
677
+ lastActiveIndexPos = _ref13$.activeIndexPos,
678
+ lastIsInverted = _ref13$.isInverted,
679
+ lastDiffType = _ref13$.diffType,
680
+ lastHideDeletedDiffs = _ref13$.hideDeletedDiffs,
681
+ lastHideAddedDiffsUnderline = _ref13$.hideAddedDiffsUnderline,
682
+ lastShowIndicators = _ref13$.showIndicators,
683
+ lastSmartThresholds = _ref13$.smartThresholds,
684
+ lastDeletedDiffPlacement = _ref13$.deletedDiffPlacement,
685
+ lastInlineDeletedDiffPlacement = _ref13$.inlineDeletedDiffPlacement;
649
686
  var originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
650
687
  if (isExtendedEnabled(diffType)) {
651
- var _ref12;
652
- return (_ref12 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && isEqual(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref12 !== void 0 ? _ref12 : false;
688
+ var _ref14;
689
+ return (_ref14 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && isEqual(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && isEqual(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref14 !== void 0 ? _ref14 : false;
653
690
  }
654
- return (_ref13 = originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isEqual(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref13 !== void 0 ? _ref13 : false;
691
+ return (_ref15 = originalDocIsSame && isEqual(pluginState.steps, lastPluginState.steps) && isEqual(pluginState.stepAttributions, lastPluginState.stepAttributions) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isEqual(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref15 !== void 0 ? _ref15 : false;
655
692
  });
@@ -1,10 +1,13 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  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; }
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import isEqual from 'lodash/isEqual';
5
+ import omit from 'lodash/omit';
4
6
  import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
5
7
  import { isExperimentEnabled } from '@atlaskit/editor-common/deprecated-platform-feature-experiments';
6
8
  import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
7
9
  import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
10
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
8
11
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
9
12
  import { getRequiredIncludedDiffableAttrs, isDiffableAttr } from './diffableAttrs';
10
13
  var filterUndefined = function filterUndefined(x) {
@@ -34,33 +37,57 @@ var isInlineAttrChangeNodeName = function isInlineAttrChangeNodeName(nodeName) {
34
37
  // Extension node type names. Their "any attr except localId" exclude rule lives
35
38
  // in the shared `diffableAttrs` map and is applied via `isDiffableAttr` below.
36
39
  var extensionNodeNames = ['extension', 'inlineExtension', 'bodiedExtension'];
40
+ var transientExtensionAttrPaths = ['localId', 'parameters.macroParams._parentId'];
41
+
42
+ /**
43
+ * Removes extension metadata that can change between document versions without changing the
44
+ * extension's user-visible configuration.
45
+ */
46
+ var getComparableExtensionAttrs = function getComparableExtensionAttrs(node) {
47
+ return omit(node.attrs, transientExtensionAttrPaths);
48
+ };
49
+ var haveSameRelevantExtensionAttrs = function haveSameRelevantExtensionAttrs(beforeNode, afterNode) {
50
+ return isEqual(getComparableExtensionAttrs(beforeNode), getComparableExtensionAttrs(afterNode));
51
+ };
37
52
  var getStepAttrs = function getStepAttrs(step) {
38
53
  if (step instanceof AttrStep) {
39
54
  return [step.attr];
40
55
  }
41
- if (step instanceof SetAttrsStep && step.attrs) {
56
+ if (step.attrs) {
42
57
  return Object.keys(step.attrs);
43
58
  }
44
59
  return [];
45
60
  };
46
- export var getAttrChangeRanges = function getAttrChangeRanges(doc, steps, originalDoc) {
47
- return steps.map(function (step) {
61
+ export var getAttrChangeRanges = function getAttrChangeRanges(doc, attrStepContexts, originalDoc) {
62
+ return attrStepContexts.map(function (attrStepContext) {
63
+ var afterNode = attrStepContext.afterNode,
64
+ beforeNode = attrStepContext.beforeNode,
65
+ finalPos = attrStepContext.finalPos,
66
+ originalPos = attrStepContext.originalPos,
67
+ step = attrStepContext.step;
48
68
  if (!(step instanceof AttrStep) && !(step instanceof SetAttrsStep)) {
49
69
  return undefined;
50
70
  }
51
71
  var stepAttrs = getStepAttrs(step);
52
- var $pos = doc.resolve(step.pos);
53
- var nodeAtPos = doc.nodeAt(step.pos);
72
+ // SetAttrsStep contains the complete replacement attrs, not only the attrs that changed.
73
+ // Keep the legacy payload-based checks until the rollout gate is enabled, and fall back
74
+ // to them if either step-time node is unavailable.
75
+ var attrsToCheck = fg('platform_editor_reduce_diff_attr_sensitivity') && beforeNode && afterNode ? stepAttrs.filter(function (attrName) {
76
+ return !isEqual(beforeNode.attrs[attrName], afterNode.attrs[attrName]);
77
+ }) : stepAttrs;
78
+ var $pos = doc.resolve(finalPos);
79
+ var nodeAtPos = doc.nodeAt(finalPos);
80
+ var originalNodeAtPos = originalPos === undefined ? null : originalDoc.nodeAt(originalPos);
54
81
 
55
82
  // date node: timestamp attribute change — highlight the date node itself (inline)
56
- if (stepAttrs.some(function (v) {
83
+ if (attrsToCheck.some(function (v) {
57
84
  return dateAttrs.includes(v);
58
85
  }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !isExperimentEnabled('platform_editor_improve_inline_diffs', function () {
59
86
  return expValEquals('platform_editor_improve_inline_diffs', 'isEnabled', true);
60
87
  })) {
61
88
  return {
62
- fromB: step.pos,
63
- toB: step.pos + nodeAtPos.nodeSize,
89
+ fromB: finalPos,
90
+ toB: finalPos + nodeAtPos.nodeSize,
64
91
  isInline: true,
65
92
  inlineNodeName: 'date'
66
93
  };
@@ -75,30 +102,29 @@ export var getAttrChangeRanges = function getAttrChangeRanges(doc, steps, origin
75
102
  var nodeName = nodeAtPos.type.name;
76
103
  if (isInlineAttrChangeNodeName(nodeName)) {
77
104
  var watchedAttrs = inlineNodeAttrMap[nodeName];
78
- if (stepAttrs.some(function (v) {
105
+ if (attrsToCheck.some(function (v) {
79
106
  return watchedAttrs.includes(v);
80
107
  })) {
81
- var originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
82
108
  return _objectSpread({
83
- fromB: step.pos,
84
- toB: step.pos + nodeAtPos.nodeSize,
109
+ fromB: finalPos,
110
+ toB: finalPos + nodeAtPos.nodeSize,
85
111
  isInline: true,
86
112
  inlineNodeName: nodeName
87
- }, originalNodeAtPos && {
88
- fromA: step.pos,
89
- toA: step.pos + originalNodeAtPos.nodeSize
113
+ }, originalPos !== undefined && originalNodeAtPos && {
114
+ fromA: originalPos,
115
+ toA: originalPos + originalNodeAtPos.nodeSize
90
116
  });
91
117
  }
92
118
  }
93
119
  }
94
120
 
95
121
  // taskItem node: state attribute change — highlight the taskItem node
96
- if (stepAttrs.some(function (v) {
122
+ if (attrsToCheck.some(function (v) {
97
123
  return taskItemAttrs.includes(v);
98
124
  }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') {
99
125
  return {
100
- fromB: step.pos,
101
- toB: step.pos + nodeAtPos.nodeSize
126
+ fromB: finalPos,
127
+ toB: finalPos + nodeAtPos.nodeSize
102
128
  };
103
129
  }
104
130
 
@@ -106,33 +132,36 @@ export var getAttrChangeRanges = function getAttrChangeRanges(doc, steps, origin
106
132
  // (e.g. note -> warning) — highlight the new panel and, when the original node
107
133
  // is resolvable, expose its range (fromA/toA) so the caller can render the old
108
134
  // panel as a "deleted" widget for a before/after comparison.
109
- if (stepAttrs.some(function (v) {
135
+ if (attrsToCheck.some(function (v) {
110
136
  return panelAttrs.includes(v);
111
137
  }) && nodeAtPos && getBaseNodeTypeName(nodeAtPos.type) === 'panel') {
112
- var _originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos);
113
138
  return _objectSpread({
114
- fromB: step.pos,
115
- toB: step.pos + nodeAtPos.nodeSize
116
- }, _originalNodeAtPos && {
117
- fromA: step.pos,
118
- toA: step.pos + _originalNodeAtPos.nodeSize
139
+ fromB: finalPos,
140
+ toB: finalPos + nodeAtPos.nodeSize
141
+ }, originalPos !== undefined && originalNodeAtPos && {
142
+ fromA: originalPos,
143
+ toA: originalPos + originalNodeAtPos.nodeSize
119
144
  });
120
145
  }
121
146
 
122
- // extension nodes: highlight on any diffable attr change (exclude rule in shared map)
123
- if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && stepAttrs.some(function (v) {
147
+ // Extension nodes: highlight changes to user-visible configuration. When enabled,
148
+ // transient extension metadata is ignored by the comparison below.
149
+ if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && attrsToCheck.some(function (v) {
124
150
  return isDiffableAttr(nodeAtPos.type.name, v);
125
151
  })) {
152
+ if (fg('platform_editor_reduce_diff_attr_sensitivity') && beforeNode && afterNode && beforeNode.type === afterNode.type && haveSameRelevantExtensionAttrs(beforeNode, afterNode)) {
153
+ return undefined;
154
+ }
126
155
  var isInline = nodeAtPos.type.name === 'inlineExtension';
127
156
  return {
128
- fromB: step.pos,
129
- toB: step.pos + nodeAtPos.nodeSize,
157
+ fromB: finalPos,
158
+ toB: finalPos + nodeAtPos.nodeSize,
130
159
  isInline: isInline
131
160
  };
132
161
  }
133
162
 
134
163
  // media node: id/collection/url attribute change — highlight the mediaSingle parent
135
- if (stepAttrs.some(function (v) {
164
+ if (attrsToCheck.some(function (v) {
136
165
  return mediaAttrs.includes(v);
137
166
  }) && $pos.parent.type === doc.type.schema.nodes.mediaSingle) {
138
167
  var startPos = $pos.pos + $pos.parentOffset;
@@ -1 +1 @@
1
- export type { DeletedDiffPlacement, DeletedDiffWidget, DiffParams, DiffStepAttribution, DiffType, PMDiffParams, ShowDiffPlugin, SmartDiffThresholds, StepWithAttribution, } from '../showDiffPluginType';
1
+ export type { DeletedDiffPlacement, DeletedDiffWidget, DiffParams, DiffStepAttribution, DiffType, PMDiffParams, ShowDiffParams, ShowDiffPlugin, SmartDiffThresholds, StepWithAttribution, } from '../showDiffPluginType';
@@ -1,6 +1,16 @@
1
+ import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
1
2
  import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
2
3
  import type { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform-override';
4
+ import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
3
5
  export type InlineAttrChangeNodeName = 'date' | 'emoji' | 'mention' | 'status';
6
+ type AttrChangeStep = AttrStep | SetAttrsStep;
7
+ export type AttrStepContext = {
8
+ afterNode: PMNode | null;
9
+ beforeNode: PMNode | null;
10
+ finalPos: number;
11
+ originalPos?: number;
12
+ step: AttrChangeStep;
13
+ };
4
14
  type StepRange = {
5
15
  /**
6
16
  * Position of the original (before) node in the original doc.
@@ -16,7 +26,7 @@ type StepRange = {
16
26
  toA?: number;
17
27
  toB: number;
18
28
  };
19
- export declare const getAttrChangeRanges: (doc: PMNode, steps: ProseMirrorStep[], originalDoc: PMNode) => StepRange[];
29
+ export declare const getAttrChangeRanges: (doc: PMNode, attrStepContexts: AttrStepContext[], originalDoc: PMNode) => StepRange[];
20
30
  /**
21
31
  * Check if the step was a valid attr change and affected the doc
22
32
  *
@@ -25,5 +35,5 @@ export declare const getAttrChangeRanges: (doc: PMNode, steps: ProseMirrorStep[]
25
35
  * @param afterDoc Doc after the step
26
36
  * @returns Boolean if the change should show a decoration
27
37
  */
28
- export declare const stepIsValidAttrChange: (step: ProseMirrorStep, beforeDoc: PMNode, afterDoc: PMNode) => boolean;
38
+ export declare const stepIsValidAttrChange: (step: ProseMirrorStep, beforeDoc: PMNode, afterDoc: PMNode) => step is AttrChangeStep;
29
39
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-show-diff",
3
- "version": "14.1.0",
3
+ "version": "14.2.0",
4
4
  "description": "ShowDiff plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -20,7 +20,7 @@
20
20
  "sideEffects": false,
21
21
  "atlaskit:src": "src/index.ts",
22
22
  "dependencies": {
23
- "@atlaskit/adf-schema": "^57.1.0",
23
+ "@atlaskit/adf-schema": "^57.2.0",
24
24
  "@atlaskit/custom-steps": "^1.0.0",
25
25
  "@atlaskit/editor-plugin-analytics": "^16.0.0",
26
26
  "@atlaskit/editor-plugin-user-intent": "^14.0.0",
@@ -28,7 +28,7 @@
28
28
  "@atlaskit/editor-tables": "^3.0.0",
29
29
  "@atlaskit/platform-feature-experiments": "^0.3.0",
30
30
  "@atlaskit/platform-feature-flags": "^2.1.0",
31
- "@atlaskit/tmp-editor-statsig": "^162.0.0",
31
+ "@atlaskit/tmp-editor-statsig": "^163.0.0",
32
32
  "@atlaskit/tokens": "^16.8.0",
33
33
  "@babel/runtime": "^7.0.0",
34
34
  "@compiled/react": "^1.0.2",
@@ -39,9 +39,9 @@
39
39
  "devDependencies": {
40
40
  "@atlaskit/adf-utils": "^20.7.0",
41
41
  "@atlaskit/button": "^25.2.0",
42
- "@atlaskit/css": "^1.0.0",
42
+ "@atlaskit/css": "^1.1.0",
43
43
  "@atlaskit/dropdown-menu": "^18.2.0",
44
- "@atlaskit/editor-core": "^226.0.0",
44
+ "@atlaskit/editor-core": "^226.1.0",
45
45
  "@atlaskit/editor-json-transformer": "^9.6.0",
46
46
  "@atlaskit/editor-plugins": "^16.1.0",
47
47
  "@atlaskit/form": "^17.1.0",
@@ -104,6 +104,9 @@
104
104
  },
105
105
  "confluence_ncs_step_diffing_version_history": {
106
106
  "type": "boolean"
107
+ },
108
+ "platform_editor_reduce_diff_attr_sensitivity": {
109
+ "type": "boolean"
107
110
  }
108
111
  }
109
112
  }