@atlaskit/node-data-provider 4.1.2 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cjs/index.js +13 -226
  3. package/dist/cjs/node-data-provider.js +252 -0
  4. package/dist/cjs/utils/find-nodes-to-prefetch.js +68 -0
  5. package/dist/cjs/utils/prefetch-node-data-providers-data.js +165 -0
  6. package/dist/es2019/index.js +3 -190
  7. package/dist/es2019/node-data-provider.js +216 -0
  8. package/dist/es2019/utils/find-nodes-to-prefetch.js +57 -0
  9. package/dist/es2019/utils/prefetch-node-data-providers-data.js +128 -0
  10. package/dist/esm/index.js +3 -226
  11. package/dist/esm/node-data-provider.js +248 -0
  12. package/dist/esm/utils/find-nodes-to-prefetch.js +61 -0
  13. package/dist/esm/utils/prefetch-node-data-providers-data.js +161 -0
  14. package/dist/types/index.d.ts +2 -134
  15. package/dist/types/node-data-provider.d.ts +125 -0
  16. package/dist/types/utils/find-nodes-to-prefetch.d.ts +21 -0
  17. package/dist/types/utils/prefetch-node-data-providers-data.d.ts +107 -0
  18. package/dist/types-ts4.5/index.d.ts +2 -134
  19. package/dist/types-ts4.5/node-data-provider.d.ts +125 -0
  20. package/dist/types-ts4.5/utils/find-nodes-to-prefetch.d.ts +21 -0
  21. package/dist/types-ts4.5/utils/prefetch-node-data-providers-data.d.ts +107 -0
  22. package/package.json +6 -13
  23. package/cache/package.json +0 -15
  24. package/content/package.json +0 -15
  25. package/dist/cjs/cache.js +0 -145
  26. package/dist/cjs/consumption/_global-ndp-caches.js +0 -21
  27. package/dist/cjs/consumption/_internal-context.js +0 -77
  28. package/dist/cjs/consumption/_lru-cache.js +0 -45
  29. package/dist/cjs/consumption/content.js +0 -56
  30. package/dist/cjs/get-providers/confluence-page.js +0 -15
  31. package/dist/cjs/internal-types.js +0 -5
  32. package/dist/cjs/plugin-hooks.js +0 -100
  33. package/dist/cjs/providers/emoji.js +0 -54
  34. package/dist/es2019/cache.js +0 -96
  35. package/dist/es2019/consumption/_global-ndp-caches.js +0 -13
  36. package/dist/es2019/consumption/_internal-context.js +0 -71
  37. package/dist/es2019/consumption/_lru-cache.js +0 -30
  38. package/dist/es2019/consumption/content.js +0 -49
  39. package/dist/es2019/get-providers/confluence-page.js +0 -10
  40. package/dist/es2019/internal-types.js +0 -1
  41. package/dist/es2019/plugin-hooks.js +0 -69
  42. package/dist/es2019/providers/emoji.js +0 -26
  43. package/dist/esm/cache.js +0 -141
  44. package/dist/esm/consumption/_global-ndp-caches.js +0 -13
  45. package/dist/esm/consumption/_internal-context.js +0 -71
  46. package/dist/esm/consumption/_lru-cache.js +0 -38
  47. package/dist/esm/consumption/content.js +0 -49
  48. package/dist/esm/get-providers/confluence-page.js +0 -9
  49. package/dist/esm/internal-types.js +0 -1
  50. package/dist/esm/plugin-hooks.js +0 -93
  51. package/dist/esm/providers/emoji.js +0 -47
  52. package/dist/types/cache.d.ts +0 -61
  53. package/dist/types/consumption/_global-ndp-caches.d.ts +0 -8
  54. package/dist/types/consumption/_internal-context.d.ts +0 -32
  55. package/dist/types/consumption/_lru-cache.d.ts +0 -7
  56. package/dist/types/consumption/content.d.ts +0 -65
  57. package/dist/types/get-providers/confluence-page.d.ts +0 -6
  58. package/dist/types/internal-types.d.ts +0 -2
  59. package/dist/types/plugin-hooks.d.ts +0 -32
  60. package/dist/types/providers/emoji.d.ts +0 -10
  61. package/dist/types-ts4.5/cache.d.ts +0 -61
  62. package/dist/types-ts4.5/consumption/_global-ndp-caches.d.ts +0 -8
  63. package/dist/types-ts4.5/consumption/_internal-context.d.ts +0 -32
  64. package/dist/types-ts4.5/consumption/_lru-cache.d.ts +0 -7
  65. package/dist/types-ts4.5/consumption/content.d.ts +0 -65
  66. package/dist/types-ts4.5/get-providers/confluence-page.d.ts +0 -6
  67. package/dist/types-ts4.5/internal-types.d.ts +0 -2
  68. package/dist/types-ts4.5/plugin-hooks.d.ts +0 -32
  69. package/dist/types-ts4.5/providers/emoji.d.ts +0 -10
  70. package/emoji-provider/package.json +0 -15
  71. package/get-confluence-page-providers/package.json +0 -15
  72. package/plugin-hooks/package.json +0 -15
@@ -0,0 +1,128 @@
1
+ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
2
+
3
+ /**
4
+ * Represents the SSR data for a single provider.
5
+ * It's a map where each key is a unique node data key and the value is the prefetched data for that node.
6
+ *
7
+ * @example
8
+ * {
9
+ * 'node-id-1': { value: 'some data' },
10
+ * 'node-id-2': { value: 'other data' }
11
+ * }
12
+ */
13
+
14
+ /**
15
+ * Represents the aggregated SSR data for all node data providers.
16
+ * It's a map where each key is a provider's name and the value is the {@link SsrData} for that provider.
17
+ * This structure is used to hydrate the client-side caches.
18
+ *
19
+ * @example
20
+ * {
21
+ * 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
22
+ * 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
23
+ * }
24
+ */
25
+
26
+ /**
27
+ * Fetches data for nodes in the document that are supported by the given providers.
28
+ * This function will traverse the document and call the `fetchData` method for each node that is supported by the providers.
29
+ *
30
+ * @example
31
+ * ```
32
+ * const doc = JSON.parse('{"type": "doc", "content": [...] }');
33
+ * const providers = [
34
+ * {
35
+ * provider: new EditorCardProvider(),
36
+ * maxNodesToPrefetch: 10,
37
+ * timeout: 500,
38
+ * },
39
+ * {
40
+ * provider: new EditorMentionsProvider(),
41
+ * maxNodesToPrefetch: 50,
42
+ * timeout: 500,
43
+ * },
44
+ * ];
45
+ *
46
+ * window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
47
+ * providers,
48
+ * doc,
49
+ * timeout: 1_000,
50
+ * maxNodesToVisit: 2_000
51
+ * });
52
+ * ```
53
+ *
54
+ * @param props The properties for prefetching node data.
55
+ * @returns Record of provider names to their respective SSR data,
56
+ * where each SSR data is a record of node data keys to the fetched data.
57
+ */
58
+ export async function prefetchNodeDataProvidersData({
59
+ providers,
60
+ doc,
61
+ timeout,
62
+ maxNodesToVisit = Infinity
63
+ }) {
64
+ const providersWithDefaults = providers.map(({
65
+ provider,
66
+ maxNodesToPrefetch = Infinity,
67
+ timeout: providerTimeout = Infinity
68
+ }) => ({
69
+ provider,
70
+ maxNodesToPrefetch,
71
+ // Use the minimum of the global timeout and the provider-specific timeout
72
+ timeout: Math.min(providerTimeout, timeout)
73
+ }));
74
+ const providerTimeouts = providersWithDefaults.reduce((acc, {
75
+ provider,
76
+ timeout
77
+ }) => {
78
+ acc[provider.name] = timeout;
79
+ return acc;
80
+ }, {});
81
+ const nodesWithProviders = findNodesToPrefetch(doc, providersWithDefaults, maxNodesToVisit).map(({
82
+ provider,
83
+ nodes
84
+ }) => ({
85
+ provider,
86
+ nodes,
87
+ timeout: providerTimeouts[provider.name]
88
+ }));
89
+ const promises = nodesWithProviders.map(async ({
90
+ nodes,
91
+ provider,
92
+ timeout
93
+ }) => {
94
+ try {
95
+ const timeoutPromise = new Promise(resolve => {
96
+ setTimeout(() => {
97
+ resolve([]);
98
+ }, timeout);
99
+ });
100
+ const data = await Promise.race([provider.fetchNodesData(nodes), timeoutPromise]);
101
+ return {
102
+ provider,
103
+ nodes,
104
+ data
105
+ };
106
+ } catch {
107
+ return {
108
+ provider,
109
+ nodes,
110
+ data: []
111
+ };
112
+ }
113
+ });
114
+ const results = await Promise.all(promises);
115
+ return results.reduce((acc, {
116
+ provider,
117
+ nodes,
118
+ data
119
+ }) => {
120
+ acc[provider.name] = data.reduce((providerSsrData, nodeData, nodeIndex) => {
121
+ const node = nodes[nodeIndex];
122
+ const nodeDataKey = provider.nodeDataKey(node);
123
+ providerSsrData[nodeDataKey] = nodeData;
124
+ return providerSsrData;
125
+ }, {});
126
+ return acc;
127
+ }, {});
128
+ }
package/dist/esm/index.js CHANGED
@@ -1,227 +1,4 @@
1
- import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
- import _createClass from "@babel/runtime/helpers/createClass";
4
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
5
- import _regeneratorRuntime from "@babel/runtime/regenerator";
6
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
7
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
8
- /**
9
- * This is the base class for creating a node data provider for an editor plugin.
10
- *
11
- * ## Usage
12
- *
13
- * ### Create a provider
14
- *
15
- * @example
16
- * ```ts
17
- * class EmojiNodeDataProvider extends NodeDataProvider<
18
- * { attrs: EmojiAttributes },
19
- * { resolvedData: string }
20
- * > {
21
- * constructor({ existingCache }?: { existingCache: Record<string, { resolvedData: string }> }) {
22
- * super({ existingCache, nodeName: 'emoji' });
23
- * }
24
- * nodeToKey(node: { attrs: EmojiAttributes }): string {
25
- * return `${node.attrs.shortName}-${node.attrs.text}-${node.attrs.id}`;
26
- * }
27
- * resolve(node: { attrs: EmojiAttributes }, _?: { signal: AbortSignal }) {
28
- * return Promise.resolve({ resolvedData: 'resolved' });
29
- * }
30
- * }
31
- * ```
32
- *
33
- * ### Use the provider
34
- *
35
- * @example
36
- * ```ts
37
- * const emojiNodeDataProvider = new EmojiNodeDataProvider();
38
- * ```
39
- *
40
- * ### Caching
41
- *
42
- * @see {@link buildCaches} for more information on building caches.
43
- *
44
- * #### Load an existing provider with a cache
45
- *
46
- * @example
47
- * ```
48
- * await buildCaches({
49
- * adf: docFromSomewhere,
50
- * nodeDataProviders: [emojiNodeDataProvider],
51
- * signal: AbortSignal.timeout(5000),
52
- * });
53
- * emojiNodeDataProvider // { 'key': 'value' }
54
- * ```
55
- *
56
- * ### Load an new provider with an existing cache
57
- *
58
- * @example
59
- * ```
60
- * const provider1 = new ExampleNodeDataProvider();
61
- * await buildCaches({adf, nodeDataProviders: [provider1]})
62
- * provider1.cache // { 'key': 'value' }
63
- *
64
- * const provider2 = new ExampleNodeDataProvider({existingCache: provider1.cache});
65
- * ```
66
- */
67
- export var NodeDataProvider = /*#__PURE__*/function () {
68
- /**
69
- * This takes a node and returns a key that can be used to cache the result of the resolve function.
70
- */
1
+ /* eslint-disable @atlaskit/editor/no-re-export */
71
2
 
72
- /**
73
- * This returns the information required to render a node.
74
- *
75
- * If unresolvable, this method will throw an error.
76
- *
77
- * If signal is aborted, this method will return undefined.
78
- */
79
-
80
- /**
81
- * The adf node name this provider is responsible for.
82
- */
83
-
84
- function NodeDataProvider(_ref) {
85
- var _ref$existingCache = _ref.existingCache,
86
- existingCache = _ref$existingCache === void 0 ? {} : _ref$existingCache,
87
- nodeName = _ref.nodeName,
88
- nodeToKey = _ref.nodeToKey,
89
- resolve = _ref.resolve;
90
- _classCallCheck(this, NodeDataProvider);
91
- /**
92
- * This is added to ease building types
93
- */
94
- // @ts-ignore
95
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
- _defineProperty(this, "__node", {});
97
- _defineProperty(this, "pending", {});
98
- this.__cache = existingCache;
99
- this.nodeName = nodeName;
100
- this.nodeToKey = nodeToKey;
101
- this.resolve = resolve;
102
- }
103
-
104
- /**
105
- * Updates the providers cache.
106
- *
107
- * Useful in scenarios such as SSR where the cache is built on the server and then passed to the client.
108
- *
109
- * Avoids the need to provide the cache to the constructor (to allow decoupling creation of node data providers from cache building),
110
- * and allow for caching to be managed at a group level across multiple providers.
111
- *
112
- * This is not expected to be used by consumers, for internal consumption examples;
113
- * @see {@link buildCaches}
114
- *
115
- */
116
- return _createClass(NodeDataProvider, [{
117
- key: "updateCache",
118
- value: function updateCache(cache, options) {
119
- switch (options.strategy) {
120
- case 'merge-override':
121
- this.__cache = _objectSpread(_objectSpread({}, this.__cache), cache);
122
- return;
123
- case 'replace':
124
- this.__cache = cache;
125
- return;
126
- }
127
- }
128
-
129
- /**
130
- * This is the cache for the provider.
131
- */
132
- }, {
133
- key: "cache",
134
- get: function get() {
135
- return this.__cache;
136
- }
137
- }, {
138
- key: "get",
139
- value: function get(node, _) {
140
- var _this = this;
141
- var key = this.nodeToKey(node);
142
- var cached = this.cache[key];
143
- if (cached) {
144
- return cached;
145
- }
146
-
147
- // Get could be called from a variety of sources;
148
- // - a Node Data Provider
149
- // - a cache build
150
- // - something else
151
- //
152
- // We want to avoid triggering multiple resolves for the same node -- so we keep track of pending requests
153
- // and share them across any overlapping gets.
154
- //
155
- // When a get is cancelled -- we only want to cancel the shared resolve if all signals are aborted
156
- // so we keep track of all signals that are not aborted.
157
-
158
- var originalSignal = (_ === null || _ === void 0 ? void 0 : _.signal) || new AbortController().signal;
159
- if (!this.pending[key]) {
160
- var abortController = new AbortController();
161
- this.pending[key] = {
162
- // eslint-disable-next-line no-async-promise-executor
163
- resolving: new Promise( /*#__PURE__*/function () {
164
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(res, rej) {
165
- var result;
166
- return _regeneratorRuntime.wrap(function _callee$(_context) {
167
- while (1) switch (_context.prev = _context.next) {
168
- case 0:
169
- _context.prev = 0;
170
- _context.next = 3;
171
- return _this.resolve(node, {
172
- signal: abortController.signal
173
- }).catch(function (res) {
174
- return res(undefined);
175
- });
176
- case 3:
177
- result = _context.sent;
178
- res(result);
179
- _context.next = 10;
180
- break;
181
- case 7:
182
- _context.prev = 7;
183
- _context.t0 = _context["catch"](0);
184
- res(undefined);
185
- case 10:
186
- case "end":
187
- return _context.stop();
188
- }
189
- }, _callee, null, [[0, 7]]);
190
- }));
191
- return function (_x, _x2) {
192
- return _ref2.apply(this, arguments);
193
- };
194
- }()),
195
- abortController: abortController,
196
- activeSignals: [originalSignal]
197
- };
198
- }
199
- var handleAbort = function handleAbort() {
200
- _this.pending[key].activeSignals = _this.pending[key].activeSignals.filter(function (activeSignal) {
201
- return activeSignal !== originalSignal;
202
- });
203
- if (_this.pending[key].activeSignals.length === 0) {
204
- // abort the resolution if all signals are aborted
205
- _this.pending[key].abortController.abort();
206
- }
207
- };
208
-
209
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
210
- originalSignal === null || originalSignal === void 0 || originalSignal.addEventListener('abort', handleAbort);
211
- this.pending[key].resolving.then(function (resolvedValue) {
212
- if (resolvedValue) {
213
- _this.cache[key] = resolvedValue;
214
- }
215
- // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
216
- originalSignal === null || originalSignal === void 0 || originalSignal.removeEventListener('abort', handleAbort);
217
- return resolvedValue;
218
- });
219
- return this.pending[key].resolving;
220
- }
221
- }]);
222
- }();
223
-
224
- // The purpose of this type is to ensure that either a DocNode or a PMNode is passed in
225
- // to the provider.
226
- // It is not opinionated about which nodes are used, so `any` is used here to allow
227
- // compatibility with both DocNodes and PMNodes.
3
+ export { NodeDataProvider } from './node-data-provider';
4
+ export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
@@ -0,0 +1,248 @@
1
+ import _typeof from "@babel/runtime/helpers/typeof";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
5
+ import _createClass from "@babel/runtime/helpers/createClass";
6
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
7
+ import { isSSR } from '@atlaskit/editor-common/core-utils';
8
+
9
+ /**
10
+ * Represents the SSR data for a single provider.
11
+ * It's a map where each key is a unique node data key and the value is the prefetched data for that node.
12
+ *
13
+ * @example
14
+ * {
15
+ * 'node-id-1': { value: 'some data' },
16
+ * 'node-id-2': { value: 'other data' }
17
+ * }
18
+ */
19
+
20
+ /**
21
+ * Represents the cached data for a Node Data Provider.
22
+ * Each key is a unique node data key, and the value is an object containing:
23
+ * - `source`: Indicates whether the data was fetched from SSR or the network.
24
+ * - `data`: The actual data, which can be either a resolved value or a Promise.
25
+ *
26
+ * @example
27
+ * {
28
+ * 'node-id-1': { source: 'ssr', data: { value: 'some data' } },
29
+ * 'node-id-2': { source: 'network', data: Promise.resolve({ value: 'other data' }) }
30
+ * }
31
+ */
32
+
33
+ /**
34
+ * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
35
+ * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
36
+ *
37
+ * @template Node The specific type of JSONNode this provider supports.
38
+ * @template Data The type of data this provider fetches and manages.
39
+ */
40
+ export var NodeDataProvider = /*#__PURE__*/function () {
41
+ function NodeDataProvider() {
42
+ _classCallCheck(this, NodeDataProvider);
43
+ this.cacheVersion = 0;
44
+ this.cache = {};
45
+ }
46
+
47
+ /**
48
+ * Sets the SSR data for the provider.
49
+ * This pre-populates the cache with data rendered on the server, preventing redundant network requests on the client.
50
+ * Calling this method will invalidate the existing cache.
51
+ *
52
+ * @example
53
+ * ```
54
+ * const ssrData = window.__SSR_NODE_DATA__ || {};
55
+ * nodeDataProvider.setSSRData(ssrData);
56
+ * ```
57
+ *
58
+ * @param ssrData A map of node data keys to their corresponding data.
59
+ */
60
+ return _createClass(NodeDataProvider, [{
61
+ key: "setSSRData",
62
+ value: function setSSRData() {
63
+ var ssrData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
64
+ this.cacheVersion++;
65
+ this.cache = Object.entries(ssrData).reduce(function (acc, _ref) {
66
+ var _ref2 = _slicedToArray(_ref, 2),
67
+ key = _ref2[0],
68
+ data = _ref2[1];
69
+ acc[key] = {
70
+ source: 'ssr',
71
+ data: data
72
+ };
73
+ return acc;
74
+ }, {});
75
+ }
76
+
77
+ /**
78
+ * Clears all cached data.
79
+ * This increments the internal cache version, invalidating any pending network requests.
80
+ *
81
+ * @example
82
+ * ```
83
+ * function useMyNodeDataProvider(contentId: string) {
84
+ * const nodeDataProvider = new MyNodeDataProvider();
85
+ *
86
+ * // Reset the cache when the contentId changes (e.g., when the user navigates to a different page).
87
+ * useEffect(() => {
88
+ * nodeDataProvider.resetCache();
89
+ * }, [contentId]);
90
+ *
91
+ * return nodeDataProvider;
92
+ * }
93
+ * ```
94
+ */
95
+ }, {
96
+ key: "resetCache",
97
+ value: function resetCache() {
98
+ this.cacheVersion++;
99
+ this.cache = {};
100
+ }
101
+
102
+ /**
103
+ * Fetches data for a given node using a cache-first-then-network strategy.
104
+ *
105
+ * The provided callback may be called multiple times:
106
+ * 1. Immediately with data from the SSR cache, if available.
107
+ * 2. Asynchronously with data fetched from the network.
108
+ *
109
+ * @example
110
+ * ```
111
+ * const nodeDataProvider = new MyNodeDataProvider();
112
+ *
113
+ * nodeDataProvider.getData(node, (data) => {
114
+ * console.log('Node data:', data);
115
+ * });
116
+ * ```
117
+ *
118
+ * @param node The node (or its ProseMirror representation) for which to fetch data.
119
+ * @param callback The function to call when data is available.
120
+ */
121
+ }, {
122
+ key: "getData",
123
+ value: function getData(node, callback) {
124
+ // Move implementation to a separate async method
125
+ // to keep this method synchronous and avoid async/await in the public API.
126
+ void this.getDataAsync(node, callback);
127
+ }
128
+ }, {
129
+ key: "getDataAsync",
130
+ value: function () {
131
+ var _getDataAsync = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(node, callback) {
132
+ var jsonNode, dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
133
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
134
+ while (1) switch (_context.prev = _context.next) {
135
+ case 0:
136
+ jsonNode = 'toJSON' in node ? node.toJSON() : node;
137
+ if (this.isNodeSupported(jsonNode)) {
138
+ _context.next = 4;
139
+ break;
140
+ }
141
+ // eslint-disable-next-line no-console
142
+ console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
143
+ return _context.abrupt("return");
144
+ case 4:
145
+ dataKey = this.nodeDataKey(jsonNode);
146
+ dataFromCache = this.cache[dataKey];
147
+ if (!(dataFromCache !== undefined)) {
148
+ _context.next = 18;
149
+ break;
150
+ }
151
+ if (!isPromise(dataFromCache.data)) {
152
+ _context.next = 15;
153
+ break;
154
+ }
155
+ _context.t0 = callback;
156
+ _context.next = 11;
157
+ return dataFromCache.data;
158
+ case 11:
159
+ _context.t1 = _context.sent;
160
+ (0, _context.t0)(_context.t1);
161
+ _context.next = 16;
162
+ break;
163
+ case 15:
164
+ callback(dataFromCache.data);
165
+ case 16:
166
+ if (!isSSR()) {
167
+ _context.next = 18;
168
+ break;
169
+ }
170
+ return _context.abrupt("return");
171
+ case 18:
172
+ if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
173
+ _context.next = 27;
174
+ break;
175
+ }
176
+ // Store the current cache version before making the request,
177
+ // so we can check if the cache has changed while we are waiting for the network response.
178
+ cacheVersionBeforeRequest = this.cacheVersion;
179
+ dataPromise = this.fetchNodesData([jsonNode]).then(function (_ref3) {
180
+ var _ref4 = _slicedToArray(_ref3, 1),
181
+ value = _ref4[0];
182
+ return value;
183
+ }); // Store the promise in the cache to avoid multiple requests for the same data
184
+ this.cache[dataKey] = {
185
+ source: 'network',
186
+ data: dataPromise
187
+ };
188
+ _context.next = 24;
189
+ return dataPromise;
190
+ case 24:
191
+ data = _context.sent;
192
+ // We need to call the callback with the data with result even if the cache version has changed,
193
+ // so all promises that are waiting for the data can resolve.
194
+ callback(data);
195
+
196
+ // If the cache version has changed, we don't want to use the data from the network
197
+ // because it could be stale data.
198
+ if (cacheVersionBeforeRequest === this.cacheVersion) {
199
+ // Replace promise with the resolved data in the cache
200
+ this.cache[dataKey] = {
201
+ source: 'network',
202
+ data: data
203
+ };
204
+ }
205
+ case 27:
206
+ case "end":
207
+ return _context.stop();
208
+ }
209
+ }, _callee, this);
210
+ }));
211
+ function getDataAsync(_x, _x2) {
212
+ return _getDataAsync.apply(this, arguments);
213
+ }
214
+ return getDataAsync;
215
+ }()
216
+ /**
217
+ * Fetches data for a given node and returns it as a Promise.
218
+ * This is a convenience wrapper around the `data` method for use with async/await.
219
+ *
220
+ * Note: This promise resolves with the *first* available data, which could be from the SSR cache or the network.
221
+ * It may not provide the most up-to-date data if a network fetch is in progress.
222
+ *
223
+ * Note: This method is only for migration purposes. Use {@link getData} in new code instead.
224
+ *
225
+ * @private
226
+ * @deprecated Don't use this method, use {@link getData} method instead.
227
+ * This method is only for migration purposes.
228
+ *
229
+ * @param node The node (or its ProseMirror representation) for which to fetch data.
230
+ * @returns A promise that resolves with the node's data.
231
+ */
232
+ }, {
233
+ key: "getDataAsPromise_DO_NOT_USE_OUTSIDE_MIGRATIONS",
234
+ value: function getDataAsPromise_DO_NOT_USE_OUTSIDE_MIGRATIONS(node) {
235
+ var _this = this;
236
+ return new Promise(function (resolve, reject) {
237
+ try {
238
+ return _this.getData(node, resolve);
239
+ } catch (error) {
240
+ reject(error);
241
+ }
242
+ });
243
+ }
244
+ }]);
245
+ }();
246
+ function isPromise(value) {
247
+ return _typeof(value) === 'object' && value !== null && 'then' in value && typeof value.then === 'function';
248
+ }
@@ -0,0 +1,61 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ /**
3
+ * Finds nodes in the document that are supported by the given providers, up to a maximum number of nodes.
4
+ *
5
+ * @param doc The document to search for nodes.
6
+ * @param providers An array of providers with their maximum nodes to prefetch.
7
+ * @param maxNodesToVisit The maximum number of nodes to visit in the document.
8
+ * @returns An array of objects, each containing a provider and the nodes that are supported by that provider.
9
+ */
10
+ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
11
+ var totalVisitedNodesCount = 0;
12
+ var resultMap = providers.reduce(function (acc, _ref) {
13
+ var provider = _ref.provider;
14
+ acc[provider.name] = {
15
+ provider: provider,
16
+ nodes: []
17
+ };
18
+ return acc;
19
+ }, {});
20
+
21
+ // It doesn't use `filter` function from `@atlaskit/adf-utils/traverse` because it does not support early stopping.
22
+ // We need to stop traversing when we reach the maximum number of nodes to visit to support large documents.
23
+
24
+ var providersToLookup = providers.filter(function (_ref2) {
25
+ var maxNodesToPrefetch = _ref2.maxNodesToPrefetch;
26
+ return maxNodesToPrefetch > 0;
27
+ }).map(function (_ref3) {
28
+ var provider = _ref3.provider,
29
+ maxNodesToPrefetch = _ref3.maxNodesToPrefetch;
30
+ return {
31
+ provider: provider,
32
+ maxNodesToPrefetch: maxNodesToPrefetch,
33
+ foundNodes: 0
34
+ };
35
+ });
36
+ var nodesToVisit = [doc];
37
+ var currentIndex = 0;
38
+ while (currentIndex < nodesToVisit.length && providersToLookup.length > 0 && totalVisitedNodesCount < maxNodesToVisit) {
39
+ totalVisitedNodesCount += 1;
40
+ var currentNode = nodesToVisit[currentIndex];
41
+ currentIndex++;
42
+
43
+ // Using reverse loop to avoid issues with array mutation
44
+ for (var i = providersToLookup.length - 1; i >= 0; i--) {
45
+ var providerToFind = providersToLookup[i];
46
+ if (providerToFind.provider.isNodeSupported(currentNode)) {
47
+ resultMap[providerToFind.provider.name].nodes.push(currentNode);
48
+ providerToFind.foundNodes += 1;
49
+ if (providerToFind.foundNodes >= providerToFind.maxNodesToPrefetch) {
50
+ providersToLookup.splice(i, 1);
51
+ }
52
+ }
53
+ }
54
+ if (currentNode.content) {
55
+ nodesToVisit.push.apply(nodesToVisit, _toConsumableArray(currentNode.content.filter(function (node) {
56
+ return node !== undefined;
57
+ })));
58
+ }
59
+ }
60
+ return Object.values(resultMap);
61
+ }