@atlaskit/editor-plugin-local-id 13.0.3 → 13.1.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,17 @@
1
1
  # @atlaskit/editor-plugin-local-id
2
2
 
3
+ ## 13.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`bbd0908b16b23`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bbd0908b16b23) -
8
+ Under `platform_editor_local_id_reliability`, improve local ID reliability by validating blank IDs
9
+ and rescanning the document before Rovo reads it.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
3
15
  ## 13.0.3
4
16
 
5
17
  ### Patch Changes
@@ -32,6 +32,9 @@
32
32
  {
33
33
  "path": "../../editor-prosemirror/afm-cc/tsconfig.json"
34
34
  },
35
+ {
36
+ "path": "../../../platform/feature-experiments/afm-cc/tsconfig.json"
37
+ },
35
38
  {
36
39
  "path": "../../../platform/feature-flags/afm-cc/tsconfig.json"
37
40
  },
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.addMissingLocalIds = void 0;
7
+ var _addMissingLocalIds = require("../pm-plugins/add-missing-local-ids");
8
+ /**
9
+ * Scans the current document and adds missing local IDs.
10
+ */
11
+ var addMissingLocalIds = exports.addMissingLocalIds = function addMissingLocalIds() {
12
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
13
+ return function (_ref) {
14
+ var tr = _ref.tr;
15
+ if (!(0, _addMissingLocalIds.addMissingLocalIdsToDocument)(tr, options)) {
16
+ return null;
17
+ }
18
+ return tr;
19
+ };
20
+ };
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.localIdPlugin = void 0;
7
7
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
8
8
  var _editorActions = require("./editor-actions");
9
+ var _editorCommands = require("./editor-commands");
9
10
  var _main = require("./pm-plugins/main");
10
11
  var _watchmen = require("./pm-plugins/watchmen");
11
12
  var localIdPlugin = exports.localIdPlugin = function localIdPlugin(_ref) {
@@ -16,6 +17,9 @@ var localIdPlugin = exports.localIdPlugin = function localIdPlugin(_ref) {
16
17
  replaceNode: (0, _editorActions.replaceNode)(api),
17
18
  getNode: (0, _editorActions.getNode)(api)
18
19
  },
20
+ commands: {
21
+ addMissingLocalIds: _editorCommands.addMissingLocalIds
22
+ },
19
23
  pmPlugins: function pmPlugins() {
20
24
  return [{
21
25
  name: 'localIdPlugin',
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.localIdNotEmpty = exports.batchAddLocalIdToNodes = exports.addMissingLocalIdsToDocument = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _steps = require("@atlaskit/adf-schema/steps");
10
+ var _collab = require("@atlaskit/editor-common/collab");
11
+ var _generateShortUUID = require("./generateShortUUID");
12
+ var localIdNotEmpty = exports.localIdNotEmpty = function localIdNotEmpty(localId) {
13
+ return typeof localId === 'string' && localId.trim().length > 0;
14
+ };
15
+ var addMissingLocalIdsToDocument = exports.addMissingLocalIdsToDocument = function addMissingLocalIdsToDocument(tr) {
16
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
17
+ onRepaired = _ref.onRepaired;
18
+ var missingLocalIdPositions = [];
19
+ var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
20
+ text = _tr$doc$type$schema$n.text,
21
+ hardBreak = _tr$doc$type$schema$n.hardBreak,
22
+ mediaGroup = _tr$doc$type$schema$n.mediaGroup;
23
+ var ignoredNodeTypes = [text === null || text === void 0 ? void 0 : text.name, hardBreak === null || hardBreak === void 0 ? void 0 : hardBreak.name, mediaGroup === null || mediaGroup === void 0 ? void 0 : mediaGroup.name];
24
+ tr.doc.descendants(function (node, pos) {
25
+ var _node$type$spec$attrs;
26
+ if (localIdNotEmpty(node.attrs.localId)) {
27
+ _generateShortUUID.generatedShortUUIDs.add(node.attrs.localId);
28
+ } else if (!ignoredNodeTypes.includes(node.type.name) && !!((_node$type$spec$attrs = node.type.spec.attrs) !== null && _node$type$spec$attrs !== void 0 && _node$type$spec$attrs.localId)) {
29
+ missingLocalIdPositions.push(pos);
30
+ }
31
+ return true;
32
+ });
33
+ var nodesToUpdate = new Map(missingLocalIdPositions.map(function (pos) {
34
+ return [pos, (0, _generateShortUUID.generateShortUUID)()];
35
+ }));
36
+ if (nodesToUpdate.size === 0) {
37
+ return false;
38
+ }
39
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
40
+ (0, _collab.tintDirtyTransaction)(tr);
41
+ onRepaired === null || onRepaired === void 0 || onRepaired({
42
+ repairedNodeCount: nodesToUpdate.size
43
+ });
44
+ return true;
45
+ };
46
+
47
+ /**
48
+ * Batch adds local IDs to nodes using a BatchAttrsStep
49
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
50
+ * @param tr
51
+ */
52
+ var batchAddLocalIdToNodes = exports.batchAddLocalIdToNodes = function batchAddLocalIdToNodes(nodesToUpdate, tr) {
53
+ var batchData = Array.from(nodesToUpdate.entries()).map(function (_ref2) {
54
+ var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
55
+ pos = _ref3[0],
56
+ localId = _ref3[1];
57
+ var node = tr.doc.nodeAt(pos);
58
+ if (!node) {
59
+ throw new Error("Node does not exist at position ".concat(pos));
60
+ }
61
+ return {
62
+ position: pos,
63
+ attrs: {
64
+ localId: localId
65
+ },
66
+ nodeType: node.type.name
67
+ };
68
+ });
69
+ tr.step(new _steps.BatchAttrsStep(batchData));
70
+ tr.setMeta('addToHistory', false);
71
+ };
@@ -4,15 +4,17 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.localIdPluginKey = exports.createPlugin = exports.batchAddLocalIdToNodes = void 0;
8
- var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
7
+ exports.localIdPluginKey = exports.createPlugin = void 0;
9
8
  var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
10
9
  var _steps = require("@atlaskit/adf-schema/steps");
11
10
  var _collab = require("@atlaskit/editor-common/collab");
12
11
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
13
12
  var _utils = require("@atlaskit/editor-common/utils");
14
13
  var _state = require("@atlaskit/editor-prosemirror/state");
14
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
15
15
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
16
+ var _editorCommands = require("../editor-commands");
17
+ var _addMissingLocalIds = require("./add-missing-local-ids");
16
18
  var _generateShortUUID = require("./generateShortUUID");
17
19
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
18
20
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
@@ -48,6 +50,10 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
48
50
  };
49
51
  }
50
52
  requestIdleCallbackWithFallback(function () {
53
+ if ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_local_id_reliability')) {
54
+ api === null || api === void 0 || api.core.actions.execute((0, _editorCommands.addMissingLocalIds)());
55
+ return;
56
+ }
51
57
  var tr = editorView.state.tr;
52
58
  var nodesToUpdate = new Map(); // position -> localId
53
59
 
@@ -66,7 +72,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
66
72
  return true; // Continue traversing
67
73
  });
68
74
  if (nodesToUpdate.size > 0) {
69
- batchAddLocalIdToNodes(nodesToUpdate, tr);
75
+ (0, _addMissingLocalIds.batchAddLocalIdToNodes)(nodesToUpdate, tr);
70
76
  (0, _collab.tintDirtyTransaction)(tr);
71
77
  editorView.dispatch(tr);
72
78
  }
@@ -190,7 +196,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
190
196
  continue;
191
197
  }
192
198
  var existingId = node.attrs.localId;
193
- var needsNewIds = !existingId || localIds.has(existingId) || seenIds.has(existingId);
199
+ var needsNewIds = ((0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_local_id_reliability') ? !(0, _addMissingLocalIds.localIdNotEmpty)(existingId) : !existingId) || localIds.has(existingId) || seenIds.has(existingId);
194
200
  if (needsNewIds) {
195
201
  // No usable localId: assign a fresh unique one to every position.
196
202
  var _iterator2 = _createForOfIteratorHelper(positions),
@@ -245,34 +251,9 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
245
251
  // - When enabled: Batch all updates into a single BatchAttrsStep
246
252
  // - When disabled: Individual steps were already applied above during node processing
247
253
  if (modified && nodesToUpdate.size > 0) {
248
- batchAddLocalIdToNodes(nodesToUpdate, tr);
254
+ (0, _addMissingLocalIds.batchAddLocalIdToNodes)(nodesToUpdate, tr);
249
255
  }
250
256
  return modified ? tr : undefined;
251
257
  }
252
258
  });
253
- };
254
- /**
255
- * Batch adds local IDs to nodes using a BatchAttrsStep
256
- * @param nodesToUpdate Map of position -> localId for nodes that need updates
257
- * @param tr
258
- */
259
- var batchAddLocalIdToNodes = exports.batchAddLocalIdToNodes = function batchAddLocalIdToNodes(nodesToUpdate, tr) {
260
- var batchData = Array.from(nodesToUpdate.entries()).map(function (_ref) {
261
- var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
262
- pos = _ref2[0],
263
- localId = _ref2[1];
264
- var node = tr.doc.nodeAt(pos);
265
- if (!node) {
266
- throw new Error("Node does not exist at position ".concat(pos));
267
- }
268
- return {
269
- position: pos,
270
- attrs: {
271
- localId: localId
272
- },
273
- nodeType: node.type.name
274
- };
275
- });
276
- tr.step(new _steps.BatchAttrsStep(batchData));
277
- tr.setMeta('addToHistory', false);
278
259
  };
@@ -0,0 +1,13 @@
1
+ import { addMissingLocalIdsToDocument } from '../pm-plugins/add-missing-local-ids';
2
+
3
+ /**
4
+ * Scans the current document and adds missing local IDs.
5
+ */
6
+ export const addMissingLocalIds = (options = {}) => ({
7
+ tr
8
+ }) => {
9
+ if (!addMissingLocalIdsToDocument(tr, options)) {
10
+ return null;
11
+ }
12
+ return tr;
13
+ };
@@ -1,5 +1,6 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
2
  import { replaceNode, getNode } from './editor-actions';
3
+ import { addMissingLocalIds } from './editor-commands';
3
4
  import { createPlugin } from './pm-plugins/main';
4
5
  import { createWatchmenPlugin, localIdWatchmenPluginKey } from './pm-plugins/watchmen';
5
6
  export const localIdPlugin = ({
@@ -10,6 +11,9 @@ export const localIdPlugin = ({
10
11
  replaceNode: replaceNode(api),
11
12
  getNode: getNode(api)
12
13
  },
14
+ commands: {
15
+ addMissingLocalIds
16
+ },
13
17
  pmPlugins() {
14
18
  return [{
15
19
  name: 'localIdPlugin',
@@ -0,0 +1,57 @@
1
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
2
+ import { tintDirtyTransaction } from '@atlaskit/editor-common/collab';
3
+ import { generateShortUUID, generatedShortUUIDs } from './generateShortUUID';
4
+ export const localIdNotEmpty = localId => typeof localId === 'string' && localId.trim().length > 0;
5
+ export const addMissingLocalIdsToDocument = (tr, {
6
+ onRepaired
7
+ } = {}) => {
8
+ const missingLocalIdPositions = [];
9
+ const {
10
+ text,
11
+ hardBreak,
12
+ mediaGroup
13
+ } = tr.doc.type.schema.nodes;
14
+ const ignoredNodeTypes = [text === null || text === void 0 ? void 0 : text.name, hardBreak === null || hardBreak === void 0 ? void 0 : hardBreak.name, mediaGroup === null || mediaGroup === void 0 ? void 0 : mediaGroup.name];
15
+ tr.doc.descendants((node, pos) => {
16
+ var _node$type$spec$attrs;
17
+ if (localIdNotEmpty(node.attrs.localId)) {
18
+ generatedShortUUIDs.add(node.attrs.localId);
19
+ } else if (!ignoredNodeTypes.includes(node.type.name) && !!((_node$type$spec$attrs = node.type.spec.attrs) !== null && _node$type$spec$attrs !== void 0 && _node$type$spec$attrs.localId)) {
20
+ missingLocalIdPositions.push(pos);
21
+ }
22
+ return true;
23
+ });
24
+ const nodesToUpdate = new Map(missingLocalIdPositions.map(pos => [pos, generateShortUUID()]));
25
+ if (nodesToUpdate.size === 0) {
26
+ return false;
27
+ }
28
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
29
+ tintDirtyTransaction(tr);
30
+ onRepaired === null || onRepaired === void 0 ? void 0 : onRepaired({
31
+ repairedNodeCount: nodesToUpdate.size
32
+ });
33
+ return true;
34
+ };
35
+
36
+ /**
37
+ * Batch adds local IDs to nodes using a BatchAttrsStep
38
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
39
+ * @param tr
40
+ */
41
+ export const batchAddLocalIdToNodes = (nodesToUpdate, tr) => {
42
+ const batchData = Array.from(nodesToUpdate.entries()).map(([pos, localId]) => {
43
+ const node = tr.doc.nodeAt(pos);
44
+ if (!node) {
45
+ throw new Error(`Node does not exist at position ${pos}`);
46
+ }
47
+ return {
48
+ position: pos,
49
+ attrs: {
50
+ localId
51
+ },
52
+ nodeType: node.type.name
53
+ };
54
+ });
55
+ tr.step(new BatchAttrsStep(batchData));
56
+ tr.setMeta('addToHistory', false);
57
+ };
@@ -1,9 +1,12 @@
1
- import { BatchAttrsStep, OverrideDocumentStep } from '@atlaskit/adf-schema/steps';
1
+ import { OverrideDocumentStep } from '@atlaskit/adf-schema/steps';
2
2
  import { tintDirtyTransaction } from '@atlaskit/editor-common/collab';
3
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
4
  import { stepHasSlice } from '@atlaskit/editor-common/utils';
5
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
6
7
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
8
+ import { addMissingLocalIds } from '../editor-commands';
9
+ import { batchAddLocalIdToNodes, localIdNotEmpty } from './add-missing-local-ids';
7
10
  import { generateShortUUID, generatedShortUUIDs } from './generateShortUUID';
8
11
  export const localIdPluginKey = new PluginKey('localIdPlugin');
9
12
  const generateUUID = () => {
@@ -36,6 +39,10 @@ export const createPlugin = api => {
36
39
  };
37
40
  }
38
41
  requestIdleCallbackWithFallback(() => {
42
+ if (isExperimentEnabled('platform_editor_local_id_reliability')) {
43
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(addMissingLocalIds());
44
+ return;
45
+ }
39
46
  const tr = editorView.state.tr;
40
47
  const nodesToUpdate = new Map(); // position -> localId
41
48
 
@@ -174,7 +181,7 @@ export const createPlugin = api => {
174
181
  continue;
175
182
  }
176
183
  const existingId = node.attrs.localId;
177
- const needsNewIds = !existingId || localIds.has(existingId) || seenIds.has(existingId);
184
+ const needsNewIds = (isExperimentEnabled('platform_editor_local_id_reliability') ? !localIdNotEmpty(existingId) : !existingId) || localIds.has(existingId) || seenIds.has(existingId);
178
185
  if (needsNewIds) {
179
186
  // No usable localId: assign a fresh unique one to every position.
180
187
  for (const pos of positions) {
@@ -208,26 +215,4 @@ export const createPlugin = api => {
208
215
  return modified ? tr : undefined;
209
216
  }
210
217
  });
211
- };
212
- /**
213
- * Batch adds local IDs to nodes using a BatchAttrsStep
214
- * @param nodesToUpdate Map of position -> localId for nodes that need updates
215
- * @param tr
216
- */
217
- export const batchAddLocalIdToNodes = (nodesToUpdate, tr) => {
218
- const batchData = Array.from(nodesToUpdate.entries()).map(([pos, localId]) => {
219
- const node = tr.doc.nodeAt(pos);
220
- if (!node) {
221
- throw new Error(`Node does not exist at position ${pos}`);
222
- }
223
- return {
224
- position: pos,
225
- attrs: {
226
- localId
227
- },
228
- nodeType: node.type.name
229
- };
230
- });
231
- tr.step(new BatchAttrsStep(batchData));
232
- tr.setMeta('addToHistory', false);
233
218
  };
@@ -0,0 +1,15 @@
1
+ import { addMissingLocalIdsToDocument } from '../pm-plugins/add-missing-local-ids';
2
+
3
+ /**
4
+ * Scans the current document and adds missing local IDs.
5
+ */
6
+ export var addMissingLocalIds = function addMissingLocalIds() {
7
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
8
+ return function (_ref) {
9
+ var tr = _ref.tr;
10
+ if (!addMissingLocalIdsToDocument(tr, options)) {
11
+ return null;
12
+ }
13
+ return tr;
14
+ };
15
+ };
@@ -1,5 +1,6 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
2
  import { replaceNode, getNode } from './editor-actions';
3
+ import { addMissingLocalIds } from './editor-commands';
3
4
  import { createPlugin } from './pm-plugins/main';
4
5
  import { createWatchmenPlugin, localIdWatchmenPluginKey } from './pm-plugins/watchmen';
5
6
  export var localIdPlugin = function localIdPlugin(_ref) {
@@ -10,6 +11,9 @@ export var localIdPlugin = function localIdPlugin(_ref) {
10
11
  replaceNode: replaceNode(api),
11
12
  getNode: getNode(api)
12
13
  },
14
+ commands: {
15
+ addMissingLocalIds: addMissingLocalIds
16
+ },
13
17
  pmPlugins: function pmPlugins() {
14
18
  return [{
15
19
  name: 'localIdPlugin',
@@ -0,0 +1,64 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
3
+ import { tintDirtyTransaction } from '@atlaskit/editor-common/collab';
4
+ import { generateShortUUID, generatedShortUUIDs } from './generateShortUUID';
5
+ export var localIdNotEmpty = function localIdNotEmpty(localId) {
6
+ return typeof localId === 'string' && localId.trim().length > 0;
7
+ };
8
+ export var addMissingLocalIdsToDocument = function addMissingLocalIdsToDocument(tr) {
9
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
10
+ onRepaired = _ref.onRepaired;
11
+ var missingLocalIdPositions = [];
12
+ var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
13
+ text = _tr$doc$type$schema$n.text,
14
+ hardBreak = _tr$doc$type$schema$n.hardBreak,
15
+ mediaGroup = _tr$doc$type$schema$n.mediaGroup;
16
+ var ignoredNodeTypes = [text === null || text === void 0 ? void 0 : text.name, hardBreak === null || hardBreak === void 0 ? void 0 : hardBreak.name, mediaGroup === null || mediaGroup === void 0 ? void 0 : mediaGroup.name];
17
+ tr.doc.descendants(function (node, pos) {
18
+ var _node$type$spec$attrs;
19
+ if (localIdNotEmpty(node.attrs.localId)) {
20
+ generatedShortUUIDs.add(node.attrs.localId);
21
+ } else if (!ignoredNodeTypes.includes(node.type.name) && !!((_node$type$spec$attrs = node.type.spec.attrs) !== null && _node$type$spec$attrs !== void 0 && _node$type$spec$attrs.localId)) {
22
+ missingLocalIdPositions.push(pos);
23
+ }
24
+ return true;
25
+ });
26
+ var nodesToUpdate = new Map(missingLocalIdPositions.map(function (pos) {
27
+ return [pos, generateShortUUID()];
28
+ }));
29
+ if (nodesToUpdate.size === 0) {
30
+ return false;
31
+ }
32
+ batchAddLocalIdToNodes(nodesToUpdate, tr);
33
+ tintDirtyTransaction(tr);
34
+ onRepaired === null || onRepaired === void 0 || onRepaired({
35
+ repairedNodeCount: nodesToUpdate.size
36
+ });
37
+ return true;
38
+ };
39
+
40
+ /**
41
+ * Batch adds local IDs to nodes using a BatchAttrsStep
42
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
43
+ * @param tr
44
+ */
45
+ export var batchAddLocalIdToNodes = function batchAddLocalIdToNodes(nodesToUpdate, tr) {
46
+ var batchData = Array.from(nodesToUpdate.entries()).map(function (_ref2) {
47
+ var _ref3 = _slicedToArray(_ref2, 2),
48
+ pos = _ref3[0],
49
+ localId = _ref3[1];
50
+ var node = tr.doc.nodeAt(pos);
51
+ if (!node) {
52
+ throw new Error("Node does not exist at position ".concat(pos));
53
+ }
54
+ return {
55
+ position: pos,
56
+ attrs: {
57
+ localId: localId
58
+ },
59
+ nodeType: node.type.name
60
+ };
61
+ });
62
+ tr.step(new BatchAttrsStep(batchData));
63
+ tr.setMeta('addToHistory', false);
64
+ };
@@ -1,14 +1,16 @@
1
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
1
  import _toArray from "@babel/runtime/helpers/toArray";
3
2
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
4
3
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
5
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
6
- import { BatchAttrsStep, OverrideDocumentStep } from '@atlaskit/adf-schema/steps';
5
+ import { OverrideDocumentStep } from '@atlaskit/adf-schema/steps';
7
6
  import { tintDirtyTransaction } from '@atlaskit/editor-common/collab';
8
7
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
9
8
  import { stepHasSlice } from '@atlaskit/editor-common/utils';
10
9
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
10
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
11
11
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
12
+ import { addMissingLocalIds } from '../editor-commands';
13
+ import { batchAddLocalIdToNodes, localIdNotEmpty } from './add-missing-local-ids';
12
14
  import { generateShortUUID, generatedShortUUIDs } from './generateShortUUID';
13
15
  export var localIdPluginKey = new PluginKey('localIdPlugin');
14
16
  var generateUUID = function generateUUID() {
@@ -41,6 +43,10 @@ export var createPlugin = function createPlugin(api) {
41
43
  };
42
44
  }
43
45
  requestIdleCallbackWithFallback(function () {
46
+ if (isExperimentEnabled('platform_editor_local_id_reliability')) {
47
+ api === null || api === void 0 || api.core.actions.execute(addMissingLocalIds());
48
+ return;
49
+ }
44
50
  var tr = editorView.state.tr;
45
51
  var nodesToUpdate = new Map(); // position -> localId
46
52
 
@@ -183,7 +189,7 @@ export var createPlugin = function createPlugin(api) {
183
189
  continue;
184
190
  }
185
191
  var existingId = node.attrs.localId;
186
- var needsNewIds = !existingId || localIds.has(existingId) || seenIds.has(existingId);
192
+ var needsNewIds = (isExperimentEnabled('platform_editor_local_id_reliability') ? !localIdNotEmpty(existingId) : !existingId) || localIds.has(existingId) || seenIds.has(existingId);
187
193
  if (needsNewIds) {
188
194
  // No usable localId: assign a fresh unique one to every position.
189
195
  var _iterator2 = _createForOfIteratorHelper(positions),
@@ -243,29 +249,4 @@ export var createPlugin = function createPlugin(api) {
243
249
  return modified ? tr : undefined;
244
250
  }
245
251
  });
246
- };
247
- /**
248
- * Batch adds local IDs to nodes using a BatchAttrsStep
249
- * @param nodesToUpdate Map of position -> localId for nodes that need updates
250
- * @param tr
251
- */
252
- export var batchAddLocalIdToNodes = function batchAddLocalIdToNodes(nodesToUpdate, tr) {
253
- var batchData = Array.from(nodesToUpdate.entries()).map(function (_ref) {
254
- var _ref2 = _slicedToArray(_ref, 2),
255
- pos = _ref2[0],
256
- localId = _ref2[1];
257
- var node = tr.doc.nodeAt(pos);
258
- if (!node) {
259
- throw new Error("Node does not exist at position ".concat(pos));
260
- }
261
- return {
262
- position: pos,
263
- attrs: {
264
- localId: localId
265
- },
266
- nodeType: node.type.name
267
- };
268
- });
269
- tr.step(new BatchAttrsStep(batchData));
270
- tr.setMeta('addToHistory', false);
271
252
  };
@@ -0,0 +1,6 @@
1
+ import type { EditorCommand } from '@atlaskit/editor-common/types';
2
+ import type { AddMissingLocalIdsOptions } from '../localIdPluginType';
3
+ /**
4
+ * Scans the current document and adds missing local IDs.
5
+ */
6
+ export declare const addMissingLocalIds: (options?: AddMissingLocalIdsOptions) => EditorCommand;
@@ -1,4 +1,4 @@
1
- import type { NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
2
2
  import type { CollabEditPlugin } from '@atlaskit/editor-plugin-collab-edit';
3
3
  import type { CompositionPlugin } from '@atlaskit/editor-plugin-composition';
4
4
  import type { LimitedModePlugin } from '@atlaskit/editor-plugin-limited-mode';
@@ -7,6 +7,11 @@ import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
7
7
  export type ActionProps = {
8
8
  localId: string;
9
9
  };
10
+ export type AddMissingLocalIdsOptions = {
11
+ onRepaired?: (payload: {
12
+ repairedNodeCount: number;
13
+ }) => void;
14
+ };
10
15
  export type LocalIdStatusCode = 'current' | 'localChangeByAttr' | 'localChangeBySetAttrs' | 'localChangeByBatchAttrs' | 'localChangeByReplace' | 'localChangeByDelete' | 'localChangeByReplaceAround' | 'localChangeByUnknown' | 'remoteChangeByAttr' | 'remoteChangeBySetAttrs' | 'remoteChangeByBatchAttrs' | 'remoteChangeByReplace' | 'remoteChangeByDelete' | 'remoteChangeByReplaceAround' | 'remoteChangeByUnknown' | 'AIChangeByAttr' | 'AIChangeBySetAttrs' | 'AIChangeByBatchAttrs' | 'AIChangeByReplace' | 'AIChangeByDelete' | 'AIChangeByReplaceAround' | 'AIChangeByUnknown' | 'docChangeByAttr' | 'docChangeBySetAttrs' | 'docChangeByBatchAttrs' | 'docChangeByReplace' | 'docChangeByDelete' | 'docChangeByReplaceAround' | 'docChangeByUnknown';
11
16
  export interface LocalIdSharedState {
12
17
  localIdStatus: Map<string, LocalIdStatusCode> | undefined;
@@ -32,6 +37,12 @@ export type LocalIdPlugin = NextEditorPlugin<'localId', {
32
37
  value: Node;
33
38
  }) => boolean;
34
39
  };
40
+ commands: {
41
+ /**
42
+ * Scans the current document and adds local IDs to eligible nodes that are missing them.
43
+ */
44
+ addMissingLocalIds: (options?: AddMissingLocalIdsOptions) => EditorCommand;
45
+ };
35
46
  dependencies: [
36
47
  CompositionPlugin,
37
48
  OptionalPlugin<CollabEditPlugin>,
@@ -0,0 +1,10 @@
1
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
2
+ import type { AddMissingLocalIdsOptions } from '../localIdPluginType';
3
+ export declare const localIdNotEmpty: (localId: unknown) => boolean;
4
+ export declare const addMissingLocalIdsToDocument: (tr: Transaction, { onRepaired }?: AddMissingLocalIdsOptions) => boolean;
5
+ /**
6
+ * Batch adds local IDs to nodes using a BatchAttrsStep
7
+ * @param nodesToUpdate Map of position -> localId for nodes that need updates
8
+ * @param tr
9
+ */
10
+ export declare const batchAddLocalIdToNodes: (nodesToUpdate: Map<number, string>, tr: Transaction) => void;
@@ -1,12 +1,6 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
- import { PluginKey, type Transaction } from '@atlaskit/editor-prosemirror/state';
3
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { LocalIdPlugin } from '../localIdPluginType';
5
5
  export declare const localIdPluginKey: PluginKey;
6
6
  export declare const createPlugin: (api: ExtractInjectionAPI<LocalIdPlugin> | undefined) => SafePlugin;
7
- /**
8
- * Batch adds local IDs to nodes using a BatchAttrsStep
9
- * @param nodesToUpdate Map of position -> localId for nodes that need updates
10
- * @param tr
11
- */
12
- export declare const batchAddLocalIdToNodes: (nodesToUpdate: Map<number, string>, tr: Transaction) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-local-id",
3
- "version": "13.0.3",
3
+ "version": "13.1.0",
4
4
  "description": "LocalId plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -25,13 +25,14 @@
25
25
  "@atlaskit/editor-plugin-composition": "^14.0.0",
26
26
  "@atlaskit/editor-plugin-limited-mode": "^12.0.0",
27
27
  "@atlaskit/editor-prosemirror": "^8.0.0",
28
+ "@atlaskit/platform-feature-experiments": "^0.3.0",
28
29
  "@atlaskit/platform-feature-flags": "^2.1.0",
29
30
  "@atlaskit/tmp-editor-statsig": "^149.0.0",
30
31
  "@babel/runtime": "^7.0.0",
31
32
  "raf-schd": "^4.0.3"
32
33
  },
33
34
  "peerDependencies": {
34
- "@atlaskit/editor-common": "^119.7.0",
35
+ "@atlaskit/editor-common": "^119.8.0",
35
36
  "react": "^18.2.0 || ^19.2.0"
36
37
  },
37
38
  "devDependencies": {