@atlaskit/editor-plugin-show-diff 12.1.2 → 12.1.3

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,13 @@
1
1
  # @atlaskit/editor-plugin-show-diff
2
2
 
3
+ ## 12.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`774c01e2f1cdd`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/774c01e2f1cdd) -
8
+ Remove the `platform_editor_diff_granular_extended` experiment and retain its disabled behavior.
9
+ - Updated dependencies
10
+
3
11
  ## 12.1.2
4
12
 
5
13
  ### Patch Changes
@@ -19,7 +19,6 @@ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
19
19
  var _areDocsEqualByBlockStructureAndText = require("../areDocsEqualByBlockStructureAndText");
20
20
  var _createAnchorDecorationWidgets = require("../decorations/createAnchorDecorationWidgets");
21
21
  var _createBlockChangedDecoration = require("../decorations/createBlockChangedDecoration");
22
- var _createGranularBlockReferenceWidget = require("../decorations/createGranularBlockReferenceWidget");
23
22
  var _createInlineChangedDecoration = require("../decorations/createInlineChangedDecoration");
24
23
  var _createNodeChangedDecorationWidget = require("../decorations/createNodeChangedDecorationWidget");
25
24
  var _decorationKeys = require("../decorations/decorationKeys");
@@ -260,7 +259,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref4
260
259
 
261
260
  // Our default operations are insertions, so it should match the opposite of isInverted.
262
261
  var isInserted = !isInverted;
263
- var createDecorationsForChange = function createDecorationsForChange(change, showGranularWithBlock) {
262
+ var createDecorationsForChange = function createDecorationsForChange(change) {
264
263
  var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
265
264
 
266
265
  // Hoisted because it decides BOTH where the deleted widget is anchored and — since the
@@ -272,10 +271,8 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref4
272
271
  inlineDeletedDiffPlacement: inlineDeletedDiffPlacement
273
272
  });
274
273
  if (change.inserted.length > 0) {
275
- // shouldHideDeleted for block/node decorations: suppressed when isInverted + hideDeletedDiffs,
276
- // or when showGranularWithBlock (block reference widget is shown instead).
277
- // isInverted gates both — on an inverted diff the inserted side is visually the deleted side.
278
- var shouldHideDeleted = (0, _isExtendedEnabled.isExtendedEnabled)(diffType) ? isInverted && (hideDeletedDiffs || showGranularWithBlock && change.deleted.length > 0) : false;
274
+ // On an inverted diff the inserted side is visually the deleted side.
275
+ var shouldHideDeleted = (0, _isExtendedEnabled.isExtendedEnabled)(diffType) ? isInverted && hideDeletedDiffs : false;
279
276
 
280
277
  // For `smart` NODE-level promotions the change range spans a whole container
281
278
  // (e.g. an entire list/table/layout, using outer node bounds). Applying a SINGLE
@@ -292,7 +289,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref4
292
289
  // change. Used to decide if indicator anchor positions should be adjusted
293
290
  // inward — when the widget is present the anchor must stay at the block
294
291
  // boundary to keep the indicator bar continuous with the deleted content.
295
- var willRenderDeletedWidget = change.deleted.length > 0 && !((0, _isExtendedEnabled.isExtendedEnabled)(diffType) && !isInverted && (hideDeletedDiffs || showGranularWithBlock) && change.inserted.length > 0);
292
+ var willRenderDeletedWidget = change.deleted.length > 0 && !((0, _isExtendedEnabled.isExtendedEnabled)(diffType) && !isInverted && hideDeletedDiffs && change.inserted.length > 0);
296
293
  if (isSmartNodeLevel) {
297
294
  var _iterator2 = _createForOfIteratorHelper(leafTextblockRanges(tr.doc, change.fromB, change.toB)),
298
295
  _step2;
@@ -356,7 +353,7 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref4
356
353
  }))));
357
354
  }
358
355
  if (change.deleted.length > 0) {
359
- var _shouldHideDeleted = (0, _isExtendedEnabled.isExtendedEnabled)(diffType) ? !isInverted && (hideDeletedDiffs || showGranularWithBlock) && change.inserted.length > 0 : false;
356
+ var _shouldHideDeleted = (0, _isExtendedEnabled.isExtendedEnabled)(diffType) ? !isInverted && hideDeletedDiffs && change.inserted.length > 0 : false;
360
357
  if (!_shouldHideDeleted) {
361
358
  decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createNodeChangedDecorationWidget.createNodeChangedDecorationWidget)(_objectSpread(_objectSpread({
362
359
  change: change,
@@ -377,88 +374,9 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref4
377
374
  }
378
375
  }
379
376
  };
380
- if (diffType === 'step' && (0, _expValEquals.expValEquals)('platform_editor_diff_granular_extended', 'isEnabled', true)) {
381
- // Uses getStepChanges instead of getChanges so that we have per-step granularity metadata.
382
- // Specifically, we need to know how many granular changes each step produced in order to
383
- // apply the shouldHideDeleted suppression threshold (> 3 granular changes per step).
384
- // getChanges returns a flat Change[] with no per-step grouping, making this count impossible
385
- // to derive after the fact without re-introducing per-change metadata.
386
- var stepChanges = (0, _diffBySteps.getStepChanges)(originalDoc, steps);
387
- stepChanges.forEach(function (_ref5) {
388
- var isGranular = _ref5.isGranular,
389
- stepChangeList = _ref5.changes;
390
- var granularCount = isGranular ? stepChangeList.length : 0;
391
-
392
- // Calculate the average ratio of changed content on both A (original) and B (new)
393
- // sides of the diff. If 30% or more of the block has changed on average, we show
394
- // the block reference widget even if the granular change count is below the threshold.
395
- // Block length is derived from the enclosing text block boundaries rather than the
396
- // first/last change positions, so unchanged words at the start/end are accounted for.
397
- var avgChangedRatio = 0;
398
- if (isGranular && stepChangeList.length > 0) {
399
- var first = stepChangeList[0];
400
- var last = stepChangeList[stepChangeList.length - 1];
401
- var resolvedA = originalDoc.resolve(first.fromA);
402
- var resolvedB = tr.doc.resolve(first.fromB);
403
- var blockStartA = first.fromA;
404
- var blockEndA = last.toA;
405
- var blockStartB = first.fromB;
406
- var blockEndB = last.toB;
407
- for (var depth = resolvedA.depth; depth >= 0; depth--) {
408
- var node = resolvedA.node(depth);
409
- if (node.isTextblock) {
410
- blockStartA = resolvedA.start(depth);
411
- blockEndA = blockStartA + node.nodeSize - 2; // exclude open/close tokens
412
- break;
413
- }
414
- }
415
- for (var _depth = resolvedB.depth; _depth >= 0; _depth--) {
416
- var _node = resolvedB.node(_depth);
417
- if (_node.isTextblock) {
418
- blockStartB = resolvedB.start(_depth);
419
- blockEndB = blockStartB + _node.nodeSize - 2; // exclude open/close tokens
420
- break;
421
- }
422
- }
423
- var blockLengthA = blockEndA - blockStartA;
424
- var blockLengthB = blockEndB - blockStartB;
425
- var totalChangedA = stepChangeList.reduce(function (sum, c) {
426
- return sum + (c.toA - c.fromA);
427
- }, 0);
428
- var totalChangedB = stepChangeList.reduce(function (sum, c) {
429
- return sum + (c.toB - c.fromB);
430
- }, 0);
431
- var ratioA = blockLengthA > 0 ? totalChangedA / blockLengthA : 0;
432
- var ratioB = blockLengthB > 0 ? totalChangedB / blockLengthB : 0;
433
- avgChangedRatio = (ratioA + ratioB) / 2;
434
- }
435
- var showGranularWithBlock = isGranular && granularCount !== 1 && (granularCount > 3 || avgChangedRatio >= 0.3);
436
- stepChangeList.forEach(function (change) {
437
- createDecorationsForChange(change, showGranularWithBlock);
438
- });
439
- if (showGranularWithBlock && stepChangeList.length > 0 && !hideDeletedDiffs) {
440
- var lastChange = stepChangeList[stepChangeList.length - 1];
441
- var granularBlockDiffId = crypto.randomUUID();
442
- var blockWidgets = (0, _createGranularBlockReferenceWidget.createGranularBlockReferenceWidget)({
443
- change: lastChange,
444
- originalDoc: originalDoc,
445
- newDoc: tr.doc,
446
- isInverted: isInverted,
447
- nodeViewSerializer: nodeViewSerializer,
448
- colorScheme: colorScheme,
449
- intl: intl,
450
- activeIndexPos: activeIndexPos,
451
- diffId: granularBlockDiffId,
452
- showIndicators: showIndicators
453
- });
454
- decorations.push.apply(decorations, (0, _toConsumableArray2.default)(blockWidgets));
455
- }
456
- });
457
- } else {
458
- changes.forEach(function (change) {
459
- createDecorationsForChange(change, /* showGranularWithBlock */false);
460
- });
461
- }
377
+ changes.forEach(function (change) {
378
+ createDecorationsForChange(change);
379
+ });
462
380
  (0, _getMarkChangeRanges.getMarkChangeRanges)(steps).forEach(function (change) {
463
381
  var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
464
382
  decorations.push.apply(decorations, (0, _toConsumableArray2.default)((0, _createInlineChangedDecoration.createInlineChangedDecoration)({
@@ -530,42 +448,42 @@ var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref4
530
448
  };
531
449
  var calculateDiffDecorations = exports.calculateDiffDecorations = (0, _memoizeOne.default)(calculateDiffDecorationsInner,
532
450
  // Cache results unless relevant inputs change
533
- function (_ref6, _ref7) {
534
- var _ref1;
451
+ function (_ref5, _ref6) {
452
+ var _ref0;
453
+ var _ref7 = (0, _slicedToArray2.default)(_ref5, 1),
454
+ _ref7$ = _ref7[0],
455
+ pluginState = _ref7$.pluginState,
456
+ state = _ref7$.state,
457
+ colorScheme = _ref7$.colorScheme,
458
+ intl = _ref7$.intl,
459
+ activeIndexPos = _ref7$.activeIndexPos,
460
+ isInverted = _ref7$.isInverted,
461
+ diffType = _ref7$.diffType,
462
+ hideDeletedDiffs = _ref7$.hideDeletedDiffs,
463
+ hideAddedDiffsUnderline = _ref7$.hideAddedDiffsUnderline,
464
+ showIndicators = _ref7$.showIndicators,
465
+ smartThresholds = _ref7$.smartThresholds,
466
+ deletedDiffPlacement = _ref7$.deletedDiffPlacement,
467
+ inlineDeletedDiffPlacement = _ref7$.inlineDeletedDiffPlacement;
535
468
  var _ref8 = (0, _slicedToArray2.default)(_ref6, 1),
536
469
  _ref8$ = _ref8[0],
537
- pluginState = _ref8$.pluginState,
538
- state = _ref8$.state,
539
- colorScheme = _ref8$.colorScheme,
540
- intl = _ref8$.intl,
541
- activeIndexPos = _ref8$.activeIndexPos,
542
- isInverted = _ref8$.isInverted,
543
- diffType = _ref8$.diffType,
544
- hideDeletedDiffs = _ref8$.hideDeletedDiffs,
545
- hideAddedDiffsUnderline = _ref8$.hideAddedDiffsUnderline,
546
- showIndicators = _ref8$.showIndicators,
547
- smartThresholds = _ref8$.smartThresholds,
548
- deletedDiffPlacement = _ref8$.deletedDiffPlacement,
549
- inlineDeletedDiffPlacement = _ref8$.inlineDeletedDiffPlacement;
550
- var _ref9 = (0, _slicedToArray2.default)(_ref7, 1),
551
- _ref9$ = _ref9[0],
552
- lastPluginState = _ref9$.pluginState,
553
- lastState = _ref9$.state,
554
- lastColorScheme = _ref9$.colorScheme,
555
- lastIntl = _ref9$.intl,
556
- lastActiveIndexPos = _ref9$.activeIndexPos,
557
- lastIsInverted = _ref9$.isInverted,
558
- lastDiffType = _ref9$.diffType,
559
- lastHideDeletedDiffs = _ref9$.hideDeletedDiffs,
560
- lastHideAddedDiffsUnderline = _ref9$.hideAddedDiffsUnderline,
561
- lastShowIndicators = _ref9$.showIndicators,
562
- lastSmartThresholds = _ref9$.smartThresholds,
563
- lastDeletedDiffPlacement = _ref9$.deletedDiffPlacement,
564
- lastInlineDeletedDiffPlacement = _ref9$.inlineDeletedDiffPlacement;
470
+ lastPluginState = _ref8$.pluginState,
471
+ lastState = _ref8$.state,
472
+ lastColorScheme = _ref8$.colorScheme,
473
+ lastIntl = _ref8$.intl,
474
+ lastActiveIndexPos = _ref8$.activeIndexPos,
475
+ lastIsInverted = _ref8$.isInverted,
476
+ lastDiffType = _ref8$.diffType,
477
+ lastHideDeletedDiffs = _ref8$.hideDeletedDiffs,
478
+ lastHideAddedDiffsUnderline = _ref8$.hideAddedDiffsUnderline,
479
+ lastShowIndicators = _ref8$.showIndicators,
480
+ lastSmartThresholds = _ref8$.smartThresholds,
481
+ lastDeletedDiffPlacement = _ref8$.deletedDiffPlacement,
482
+ lastInlineDeletedDiffPlacement = _ref8$.inlineDeletedDiffPlacement;
565
483
  var originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc);
566
484
  if ((0, _isExtendedEnabled.isExtendedEnabled)(diffType)) {
567
- var _ref0;
568
- return (_ref0 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && (0, _isEqual.default)(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref0 !== void 0 ? _ref0 : false;
485
+ var _ref9;
486
+ return (_ref9 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && hideDeletedDiffs === lastHideDeletedDiffs && hideAddedDiffsUnderline === lastHideAddedDiffsUnderline && showIndicators === lastShowIndicators && (0, _isEqual.default)(smartThresholds, lastSmartThresholds) && deletedDiffPlacement === lastDeletedDiffPlacement && inlineDeletedDiffPlacement === lastInlineDeletedDiffPlacement) !== null && _ref9 !== void 0 ? _ref9 : false;
569
487
  }
570
- return (_ref1 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref1 !== void 0 ? _ref1 : false;
488
+ return (_ref0 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && hideDeletedDiffs === lastHideDeletedDiffs) !== null && _ref0 !== void 0 ? _ref0 : false;
571
489
  });
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.getStepChanges = exports.diffBySteps = void 0;
7
+ exports.diffBySteps = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
10
  var _prosemirrorChangeset = require("prosemirror-changeset");
@@ -407,127 +407,4 @@ var diffBySteps = exports.diffBySteps = function diffBySteps(originalDoc, steps)
407
407
  });
408
408
  }
409
409
  return mergeOverlappingByNewDocRange(changes);
410
- };
411
-
412
- /**
413
- * A fork of `diffBySteps` that returns changes grouped per step, rather than as a flat list.
414
- *
415
- * Why forked rather than refactoring `diffBySteps`:
416
- * - `diffBySteps` returns a flat `Change[]` and is consumed by the existing decoration path.
417
- * Changing its return shape would require threading per-step metadata through all callers,
418
- * adding complexity to a stable code path.
419
- * - The per-step grouping is only needed for the `platform_editor_diff_granular_extended` gate,
420
- * where we need to know how many granular changes a single step produced in order to decide
421
- * whether to suppress deleted decorations (threshold: > 3 granular changes per step).
422
- * - Keeping the two functions separate means each has a clear, focused contract and neither
423
- * accumulates the other's concerns. Shared logic (mapping helpers, `mergeOverlappingByNewDocRange`,
424
- * `shouldCheckGranularDiff`, etc.) is already extracted and reused by both.
425
- */
426
- var getStepChanges = exports.getStepChanges = function getStepChanges(originalDoc, steps) {
427
- var result = [];
428
- var currentDoc = originalDoc;
429
- var successfulStepMaps = [];
430
- var rangedSteps = [];
431
- var _iterator4 = _createForOfIteratorHelper(steps),
432
- _step4;
433
- try {
434
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
435
- var step = _step4.value;
436
- var before = currentDoc;
437
- var stepResult = step.apply(currentDoc);
438
- if (stepResult.failed !== null || !stepResult.doc) {
439
- continue;
440
- }
441
- var stepMap = step.getMap();
442
- var rangeStep = step;
443
- if (typeof rangeStep.from === 'number' && typeof rangeStep.to === 'number') {
444
- rangedSteps.push({
445
- before: before,
446
- doc: stepResult.doc,
447
- from: rangeStep.from,
448
- to: rangeStep.to,
449
- mapIndex: successfulStepMaps.length,
450
- step: step,
451
- stepMap: stepMap
452
- });
453
- }
454
- successfulStepMaps.push(stepMap);
455
- currentDoc = stepResult.doc;
456
- }
457
- } catch (err) {
458
- _iterator4.e(err);
459
- } finally {
460
- _iterator4.f();
461
- }
462
- for (var _i2 = 0, _rangedSteps2 = rangedSteps; _i2 < _rangedSteps2.length; _i2++) {
463
- var rangedStep = _rangedSteps2[_i2];
464
- var originalToBeforeStep = createMapping(successfulStepMaps.slice(0, rangedStep.mapIndex));
465
- var beforeStepToOriginal = originalToBeforeStep.invert();
466
- var fromA = mapPosition(beforeStepToOriginal, rangedStep.from);
467
- var toA = mapPosition(beforeStepToOriginal, rangedStep.to);
468
- var fromAfterStep = rangedStep.stepMap.map(rangedStep.from, -1);
469
- var toAfterStep = rangedStep.stepMap.map(rangedStep.to, 1);
470
- var afterStepToFinal = createMapping(successfulStepMaps.slice(rangedStep.mapIndex + 1));
471
- var fromB = mapPosition(afterStepToFinal, fromAfterStep);
472
- var toB = mapPosition(afterStepToFinal, toAfterStep);
473
- if (shouldCheckGranularDiff(rangedStep.step, rangedStep.before, rangedStep.from, rangedStep.to)) {
474
- var granularStepChanges = _prosemirrorChangeset.ChangeSet.create(rangedStep.before).addSteps(rangedStep.doc, [rangedStep.stepMap], null);
475
- var optimizedGranularStepChanges = (0, _optimizeChanges.optimizeChanges)((0, _prosemirrorChangeset.simplifyChanges)(granularStepChanges.changes, rangedStep.doc));
476
- var stepChanges = [];
477
- var _iterator5 = _createForOfIteratorHelper(optimizedGranularStepChanges),
478
- _step5;
479
- try {
480
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
481
- var granularChange = _step5.value;
482
- var expandedA = expandToWordBoundaries(rangedStep.before, granularChange.fromA, granularChange.toA);
483
- var expandedB = expandToWordBoundaries(rangedStep.doc, granularChange.fromB, granularChange.toB);
484
- var aLeftDelta = granularChange.fromA - expandedA.from;
485
- var aRightDelta = expandedA.to - granularChange.toA;
486
- var bLeftDelta = granularChange.fromB - expandedB.from;
487
- var bRightDelta = expandedB.to - granularChange.toB;
488
- var finalA = expandedA;
489
- var finalB = expandedB;
490
- if (aLeftDelta > bLeftDelta || aRightDelta > bRightDelta) {
491
- var extraLeft = Math.max(0, aLeftDelta - bLeftDelta);
492
- var extraRight = Math.max(0, aRightDelta - bRightDelta);
493
- finalB = expandToWordBoundaries(rangedStep.doc, Math.max(expandedB.from - extraLeft, 0), expandedB.to + extraRight);
494
- }
495
- if (bLeftDelta > aLeftDelta || bRightDelta > aRightDelta) {
496
- var _extraLeft2 = Math.max(0, bLeftDelta - aLeftDelta);
497
- var _extraRight2 = Math.max(0, bRightDelta - aRightDelta);
498
- finalA = expandToWordBoundaries(rangedStep.before, Math.max(expandedA.from - _extraLeft2, 0), expandedA.to + _extraRight2);
499
- }
500
- stepChanges.push({
501
- fromA: mapPosition(beforeStepToOriginal, finalA.from),
502
- toA: mapPosition(beforeStepToOriginal, finalA.to),
503
- fromB: mapPosition(afterStepToFinal, finalB.from),
504
- toB: mapPosition(afterStepToFinal, finalB.to),
505
- deleted: createSpans(Math.max(0, finalA.to - finalA.from)),
506
- inserted: createSpans(Math.max(0, finalB.to - finalB.from))
507
- });
508
- }
509
- } catch (err) {
510
- _iterator5.e(err);
511
- } finally {
512
- _iterator5.f();
513
- }
514
- result.push({
515
- isGranular: true,
516
- changes: mergeOverlappingByNewDocRange(stepChanges)
517
- });
518
- continue;
519
- }
520
- result.push({
521
- isGranular: false,
522
- changes: [{
523
- fromA: fromA,
524
- toA: toA,
525
- fromB: fromB,
526
- toB: toB,
527
- deleted: createSpans(Math.max(0, toA - fromA)),
528
- inserted: createSpans(Math.max(0, toB - fromB))
529
- }]
530
- });
531
- }
532
- return result;
533
410
  };
@@ -10,14 +10,13 @@ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
10
10
  import { areDocsEqualByBlockStructureAndText } from '../areDocsEqualByBlockStructureAndText';
11
11
  import { createDocMarginAnchorWidget } from '../decorations/createAnchorDecorationWidgets';
12
12
  import { createBlockChangedDecoration } from '../decorations/createBlockChangedDecoration';
13
- import { createGranularBlockReferenceWidget } from '../decorations/createGranularBlockReferenceWidget';
14
13
  import { createInlineChangedDecoration } from '../decorations/createInlineChangedDecoration';
15
14
  import { createNodeChangedDecorationWidget } from '../decorations/createNodeChangedDecorationWidget';
16
15
  import { extractDiffDescriptors } from '../decorations/decorationKeys';
17
16
  import { getAttrChangeRanges, stepIsValidAttrChange } from '../decorations/utils/getAttrChangeRanges';
18
17
  import { getMarkChangeRanges } from '../decorations/utils/getMarkChangeRanges';
19
18
  import { isExtendedEnabled } from '../isExtendedEnabled';
20
- import { diffBySteps, getStepChanges } from './diffBySteps';
19
+ import { diffBySteps } from './diffBySteps';
21
20
  import { groupChangesByBlock } from './groupChangesByBlock';
22
21
  import { optimizeChanges } from './optimizeChanges';
23
22
  import { simplifySteps } from './simplifySteps';
@@ -235,7 +234,7 @@ const calculateDiffDecorationsInner = ({
235
234
 
236
235
  // Our default operations are insertions, so it should match the opposite of isInverted.
237
236
  const isInserted = !isInverted;
238
- const createDecorationsForChange = (change, showGranularWithBlock) => {
237
+ const createDecorationsForChange = change => {
239
238
  const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
240
239
 
241
240
  // Hoisted because it decides BOTH where the deleted widget is anchored and — since the
@@ -247,10 +246,8 @@ const calculateDiffDecorationsInner = ({
247
246
  inlineDeletedDiffPlacement
248
247
  });
249
248
  if (change.inserted.length > 0) {
250
- // shouldHideDeleted for block/node decorations: suppressed when isInverted + hideDeletedDiffs,
251
- // or when showGranularWithBlock (block reference widget is shown instead).
252
- // isInverted gates both — on an inverted diff the inserted side is visually the deleted side.
253
- const shouldHideDeleted = isExtendedEnabled(diffType) ? isInverted && (hideDeletedDiffs || showGranularWithBlock && change.deleted.length > 0) : false;
249
+ // On an inverted diff the inserted side is visually the deleted side.
250
+ const shouldHideDeleted = isExtendedEnabled(diffType) ? isInverted && hideDeletedDiffs : false;
254
251
 
255
252
  // For `smart` NODE-level promotions the change range spans a whole container
256
253
  // (e.g. an entire list/table/layout, using outer node bounds). Applying a SINGLE
@@ -267,7 +264,7 @@ const calculateDiffDecorationsInner = ({
267
264
  // change. Used to decide if indicator anchor positions should be adjusted
268
265
  // inward — when the widget is present the anchor must stay at the block
269
266
  // boundary to keep the indicator bar continuous with the deleted content.
270
- const willRenderDeletedWidget = change.deleted.length > 0 && !(isExtendedEnabled(diffType) && !isInverted && (hideDeletedDiffs || showGranularWithBlock) && change.inserted.length > 0);
267
+ const willRenderDeletedWidget = change.deleted.length > 0 && !(isExtendedEnabled(diffType) && !isInverted && hideDeletedDiffs && change.inserted.length > 0);
271
268
  if (isSmartNodeLevel) {
272
269
  for (const [from, to] of leafTextblockRanges(tr.doc, change.fromB, change.toB)) {
273
270
  decorations.push(...createInlineChangedDecoration({
@@ -322,7 +319,7 @@ const calculateDiffDecorationsInner = ({
322
319
  }));
323
320
  }
324
321
  if (change.deleted.length > 0) {
325
- const shouldHideDeleted = isExtendedEnabled(diffType) ? !isInverted && (hideDeletedDiffs || showGranularWithBlock) && change.inserted.length > 0 : false;
322
+ const shouldHideDeleted = isExtendedEnabled(diffType) ? !isInverted && hideDeletedDiffs && change.inserted.length > 0 : false;
326
323
  if (!shouldHideDeleted) {
327
324
  decorations.push(...createNodeChangedDecorationWidget({
328
325
  change,
@@ -343,85 +340,9 @@ const calculateDiffDecorationsInner = ({
343
340
  }
344
341
  }
345
342
  };
346
- if (diffType === 'step' && expValEquals('platform_editor_diff_granular_extended', 'isEnabled', true)) {
347
- // Uses getStepChanges instead of getChanges so that we have per-step granularity metadata.
348
- // Specifically, we need to know how many granular changes each step produced in order to
349
- // apply the shouldHideDeleted suppression threshold (> 3 granular changes per step).
350
- // getChanges returns a flat Change[] with no per-step grouping, making this count impossible
351
- // to derive after the fact without re-introducing per-change metadata.
352
- const stepChanges = getStepChanges(originalDoc, steps);
353
- stepChanges.forEach(({
354
- isGranular,
355
- changes: stepChangeList
356
- }) => {
357
- const granularCount = isGranular ? stepChangeList.length : 0;
358
-
359
- // Calculate the average ratio of changed content on both A (original) and B (new)
360
- // sides of the diff. If 30% or more of the block has changed on average, we show
361
- // the block reference widget even if the granular change count is below the threshold.
362
- // Block length is derived from the enclosing text block boundaries rather than the
363
- // first/last change positions, so unchanged words at the start/end are accounted for.
364
- let avgChangedRatio = 0;
365
- if (isGranular && stepChangeList.length > 0) {
366
- const first = stepChangeList[0];
367
- const last = stepChangeList[stepChangeList.length - 1];
368
- const resolvedA = originalDoc.resolve(first.fromA);
369
- const resolvedB = tr.doc.resolve(first.fromB);
370
- let blockStartA = first.fromA;
371
- let blockEndA = last.toA;
372
- let blockStartB = first.fromB;
373
- let blockEndB = last.toB;
374
- for (let depth = resolvedA.depth; depth >= 0; depth--) {
375
- const node = resolvedA.node(depth);
376
- if (node.isTextblock) {
377
- blockStartA = resolvedA.start(depth);
378
- blockEndA = blockStartA + node.nodeSize - 2; // exclude open/close tokens
379
- break;
380
- }
381
- }
382
- for (let depth = resolvedB.depth; depth >= 0; depth--) {
383
- const node = resolvedB.node(depth);
384
- if (node.isTextblock) {
385
- blockStartB = resolvedB.start(depth);
386
- blockEndB = blockStartB + node.nodeSize - 2; // exclude open/close tokens
387
- break;
388
- }
389
- }
390
- const blockLengthA = blockEndA - blockStartA;
391
- const blockLengthB = blockEndB - blockStartB;
392
- const totalChangedA = stepChangeList.reduce((sum, c) => sum + (c.toA - c.fromA), 0);
393
- const totalChangedB = stepChangeList.reduce((sum, c) => sum + (c.toB - c.fromB), 0);
394
- const ratioA = blockLengthA > 0 ? totalChangedA / blockLengthA : 0;
395
- const ratioB = blockLengthB > 0 ? totalChangedB / blockLengthB : 0;
396
- avgChangedRatio = (ratioA + ratioB) / 2;
397
- }
398
- const showGranularWithBlock = isGranular && granularCount !== 1 && (granularCount > 3 || avgChangedRatio >= 0.3);
399
- stepChangeList.forEach(change => {
400
- createDecorationsForChange(change, showGranularWithBlock);
401
- });
402
- if (showGranularWithBlock && stepChangeList.length > 0 && !hideDeletedDiffs) {
403
- const lastChange = stepChangeList[stepChangeList.length - 1];
404
- const granularBlockDiffId = crypto.randomUUID();
405
- const blockWidgets = createGranularBlockReferenceWidget({
406
- change: lastChange,
407
- originalDoc,
408
- newDoc: tr.doc,
409
- isInverted,
410
- nodeViewSerializer,
411
- colorScheme,
412
- intl,
413
- activeIndexPos,
414
- diffId: granularBlockDiffId,
415
- showIndicators
416
- });
417
- decorations.push(...blockWidgets);
418
- }
419
- });
420
- } else {
421
- changes.forEach(change => {
422
- createDecorationsForChange(change, /* showGranularWithBlock */false);
423
- });
424
- }
343
+ changes.forEach(change => {
344
+ createDecorationsForChange(change);
345
+ });
425
346
  getMarkChangeRanges(steps).forEach(change => {
426
347
  const isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to;
427
348
  decorations.push(...createInlineChangedDecoration({
@@ -362,108 +362,4 @@ export const diffBySteps = (originalDoc, steps) => {
362
362
  });
363
363
  }
364
364
  return mergeOverlappingByNewDocRange(changes);
365
- };
366
-
367
- /**
368
- * A fork of `diffBySteps` that returns changes grouped per step, rather than as a flat list.
369
- *
370
- * Why forked rather than refactoring `diffBySteps`:
371
- * - `diffBySteps` returns a flat `Change[]` and is consumed by the existing decoration path.
372
- * Changing its return shape would require threading per-step metadata through all callers,
373
- * adding complexity to a stable code path.
374
- * - The per-step grouping is only needed for the `platform_editor_diff_granular_extended` gate,
375
- * where we need to know how many granular changes a single step produced in order to decide
376
- * whether to suppress deleted decorations (threshold: > 3 granular changes per step).
377
- * - Keeping the two functions separate means each has a clear, focused contract and neither
378
- * accumulates the other's concerns. Shared logic (mapping helpers, `mergeOverlappingByNewDocRange`,
379
- * `shouldCheckGranularDiff`, etc.) is already extracted and reused by both.
380
- */
381
- export const getStepChanges = (originalDoc, steps) => {
382
- const result = [];
383
- let currentDoc = originalDoc;
384
- const successfulStepMaps = [];
385
- const rangedSteps = [];
386
- for (const step of steps) {
387
- const before = currentDoc;
388
- const stepResult = step.apply(currentDoc);
389
- if (stepResult.failed !== null || !stepResult.doc) {
390
- continue;
391
- }
392
- const stepMap = step.getMap();
393
- const rangeStep = step;
394
- if (typeof rangeStep.from === 'number' && typeof rangeStep.to === 'number') {
395
- rangedSteps.push({
396
- before,
397
- doc: stepResult.doc,
398
- from: rangeStep.from,
399
- to: rangeStep.to,
400
- mapIndex: successfulStepMaps.length,
401
- step,
402
- stepMap
403
- });
404
- }
405
- successfulStepMaps.push(stepMap);
406
- currentDoc = stepResult.doc;
407
- }
408
- for (const rangedStep of rangedSteps) {
409
- const originalToBeforeStep = createMapping(successfulStepMaps.slice(0, rangedStep.mapIndex));
410
- const beforeStepToOriginal = originalToBeforeStep.invert();
411
- const fromA = mapPosition(beforeStepToOriginal, rangedStep.from);
412
- const toA = mapPosition(beforeStepToOriginal, rangedStep.to);
413
- const fromAfterStep = rangedStep.stepMap.map(rangedStep.from, -1);
414
- const toAfterStep = rangedStep.stepMap.map(rangedStep.to, 1);
415
- const afterStepToFinal = createMapping(successfulStepMaps.slice(rangedStep.mapIndex + 1));
416
- const fromB = mapPosition(afterStepToFinal, fromAfterStep);
417
- const toB = mapPosition(afterStepToFinal, toAfterStep);
418
- if (shouldCheckGranularDiff(rangedStep.step, rangedStep.before, rangedStep.from, rangedStep.to)) {
419
- const granularStepChanges = ChangeSet.create(rangedStep.before).addSteps(rangedStep.doc, [rangedStep.stepMap], null);
420
- const optimizedGranularStepChanges = optimizeChanges(simplifyChanges(granularStepChanges.changes, rangedStep.doc));
421
- const stepChanges = [];
422
- for (const granularChange of optimizedGranularStepChanges) {
423
- const expandedA = expandToWordBoundaries(rangedStep.before, granularChange.fromA, granularChange.toA);
424
- const expandedB = expandToWordBoundaries(rangedStep.doc, granularChange.fromB, granularChange.toB);
425
- const aLeftDelta = granularChange.fromA - expandedA.from;
426
- const aRightDelta = expandedA.to - granularChange.toA;
427
- const bLeftDelta = granularChange.fromB - expandedB.from;
428
- const bRightDelta = expandedB.to - granularChange.toB;
429
- let finalA = expandedA;
430
- let finalB = expandedB;
431
- if (aLeftDelta > bLeftDelta || aRightDelta > bRightDelta) {
432
- const extraLeft = Math.max(0, aLeftDelta - bLeftDelta);
433
- const extraRight = Math.max(0, aRightDelta - bRightDelta);
434
- finalB = expandToWordBoundaries(rangedStep.doc, Math.max(expandedB.from - extraLeft, 0), expandedB.to + extraRight);
435
- }
436
- if (bLeftDelta > aLeftDelta || bRightDelta > aRightDelta) {
437
- const extraLeft = Math.max(0, bLeftDelta - aLeftDelta);
438
- const extraRight = Math.max(0, bRightDelta - aRightDelta);
439
- finalA = expandToWordBoundaries(rangedStep.before, Math.max(expandedA.from - extraLeft, 0), expandedA.to + extraRight);
440
- }
441
- stepChanges.push({
442
- fromA: mapPosition(beforeStepToOriginal, finalA.from),
443
- toA: mapPosition(beforeStepToOriginal, finalA.to),
444
- fromB: mapPosition(afterStepToFinal, finalB.from),
445
- toB: mapPosition(afterStepToFinal, finalB.to),
446
- deleted: createSpans(Math.max(0, finalA.to - finalA.from)),
447
- inserted: createSpans(Math.max(0, finalB.to - finalB.from))
448
- });
449
- }
450
- result.push({
451
- isGranular: true,
452
- changes: mergeOverlappingByNewDocRange(stepChanges)
453
- });
454
- continue;
455
- }
456
- result.push({
457
- isGranular: false,
458
- changes: [{
459
- fromA,
460
- toA,
461
- fromB,
462
- toB,
463
- deleted: createSpans(Math.max(0, toA - fromA)),
464
- inserted: createSpans(Math.max(0, toB - fromB))
465
- }]
466
- });
467
- }
468
- return result;
469
365
  };