@atlaskit/node-data-provider 4.3.0 → 4.4.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/node-data-provider
2
2
 
3
+ ## 4.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#191942](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/191942)
8
+ [`6b5ec599e6dfd`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6b5ec599e6dfd) -
9
+ [https://product-fabric.atlassian.net/browse/ED-28596](ED-28596) - extend EditorCardProvider from
10
+ NodeDataProvider
11
+
12
+ ### Patch Changes
13
+
14
+ - [#191913](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/191913)
15
+ [`6d1e56695e91d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6d1e56695e91d) -
16
+ EDITOR-1131 Bump adf-schema package to 50.0.0
17
+ - Updated dependencies
18
+
3
19
  ## 4.3.0
4
20
 
5
21
  ### Minor Changes
@@ -34,6 +34,10 @@ var _coreUtils = require("@atlaskit/editor-common/core-utils");
34
34
  * 'node-id-2': { source: 'network', data: Promise.resolve({ value: 'other data' }) }
35
35
  * }
36
36
  */
37
+ /**
38
+ * Represents the payload passed to the callback function when data is fetched.
39
+ * It can either contain an error or the fetched data.
40
+ */
37
41
  /**
38
42
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
39
43
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -66,16 +70,15 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
66
70
  value: function setSSRData() {
67
71
  var ssrData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
68
72
  this.cacheVersion++;
69
- this.cache = Object.entries(ssrData).reduce(function (acc, _ref) {
73
+ this.cache = Object.fromEntries(Object.entries(ssrData).map(function (_ref) {
70
74
  var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
71
75
  key = _ref2[0],
72
76
  data = _ref2[1];
73
- acc[key] = {
74
- source: 'ssr',
75
- data: data
76
- };
77
- return acc;
78
- }, {});
77
+ return [key, {
78
+ data: data,
79
+ source: 'ssr'
80
+ }];
81
+ }));
79
82
  }
80
83
 
81
84
  /**
@@ -120,7 +123,7 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
120
123
  * ```
121
124
  *
122
125
  * @param node The node (or its ProseMirror representation) for which to fetch data.
123
- * @param callback The function to call when data is available.
126
+ * @param callback The callback function to call with the fetched data or an error.
124
127
  */
125
128
  }, {
126
129
  key: "getData",
@@ -133,48 +136,54 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
133
136
  key: "getDataAsync",
134
137
  value: function () {
135
138
  var _getDataAsync = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(node, callback) {
136
- var jsonNode, dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
139
+ var jsonNode, _dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
137
140
  return _regenerator.default.wrap(function _callee$(_context) {
138
141
  while (1) switch (_context.prev = _context.next) {
139
142
  case 0:
143
+ _context.prev = 0;
140
144
  jsonNode = 'toJSON' in node ? node.toJSON() : node;
141
145
  if (this.isNodeSupported(jsonNode)) {
142
- _context.next = 4;
146
+ _context.next = 5;
143
147
  break;
144
148
  }
145
149
  // eslint-disable-next-line no-console
146
150
  console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
147
151
  return _context.abrupt("return");
148
- case 4:
149
- dataKey = this.nodeDataKey(jsonNode);
150
- dataFromCache = this.cache[dataKey];
152
+ case 5:
153
+ _dataKey = this.nodeDataKey(jsonNode);
154
+ dataFromCache = this.cache[_dataKey];
151
155
  if (!(dataFromCache !== undefined)) {
152
- _context.next = 18;
156
+ _context.next = 20;
153
157
  break;
154
158
  }
155
159
  if (!isPromise(dataFromCache.data)) {
156
- _context.next = 15;
160
+ _context.next = 17;
157
161
  break;
158
162
  }
159
163
  _context.t0 = callback;
160
- _context.next = 11;
164
+ _context.next = 12;
161
165
  return dataFromCache.data;
162
- case 11:
166
+ case 12:
163
167
  _context.t1 = _context.sent;
164
- (0, _context.t0)(_context.t1);
165
- _context.next = 16;
168
+ _context.t2 = {
169
+ data: _context.t1
170
+ };
171
+ (0, _context.t0)(_context.t2);
172
+ _context.next = 18;
166
173
  break;
167
- case 15:
168
- callback(dataFromCache.data);
169
- case 16:
174
+ case 17:
175
+ callback({
176
+ data: dataFromCache.data
177
+ });
178
+ case 18:
170
179
  if (!(0, _coreUtils.isSSR)()) {
171
- _context.next = 18;
180
+ _context.next = 20;
172
181
  break;
173
182
  }
174
183
  return _context.abrupt("return");
175
- case 18:
184
+ case 20:
176
185
  if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
177
- _context.next = 27;
186
+ _context.next = 29;
178
187
  break;
179
188
  }
180
189
  // Store the current cache version before making the request,
@@ -185,32 +194,44 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
185
194
  value = _ref4[0];
186
195
  return value;
187
196
  }); // Store the promise in the cache to avoid multiple requests for the same data
188
- this.cache[dataKey] = {
197
+ this.cache[_dataKey] = {
189
198
  source: 'network',
190
199
  data: dataPromise
191
200
  };
192
- _context.next = 24;
201
+ _context.next = 26;
193
202
  return dataPromise;
194
- case 24:
203
+ case 26:
195
204
  data = _context.sent;
196
205
  // We need to call the callback with the data with result even if the cache version has changed,
197
206
  // so all promises that are waiting for the data can resolve.
198
- callback(data);
207
+ callback({
208
+ data: data
209
+ });
199
210
 
200
211
  // If the cache version has changed, we don't want to use the data from the network
201
212
  // because it could be stale data.
202
213
  if (cacheVersionBeforeRequest === this.cacheVersion) {
203
214
  // Replace promise with the resolved data in the cache
204
- this.cache[dataKey] = {
215
+ this.cache[_dataKey] = {
205
216
  source: 'network',
206
217
  data: data
207
218
  };
208
219
  }
209
- case 27:
220
+ case 29:
221
+ _context.next = 34;
222
+ break;
223
+ case 31:
224
+ _context.prev = 31;
225
+ _context.t3 = _context["catch"](0);
226
+ // If an error occurs, we call the callback with the error
227
+ callback({
228
+ error: _context.t3 instanceof Error ? _context.t3 : new Error(String(_context.t3))
229
+ });
230
+ case 34:
210
231
  case "end":
211
232
  return _context.stop();
212
233
  }
213
- }, _callee, this);
234
+ }, _callee, this, [[0, 31]]);
214
235
  }));
215
236
  function getDataAsync(_x, _x2) {
216
237
  return _getDataAsync.apply(this, arguments);
@@ -239,7 +260,13 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
239
260
  var _this = this;
240
261
  return new Promise(function (resolve, reject) {
241
262
  try {
242
- return _this.getData(node, resolve);
263
+ _this.getData(node, function (payload) {
264
+ if (payload.error) {
265
+ reject(payload.error);
266
+ } else {
267
+ resolve(payload.data);
268
+ }
269
+ });
243
270
  } catch (error) {
244
271
  reject(error);
245
272
  }
@@ -15,7 +15,9 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
15
15
  * @returns An array of objects, each containing a provider and the nodes that are supported by that provider.
16
16
  */
17
17
  function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
18
+ // Counter for the total number of visited nodes to limit the traversal.
18
19
  var totalVisitedNodesCount = 0;
20
+ // A map to store the results, with the provider name as the key.
19
21
  var resultMap = providers.reduce(function (acc, _ref) {
20
22
  var provider = _ref.provider;
21
23
  acc[provider.name] = {
@@ -28,6 +30,7 @@ function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
28
30
  // It doesn't use `filter` function from `@atlaskit/adf-utils/traverse` because it does not support early stopping.
29
31
  // We need to stop traversing when we reach the maximum number of nodes to visit to support large documents.
30
32
 
33
+ // Create a list of providers for which we still need to find nodes.
31
34
  var providersToLookup = providers.filter(function (_ref2) {
32
35
  var maxNodesToPrefetch = _ref2.maxNodesToPrefetch;
33
36
  return maxNodesToPrefetch > 0;
@@ -37,32 +40,46 @@ function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
37
40
  return {
38
41
  provider: provider,
39
42
  maxNodesToPrefetch: maxNodesToPrefetch,
40
- foundNodes: 0
43
+ foundNodes: 0 // Counter for nodes found for each provider.
41
44
  };
42
45
  });
46
+
47
+ // Queue for the breadth-first search (BFS), starting with the root document node.
43
48
  var nodesToVisit = [doc];
44
49
  var currentIndex = 0;
50
+ // The loop continues as long as there are nodes to visit, providers to look for,
51
+ // and the visited nodes limit has not been reached.
45
52
  while (currentIndex < nodesToVisit.length && providersToLookup.length > 0 && totalVisitedNodesCount < maxNodesToVisit) {
46
53
  totalVisitedNodesCount += 1;
47
54
  var currentNode = nodesToVisit[currentIndex];
48
55
  currentIndex++;
49
56
 
50
- // Using reverse loop to avoid issues with array mutation
57
+ // Using a reverse loop to avoid issues with array mutation (when removing elements).
51
58
  for (var i = providersToLookup.length - 1; i >= 0; i--) {
52
59
  var providerToFind = providersToLookup[i];
60
+
61
+ // Check if the current provider supports this node.
53
62
  if (providerToFind.provider.isNodeSupported(currentNode)) {
63
+ // If provider supports the node, add it to the result map.
54
64
  resultMap[providerToFind.provider.name].nodes.push(currentNode);
65
+ // Increment the count of found nodes for this provider.
55
66
  providerToFind.foundNodes += 1;
67
+
68
+ // If the provider has found enough nodes, remove it from the lookup list.
56
69
  if (providerToFind.foundNodes >= providerToFind.maxNodesToPrefetch) {
57
70
  providersToLookup.splice(i, 1);
58
71
  }
59
72
  }
60
73
  }
74
+
75
+ // If the current node has children, add them to the queue to be visited.
61
76
  if (currentNode.content) {
62
77
  nodesToVisit.push.apply(nodesToVisit, (0, _toConsumableArray2.default)(currentNode.content.filter(function (node) {
63
78
  return node !== undefined;
64
79
  })));
65
80
  }
66
81
  }
82
+
83
+ // Return an array of the found nodes, grouped by provider.
67
84
  return Object.values(resultMap);
68
85
  }
@@ -24,6 +24,11 @@ import { isSSR } from '@atlaskit/editor-common/core-utils';
24
24
  * }
25
25
  */
26
26
 
27
+ /**
28
+ * Represents the payload passed to the callback function when data is fetched.
29
+ * It can either contain an error or the fetched data.
30
+ */
31
+
27
32
  /**
28
33
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
29
34
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -78,13 +83,10 @@ export class NodeDataProvider {
78
83
  */
79
84
  setSSRData(ssrData = {}) {
80
85
  this.cacheVersion++;
81
- this.cache = Object.entries(ssrData).reduce((acc, [key, data]) => {
82
- acc[key] = {
83
- source: 'ssr',
84
- data
85
- };
86
- return acc;
87
- }, {});
86
+ this.cache = Object.fromEntries(Object.entries(ssrData).map(([key, data]) => [key, {
87
+ data,
88
+ source: 'ssr'
89
+ }]));
88
90
  }
89
91
 
90
92
  /**
@@ -127,7 +129,7 @@ export class NodeDataProvider {
127
129
  * ```
128
130
  *
129
131
  * @param node The node (or its ProseMirror representation) for which to fetch data.
130
- * @param callback The function to call when data is available.
132
+ * @param callback The callback function to call with the fetched data or an error.
131
133
  */
132
134
  getData(node, callback) {
133
135
  // Move implementation to a separate async method
@@ -135,53 +137,66 @@ export class NodeDataProvider {
135
137
  void this.getDataAsync(node, callback);
136
138
  }
137
139
  async getDataAsync(node, callback) {
138
- const jsonNode = 'toJSON' in node ? node.toJSON() : node;
139
- if (!this.isNodeSupported(jsonNode)) {
140
- // eslint-disable-next-line no-console
141
- console.error(`The ${this.constructor.name} doesn't support Node ${jsonNode.type}.`);
142
- return;
143
- }
144
- const dataKey = this.nodeDataKey(jsonNode);
145
- const dataFromCache = this.cache[dataKey];
146
- if (dataFromCache !== undefined) {
147
- // If we have the data in the SSR data, we can use it directly
148
- if (isPromise(dataFromCache.data)) {
149
- callback(await dataFromCache.data);
150
- } else {
151
- callback(dataFromCache.data);
152
- }
153
- if (isSSR()) {
154
- // If we are in SSR, we don't want to fetch the data again, as it is already available in the SSR data
140
+ try {
141
+ const jsonNode = 'toJSON' in node ? node.toJSON() : node;
142
+ if (!this.isNodeSupported(jsonNode)) {
143
+ // eslint-disable-next-line no-console
144
+ console.error(`The ${this.constructor.name} doesn't support Node ${jsonNode.type}.`);
155
145
  return;
156
146
  }
157
- }
158
-
159
- // If no data is available in the cache or the data is from the network,
160
- // we need to fetch it from the network.
161
- if ((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network') {
162
- // Store the current cache version before making the request,
163
- // so we can check if the cache has changed while we are waiting for the network response.
164
- const cacheVersionBeforeRequest = this.cacheVersion;
165
- const dataPromise = this.fetchNodesData([jsonNode]).then(([value]) => value);
166
- // Store the promise in the cache to avoid multiple requests for the same data
167
- this.cache[dataKey] = {
168
- source: 'network',
169
- data: dataPromise
170
- };
171
- const data = await dataPromise;
172
- // We need to call the callback with the data with result even if the cache version has changed,
173
- // so all promises that are waiting for the data can resolve.
174
- callback(data);
147
+ const dataKey = this.nodeDataKey(jsonNode);
148
+ const dataFromCache = this.cache[dataKey];
149
+ if (dataFromCache !== undefined) {
150
+ // If we have the data in the SSR data, we can use it directly
151
+ if (isPromise(dataFromCache.data)) {
152
+ callback({
153
+ data: await dataFromCache.data
154
+ });
155
+ } else {
156
+ callback({
157
+ data: dataFromCache.data
158
+ });
159
+ }
160
+ if (isSSR()) {
161
+ // If we are in SSR, we don't want to fetch the data again, as it is already available in the SSR data
162
+ return;
163
+ }
164
+ }
175
165
 
176
- // If the cache version has changed, we don't want to use the data from the network
177
- // because it could be stale data.
178
- if (cacheVersionBeforeRequest === this.cacheVersion) {
179
- // Replace promise with the resolved data in the cache
166
+ // If no data is available in the cache or the data is from the network,
167
+ // we need to fetch it from the network.
168
+ if ((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network') {
169
+ // Store the current cache version before making the request,
170
+ // so we can check if the cache has changed while we are waiting for the network response.
171
+ const cacheVersionBeforeRequest = this.cacheVersion;
172
+ const dataPromise = this.fetchNodesData([jsonNode]).then(([value]) => value);
173
+ // Store the promise in the cache to avoid multiple requests for the same data
180
174
  this.cache[dataKey] = {
181
175
  source: 'network',
182
- data
176
+ data: dataPromise
183
177
  };
178
+ const data = await dataPromise;
179
+ // We need to call the callback with the data with result even if the cache version has changed,
180
+ // so all promises that are waiting for the data can resolve.
181
+ callback({
182
+ data
183
+ });
184
+
185
+ // If the cache version has changed, we don't want to use the data from the network
186
+ // because it could be stale data.
187
+ if (cacheVersionBeforeRequest === this.cacheVersion) {
188
+ // Replace promise with the resolved data in the cache
189
+ this.cache[dataKey] = {
190
+ source: 'network',
191
+ data
192
+ };
193
+ }
184
194
  }
195
+ } catch (error) {
196
+ // If an error occurs, we call the callback with the error
197
+ callback({
198
+ error: error instanceof Error ? error : new Error(String(error))
199
+ });
185
200
  }
186
201
  }
187
202
 
@@ -204,7 +219,13 @@ export class NodeDataProvider {
204
219
  getDataAsPromise_DO_NOT_USE_OUTSIDE_MIGRATIONS(node) {
205
220
  return new Promise((resolve, reject) => {
206
221
  try {
207
- return this.getData(node, resolve);
222
+ this.getData(node, payload => {
223
+ if (payload.error) {
224
+ reject(payload.error);
225
+ } else {
226
+ resolve(payload.data);
227
+ }
228
+ });
208
229
  } catch (error) {
209
230
  reject(error);
210
231
  }
@@ -7,7 +7,9 @@
7
7
  * @returns An array of objects, each containing a provider and the nodes that are supported by that provider.
8
8
  */
9
9
  export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
10
+ // Counter for the total number of visited nodes to limit the traversal.
10
11
  let totalVisitedNodesCount = 0;
12
+ // A map to store the results, with the provider name as the key.
11
13
  const resultMap = providers.reduce((acc, {
12
14
  provider
13
15
  }) => {
@@ -21,6 +23,7 @@ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
21
23
  // It doesn't use `filter` function from `@atlaskit/adf-utils/traverse` because it does not support early stopping.
22
24
  // We need to stop traversing when we reach the maximum number of nodes to visit to support large documents.
23
25
 
26
+ // Create a list of providers for which we still need to find nodes.
24
27
  const providersToLookup = providers.filter(({
25
28
  maxNodesToPrefetch
26
29
  }) => maxNodesToPrefetch > 0).map(({
@@ -29,29 +32,43 @@ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
29
32
  }) => ({
30
33
  provider,
31
34
  maxNodesToPrefetch,
32
- foundNodes: 0
35
+ foundNodes: 0 // Counter for nodes found for each provider.
33
36
  }));
37
+
38
+ // Queue for the breadth-first search (BFS), starting with the root document node.
34
39
  const nodesToVisit = [doc];
35
40
  let currentIndex = 0;
41
+ // The loop continues as long as there are nodes to visit, providers to look for,
42
+ // and the visited nodes limit has not been reached.
36
43
  while (currentIndex < nodesToVisit.length && providersToLookup.length > 0 && totalVisitedNodesCount < maxNodesToVisit) {
37
44
  totalVisitedNodesCount += 1;
38
45
  const currentNode = nodesToVisit[currentIndex];
39
46
  currentIndex++;
40
47
 
41
- // Using reverse loop to avoid issues with array mutation
48
+ // Using a reverse loop to avoid issues with array mutation (when removing elements).
42
49
  for (let i = providersToLookup.length - 1; i >= 0; i--) {
43
50
  const providerToFind = providersToLookup[i];
51
+
52
+ // Check if the current provider supports this node.
44
53
  if (providerToFind.provider.isNodeSupported(currentNode)) {
54
+ // If provider supports the node, add it to the result map.
45
55
  resultMap[providerToFind.provider.name].nodes.push(currentNode);
56
+ // Increment the count of found nodes for this provider.
46
57
  providerToFind.foundNodes += 1;
58
+
59
+ // If the provider has found enough nodes, remove it from the lookup list.
47
60
  if (providerToFind.foundNodes >= providerToFind.maxNodesToPrefetch) {
48
61
  providersToLookup.splice(i, 1);
49
62
  }
50
63
  }
51
64
  }
65
+
66
+ // If the current node has children, add them to the queue to be visited.
52
67
  if (currentNode.content) {
53
68
  nodesToVisit.push(...currentNode.content.filter(node => node !== undefined));
54
69
  }
55
70
  }
71
+
72
+ // Return an array of the found nodes, grouped by provider.
56
73
  return Object.values(resultMap);
57
74
  }
@@ -30,6 +30,11 @@ import { isSSR } from '@atlaskit/editor-common/core-utils';
30
30
  * }
31
31
  */
32
32
 
33
+ /**
34
+ * Represents the payload passed to the callback function when data is fetched.
35
+ * It can either contain an error or the fetched data.
36
+ */
37
+
33
38
  /**
34
39
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
35
40
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -62,16 +67,15 @@ export var NodeDataProvider = /*#__PURE__*/function () {
62
67
  value: function setSSRData() {
63
68
  var ssrData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
64
69
  this.cacheVersion++;
65
- this.cache = Object.entries(ssrData).reduce(function (acc, _ref) {
70
+ this.cache = Object.fromEntries(Object.entries(ssrData).map(function (_ref) {
66
71
  var _ref2 = _slicedToArray(_ref, 2),
67
72
  key = _ref2[0],
68
73
  data = _ref2[1];
69
- acc[key] = {
70
- source: 'ssr',
71
- data: data
72
- };
73
- return acc;
74
- }, {});
74
+ return [key, {
75
+ data: data,
76
+ source: 'ssr'
77
+ }];
78
+ }));
75
79
  }
76
80
 
77
81
  /**
@@ -116,7 +120,7 @@ export var NodeDataProvider = /*#__PURE__*/function () {
116
120
  * ```
117
121
  *
118
122
  * @param node The node (or its ProseMirror representation) for which to fetch data.
119
- * @param callback The function to call when data is available.
123
+ * @param callback The callback function to call with the fetched data or an error.
120
124
  */
121
125
  }, {
122
126
  key: "getData",
@@ -129,48 +133,54 @@ export var NodeDataProvider = /*#__PURE__*/function () {
129
133
  key: "getDataAsync",
130
134
  value: function () {
131
135
  var _getDataAsync = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(node, callback) {
132
- var jsonNode, dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
136
+ var jsonNode, _dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
133
137
  return _regeneratorRuntime.wrap(function _callee$(_context) {
134
138
  while (1) switch (_context.prev = _context.next) {
135
139
  case 0:
140
+ _context.prev = 0;
136
141
  jsonNode = 'toJSON' in node ? node.toJSON() : node;
137
142
  if (this.isNodeSupported(jsonNode)) {
138
- _context.next = 4;
143
+ _context.next = 5;
139
144
  break;
140
145
  }
141
146
  // eslint-disable-next-line no-console
142
147
  console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
143
148
  return _context.abrupt("return");
144
- case 4:
145
- dataKey = this.nodeDataKey(jsonNode);
146
- dataFromCache = this.cache[dataKey];
149
+ case 5:
150
+ _dataKey = this.nodeDataKey(jsonNode);
151
+ dataFromCache = this.cache[_dataKey];
147
152
  if (!(dataFromCache !== undefined)) {
148
- _context.next = 18;
153
+ _context.next = 20;
149
154
  break;
150
155
  }
151
156
  if (!isPromise(dataFromCache.data)) {
152
- _context.next = 15;
157
+ _context.next = 17;
153
158
  break;
154
159
  }
155
160
  _context.t0 = callback;
156
- _context.next = 11;
161
+ _context.next = 12;
157
162
  return dataFromCache.data;
158
- case 11:
163
+ case 12:
159
164
  _context.t1 = _context.sent;
160
- (0, _context.t0)(_context.t1);
161
- _context.next = 16;
165
+ _context.t2 = {
166
+ data: _context.t1
167
+ };
168
+ (0, _context.t0)(_context.t2);
169
+ _context.next = 18;
162
170
  break;
163
- case 15:
164
- callback(dataFromCache.data);
165
- case 16:
171
+ case 17:
172
+ callback({
173
+ data: dataFromCache.data
174
+ });
175
+ case 18:
166
176
  if (!isSSR()) {
167
- _context.next = 18;
177
+ _context.next = 20;
168
178
  break;
169
179
  }
170
180
  return _context.abrupt("return");
171
- case 18:
181
+ case 20:
172
182
  if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
173
- _context.next = 27;
183
+ _context.next = 29;
174
184
  break;
175
185
  }
176
186
  // Store the current cache version before making the request,
@@ -181,32 +191,44 @@ export var NodeDataProvider = /*#__PURE__*/function () {
181
191
  value = _ref4[0];
182
192
  return value;
183
193
  }); // Store the promise in the cache to avoid multiple requests for the same data
184
- this.cache[dataKey] = {
194
+ this.cache[_dataKey] = {
185
195
  source: 'network',
186
196
  data: dataPromise
187
197
  };
188
- _context.next = 24;
198
+ _context.next = 26;
189
199
  return dataPromise;
190
- case 24:
200
+ case 26:
191
201
  data = _context.sent;
192
202
  // We need to call the callback with the data with result even if the cache version has changed,
193
203
  // so all promises that are waiting for the data can resolve.
194
- callback(data);
204
+ callback({
205
+ data: data
206
+ });
195
207
 
196
208
  // If the cache version has changed, we don't want to use the data from the network
197
209
  // because it could be stale data.
198
210
  if (cacheVersionBeforeRequest === this.cacheVersion) {
199
211
  // Replace promise with the resolved data in the cache
200
- this.cache[dataKey] = {
212
+ this.cache[_dataKey] = {
201
213
  source: 'network',
202
214
  data: data
203
215
  };
204
216
  }
205
- case 27:
217
+ case 29:
218
+ _context.next = 34;
219
+ break;
220
+ case 31:
221
+ _context.prev = 31;
222
+ _context.t3 = _context["catch"](0);
223
+ // If an error occurs, we call the callback with the error
224
+ callback({
225
+ error: _context.t3 instanceof Error ? _context.t3 : new Error(String(_context.t3))
226
+ });
227
+ case 34:
206
228
  case "end":
207
229
  return _context.stop();
208
230
  }
209
- }, _callee, this);
231
+ }, _callee, this, [[0, 31]]);
210
232
  }));
211
233
  function getDataAsync(_x, _x2) {
212
234
  return _getDataAsync.apply(this, arguments);
@@ -235,7 +257,13 @@ export var NodeDataProvider = /*#__PURE__*/function () {
235
257
  var _this = this;
236
258
  return new Promise(function (resolve, reject) {
237
259
  try {
238
- return _this.getData(node, resolve);
260
+ _this.getData(node, function (payload) {
261
+ if (payload.error) {
262
+ reject(payload.error);
263
+ } else {
264
+ resolve(payload.data);
265
+ }
266
+ });
239
267
  } catch (error) {
240
268
  reject(error);
241
269
  }
@@ -8,7 +8,9 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
8
8
  * @returns An array of objects, each containing a provider and the nodes that are supported by that provider.
9
9
  */
10
10
  export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
11
+ // Counter for the total number of visited nodes to limit the traversal.
11
12
  var totalVisitedNodesCount = 0;
13
+ // A map to store the results, with the provider name as the key.
12
14
  var resultMap = providers.reduce(function (acc, _ref) {
13
15
  var provider = _ref.provider;
14
16
  acc[provider.name] = {
@@ -21,6 +23,7 @@ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
21
23
  // It doesn't use `filter` function from `@atlaskit/adf-utils/traverse` because it does not support early stopping.
22
24
  // We need to stop traversing when we reach the maximum number of nodes to visit to support large documents.
23
25
 
26
+ // Create a list of providers for which we still need to find nodes.
24
27
  var providersToLookup = providers.filter(function (_ref2) {
25
28
  var maxNodesToPrefetch = _ref2.maxNodesToPrefetch;
26
29
  return maxNodesToPrefetch > 0;
@@ -30,32 +33,46 @@ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
30
33
  return {
31
34
  provider: provider,
32
35
  maxNodesToPrefetch: maxNodesToPrefetch,
33
- foundNodes: 0
36
+ foundNodes: 0 // Counter for nodes found for each provider.
34
37
  };
35
38
  });
39
+
40
+ // Queue for the breadth-first search (BFS), starting with the root document node.
36
41
  var nodesToVisit = [doc];
37
42
  var currentIndex = 0;
43
+ // The loop continues as long as there are nodes to visit, providers to look for,
44
+ // and the visited nodes limit has not been reached.
38
45
  while (currentIndex < nodesToVisit.length && providersToLookup.length > 0 && totalVisitedNodesCount < maxNodesToVisit) {
39
46
  totalVisitedNodesCount += 1;
40
47
  var currentNode = nodesToVisit[currentIndex];
41
48
  currentIndex++;
42
49
 
43
- // Using reverse loop to avoid issues with array mutation
50
+ // Using a reverse loop to avoid issues with array mutation (when removing elements).
44
51
  for (var i = providersToLookup.length - 1; i >= 0; i--) {
45
52
  var providerToFind = providersToLookup[i];
53
+
54
+ // Check if the current provider supports this node.
46
55
  if (providerToFind.provider.isNodeSupported(currentNode)) {
56
+ // If provider supports the node, add it to the result map.
47
57
  resultMap[providerToFind.provider.name].nodes.push(currentNode);
58
+ // Increment the count of found nodes for this provider.
48
59
  providerToFind.foundNodes += 1;
60
+
61
+ // If the provider has found enough nodes, remove it from the lookup list.
49
62
  if (providerToFind.foundNodes >= providerToFind.maxNodesToPrefetch) {
50
63
  providersToLookup.splice(i, 1);
51
64
  }
52
65
  }
53
66
  }
67
+
68
+ // If the current node has children, add them to the queue to be visited.
54
69
  if (currentNode.content) {
55
70
  nodesToVisit.push.apply(nodesToVisit, _toConsumableArray(currentNode.content.filter(function (node) {
56
71
  return node !== undefined;
57
72
  })));
58
73
  }
59
74
  }
75
+
76
+ // Return an array of the found nodes, grouped by provider.
60
77
  return Object.values(resultMap);
61
78
  }
@@ -13,6 +13,19 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
13
13
  type SSRData<Data> = {
14
14
  [dataKey: string]: Data;
15
15
  };
16
+ /**
17
+ * Represents the payload passed to the callback function when data is fetched.
18
+ * It can either contain an error or the fetched data.
19
+ */
20
+ type CallbackPayload<Data> = {
21
+ /** An error that occurred while fetching data. */
22
+ error: Error;
23
+ data?: undefined;
24
+ } | {
25
+ /** Fetched data for the node. */
26
+ data: Data;
27
+ error?: undefined;
28
+ };
16
29
  /**
17
30
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
18
31
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -100,9 +113,9 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
100
113
  * ```
101
114
  *
102
115
  * @param node The node (or its ProseMirror representation) for which to fetch data.
103
- * @param callback The function to call when data is available.
116
+ * @param callback The callback function to call with the fetched data or an error.
104
117
  */
105
- getData(node: Node | PMNode, callback: (data: Data) => void): void;
118
+ getData(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): void;
106
119
  private getDataAsync;
107
120
  /**
108
121
  * Fetches data for a given node and returns it as a Promise.
@@ -13,6 +13,19 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
13
13
  type SSRData<Data> = {
14
14
  [dataKey: string]: Data;
15
15
  };
16
+ /**
17
+ * Represents the payload passed to the callback function when data is fetched.
18
+ * It can either contain an error or the fetched data.
19
+ */
20
+ type CallbackPayload<Data> = {
21
+ /** An error that occurred while fetching data. */
22
+ error: Error;
23
+ data?: undefined;
24
+ } | {
25
+ /** Fetched data for the node. */
26
+ data: Data;
27
+ error?: undefined;
28
+ };
16
29
  /**
17
30
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
18
31
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -100,9 +113,9 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
100
113
  * ```
101
114
  *
102
115
  * @param node The node (or its ProseMirror representation) for which to fetch data.
103
- * @param callback The function to call when data is available.
116
+ * @param callback The callback function to call with the fetched data or an error.
104
117
  */
105
- getData(node: Node | PMNode, callback: (data: Data) => void): void;
118
+ getData(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): void;
106
119
  private getDataAsync;
107
120
  /**
108
121
  * Fetches data for a given node and returns it as a Promise.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/node-data-provider",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "Node data provider for @atlaskit/editor-core plugins and @atlaskit/renderer",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -22,7 +22,7 @@
22
22
  ".": "./src/index.ts"
23
23
  },
24
24
  "dependencies": {
25
- "@atlaskit/adf-schema": "^49.0.6",
25
+ "@atlaskit/adf-schema": "^50.0.1",
26
26
  "@atlaskit/adf-utils": "^19.20.0",
27
27
  "@atlaskit/editor-json-transformer": "^8.24.0",
28
28
  "@atlaskit/editor-prosemirror": "7.0.0",