@atlaskit/editor-synced-block-provider 12.1.5 → 12.2.1
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 +23 -0
- package/dist/cjs/entry-points/resourceId.js +8 -1
- package/dist/cjs/utils/migrateSyncBlockIds.js +108 -0
- package/dist/es2019/entry-points/resourceId.js +2 -1
- package/dist/es2019/utils/migrateSyncBlockIds.js +111 -0
- package/dist/esm/entry-points/resourceId.js +2 -1
- package/dist/esm/utils/migrateSyncBlockIds.js +102 -0
- package/dist/types/entry-points/resourceId.d.ts +2 -0
- package/dist/types/utils/migrateSyncBlockIds.d.ts +16 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @atlaskit/editor-synced-block-provider
|
|
2
2
|
|
|
3
|
+
## 12.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`c5bc5493c5486`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c5bc5493c5486) -
|
|
8
|
+
Fix migrateSyncBlockIds mutating the caller's input ADF document. traverse() falls back to
|
|
9
|
+
mutating a node in place whenever its visitor returns undefined, so the transform now always
|
|
10
|
+
returns a copy instead.
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
13
|
+
## 12.2.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [`6cf6b735bf90a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6cf6b735bf90a) -
|
|
18
|
+
Add migrateSyncBlockIds to the utils/resourceId entry point. Rewrites syncBlock and
|
|
19
|
+
bodiedSyncBlock identifiers so a document stays internally consistent after cloud-to-cloud
|
|
20
|
+
migration, preserving block UUIDs by default and supporting optional UUID regeneration.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
|
|
3
26
|
## 12.1.5
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
|
@@ -9,10 +9,17 @@ Object.defineProperty(exports, "createResourceIdForReference", {
|
|
|
9
9
|
return _resourceId.createResourceIdForReference;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
+
Object.defineProperty(exports, "migrateSyncBlockIds", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function get() {
|
|
15
|
+
return _migrateSyncBlockIds.migrateSyncBlockIds;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
12
18
|
Object.defineProperty(exports, "parseResourceId", {
|
|
13
19
|
enumerable: true,
|
|
14
20
|
get: function get() {
|
|
15
21
|
return _resourceId.parseResourceId;
|
|
16
22
|
}
|
|
17
23
|
});
|
|
18
|
-
var _resourceId = require("../utils/resourceId");
|
|
24
|
+
var _resourceId = require("../utils/resourceId");
|
|
25
|
+
var _migrateSyncBlockIds = require("../utils/migrateSyncBlockIds");
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.migrateSyncBlockIds = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _traverse = require("@atlaskit/adf-utils/traverse");
|
|
10
|
+
var _resourceId = require("./resourceId");
|
|
11
|
+
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; }
|
|
12
|
+
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) { (0, _defineProperty2.default)(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; }
|
|
13
|
+
/*
|
|
14
|
+
* Rewrites `syncBlock`/`bodiedSyncBlock` identifiers so a document stays internally
|
|
15
|
+
* consistent after cloud-to-cloud migration or a copy to different host content.
|
|
16
|
+
*
|
|
17
|
+
* Source nodes (`bodiedSyncBlock`) carry a bare UUID as both `resourceId` and `localId` -
|
|
18
|
+
* the host content ID never appears in the ADF, only in the block ARI, which Block
|
|
19
|
+
* Service derives from the cloud ID and parent content ID at runtime. Reference nodes
|
|
20
|
+
* (`syncBlock`) carry `{product}/{contentId}/{sourceUuid}`. So preserving the UUID (the
|
|
21
|
+
* default) needs no edit on source nodes, and only remaps the `contentId` segment on
|
|
22
|
+
* references - which also keeps re-runs idempotent.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** Bails to `undefined` on anything that isn't a syncBlock/bodiedSyncBlock attrs shape. */
|
|
26
|
+
var parseSyncBlockAttrs = function parseSyncBlockAttrs(attrs) {
|
|
27
|
+
var resourceId = attrs.resourceId,
|
|
28
|
+
localId = attrs.localId;
|
|
29
|
+
if (typeof resourceId !== 'string' || resourceId === '') {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
resourceId: resourceId,
|
|
34
|
+
localId: typeof localId === 'string' ? localId : undefined
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
var migrateAttrs = function migrateAttrs(attrs, resolvers, unresolvedContentIds) {
|
|
38
|
+
var _resolvers$resolveUui3;
|
|
39
|
+
var resourceId = attrs.resourceId,
|
|
40
|
+
localId = attrs.localId;
|
|
41
|
+
var parsed = (0, _resourceId.parseResourceId)(resourceId);
|
|
42
|
+
if (parsed) {
|
|
43
|
+
var _resolvers$resolveUui, _resolvers$resolveUui2;
|
|
44
|
+
var mappedContentId = resolvers.resolveContentId(parsed.contentId, parsed.product);
|
|
45
|
+
if (mappedContentId === undefined) {
|
|
46
|
+
unresolvedContentIds.add(parsed.contentId);
|
|
47
|
+
}
|
|
48
|
+
var nextContentId = mappedContentId !== null && mappedContentId !== void 0 ? mappedContentId : parsed.contentId;
|
|
49
|
+
var _nextUuid = (_resolvers$resolveUui = (_resolvers$resolveUui2 = resolvers.resolveUuid) === null || _resolvers$resolveUui2 === void 0 ? void 0 : _resolvers$resolveUui2.call(resolvers, parsed.uuid)) !== null && _resolvers$resolveUui !== void 0 ? _resolvers$resolveUui : parsed.uuid;
|
|
50
|
+
if (nextContentId === parsed.contentId && _nextUuid === parsed.uuid) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
resourceId: (0, _resourceId.createResourceIdForReference)(parsed.product, nextContentId, _nextUuid),
|
|
55
|
+
// Only mirror the UUID when this node's localId tracked it in the first place.
|
|
56
|
+
localId: localId === parsed.uuid ? _nextUuid : localId
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// bare-UUID source node: no content ID segment to remap
|
|
61
|
+
var nextUuid = (_resolvers$resolveUui3 = resolvers.resolveUuid) === null || _resolvers$resolveUui3 === void 0 ? void 0 : _resolvers$resolveUui3.call(resolvers, resourceId);
|
|
62
|
+
if (nextUuid === undefined || nextUuid === resourceId) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
resourceId: nextUuid,
|
|
67
|
+
localId: localId === resourceId ? nextUuid : localId
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** `isTransformed` is `false` when no node changed, so callers can skip persisting the result. */
|
|
72
|
+
var migrateSyncBlockIds = exports.migrateSyncBlockIds = function migrateSyncBlockIds(adf, resolvers) {
|
|
73
|
+
var unresolvedContentIds = new Set();
|
|
74
|
+
var isTransformed = false;
|
|
75
|
+
|
|
76
|
+
// Always returns a copy, even when nothing changes: traverse() falls back to mutating
|
|
77
|
+
// the original node in place (its `content` array gets reassigned) whenever a visitor
|
|
78
|
+
// returns undefined, so returning undefined here would leak that mutation onto the
|
|
79
|
+
// caller's input document.
|
|
80
|
+
var migrateNode = function migrateNode(node) {
|
|
81
|
+
var syncBlockAttrs = node.attrs && parseSyncBlockAttrs(node.attrs);
|
|
82
|
+
if (!syncBlockAttrs) {
|
|
83
|
+
return _objectSpread({}, node);
|
|
84
|
+
}
|
|
85
|
+
var nextAttrs = migrateAttrs(syncBlockAttrs, resolvers, unresolvedContentIds);
|
|
86
|
+
if (!nextAttrs) {
|
|
87
|
+
return _objectSpread({}, node);
|
|
88
|
+
}
|
|
89
|
+
isTransformed = true;
|
|
90
|
+
return _objectSpread(_objectSpread({}, node), {}, {
|
|
91
|
+
attrs: _objectSpread(_objectSpread({}, node.attrs), nextAttrs)
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
var transformedAdf = (0, _traverse.traverse)(adf, {
|
|
95
|
+
syncBlock: migrateNode,
|
|
96
|
+
bodiedSyncBlock: migrateNode
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// traverse() only returns false when a visitor deletes the root node; migrateNode never does.
|
|
100
|
+
if (transformedAdf === false) {
|
|
101
|
+
throw new Error('migrateSyncBlockIds: traverse unexpectedly removed the root node');
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
transformedAdf: transformedAdf,
|
|
105
|
+
isTransformed: isTransformed,
|
|
106
|
+
unresolvedContentIds: Array.from(unresolvedContentIds)
|
|
107
|
+
};
|
|
108
|
+
};
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
|
-
export { parseResourceId, createResourceIdForReference } from '../utils/resourceId';
|
|
2
|
+
export { parseResourceId, createResourceIdForReference } from '../utils/resourceId';
|
|
3
|
+
export { migrateSyncBlockIds } from '../utils/migrateSyncBlockIds';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { traverse } from '@atlaskit/adf-utils/traverse';
|
|
2
|
+
import { createResourceIdForReference, parseResourceId } from './resourceId';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Rewrites `syncBlock`/`bodiedSyncBlock` identifiers so a document stays internally
|
|
6
|
+
* consistent after cloud-to-cloud migration or a copy to different host content.
|
|
7
|
+
*
|
|
8
|
+
* Source nodes (`bodiedSyncBlock`) carry a bare UUID as both `resourceId` and `localId` -
|
|
9
|
+
* the host content ID never appears in the ADF, only in the block ARI, which Block
|
|
10
|
+
* Service derives from the cloud ID and parent content ID at runtime. Reference nodes
|
|
11
|
+
* (`syncBlock`) carry `{product}/{contentId}/{sourceUuid}`. So preserving the UUID (the
|
|
12
|
+
* default) needs no edit on source nodes, and only remaps the `contentId` segment on
|
|
13
|
+
* references - which also keeps re-runs idempotent.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Bails to `undefined` on anything that isn't a syncBlock/bodiedSyncBlock attrs shape. */
|
|
17
|
+
const parseSyncBlockAttrs = attrs => {
|
|
18
|
+
const {
|
|
19
|
+
resourceId,
|
|
20
|
+
localId
|
|
21
|
+
} = attrs;
|
|
22
|
+
if (typeof resourceId !== 'string' || resourceId === '') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
resourceId,
|
|
27
|
+
localId: typeof localId === 'string' ? localId : undefined
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const migrateAttrs = (attrs, resolvers, unresolvedContentIds) => {
|
|
31
|
+
var _resolvers$resolveUui3;
|
|
32
|
+
const {
|
|
33
|
+
resourceId,
|
|
34
|
+
localId
|
|
35
|
+
} = attrs;
|
|
36
|
+
const parsed = parseResourceId(resourceId);
|
|
37
|
+
if (parsed) {
|
|
38
|
+
var _resolvers$resolveUui, _resolvers$resolveUui2;
|
|
39
|
+
const mappedContentId = resolvers.resolveContentId(parsed.contentId, parsed.product);
|
|
40
|
+
if (mappedContentId === undefined) {
|
|
41
|
+
unresolvedContentIds.add(parsed.contentId);
|
|
42
|
+
}
|
|
43
|
+
const nextContentId = mappedContentId !== null && mappedContentId !== void 0 ? mappedContentId : parsed.contentId;
|
|
44
|
+
const nextUuid = (_resolvers$resolveUui = (_resolvers$resolveUui2 = resolvers.resolveUuid) === null || _resolvers$resolveUui2 === void 0 ? void 0 : _resolvers$resolveUui2.call(resolvers, parsed.uuid)) !== null && _resolvers$resolveUui !== void 0 ? _resolvers$resolveUui : parsed.uuid;
|
|
45
|
+
if (nextContentId === parsed.contentId && nextUuid === parsed.uuid) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
resourceId: createResourceIdForReference(parsed.product, nextContentId, nextUuid),
|
|
50
|
+
// Only mirror the UUID when this node's localId tracked it in the first place.
|
|
51
|
+
localId: localId === parsed.uuid ? nextUuid : localId
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// bare-UUID source node: no content ID segment to remap
|
|
56
|
+
const nextUuid = (_resolvers$resolveUui3 = resolvers.resolveUuid) === null || _resolvers$resolveUui3 === void 0 ? void 0 : _resolvers$resolveUui3.call(resolvers, resourceId);
|
|
57
|
+
if (nextUuid === undefined || nextUuid === resourceId) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
resourceId: nextUuid,
|
|
62
|
+
localId: localId === resourceId ? nextUuid : localId
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** `isTransformed` is `false` when no node changed, so callers can skip persisting the result. */
|
|
67
|
+
export const migrateSyncBlockIds = (adf, resolvers) => {
|
|
68
|
+
const unresolvedContentIds = new Set();
|
|
69
|
+
let isTransformed = false;
|
|
70
|
+
|
|
71
|
+
// Always returns a copy, even when nothing changes: traverse() falls back to mutating
|
|
72
|
+
// the original node in place (its `content` array gets reassigned) whenever a visitor
|
|
73
|
+
// returns undefined, so returning undefined here would leak that mutation onto the
|
|
74
|
+
// caller's input document.
|
|
75
|
+
const migrateNode = node => {
|
|
76
|
+
const syncBlockAttrs = node.attrs && parseSyncBlockAttrs(node.attrs);
|
|
77
|
+
if (!syncBlockAttrs) {
|
|
78
|
+
return {
|
|
79
|
+
...node
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const nextAttrs = migrateAttrs(syncBlockAttrs, resolvers, unresolvedContentIds);
|
|
83
|
+
if (!nextAttrs) {
|
|
84
|
+
return {
|
|
85
|
+
...node
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
isTransformed = true;
|
|
89
|
+
return {
|
|
90
|
+
...node,
|
|
91
|
+
attrs: {
|
|
92
|
+
...node.attrs,
|
|
93
|
+
...nextAttrs
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const transformedAdf = traverse(adf, {
|
|
98
|
+
syncBlock: migrateNode,
|
|
99
|
+
bodiedSyncBlock: migrateNode
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// traverse() only returns false when a visitor deletes the root node; migrateNode never does.
|
|
103
|
+
if (transformedAdf === false) {
|
|
104
|
+
throw new Error('migrateSyncBlockIds: traverse unexpectedly removed the root node');
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
transformedAdf,
|
|
108
|
+
isTransformed,
|
|
109
|
+
unresolvedContentIds: Array.from(unresolvedContentIds)
|
|
110
|
+
};
|
|
111
|
+
};
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
|
-
export { parseResourceId, createResourceIdForReference } from '../utils/resourceId';
|
|
2
|
+
export { parseResourceId, createResourceIdForReference } from '../utils/resourceId';
|
|
3
|
+
export { migrateSyncBlockIds } from '../utils/migrateSyncBlockIds';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
import { traverse } from '@atlaskit/adf-utils/traverse';
|
|
5
|
+
import { createResourceIdForReference, parseResourceId } from './resourceId';
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Rewrites `syncBlock`/`bodiedSyncBlock` identifiers so a document stays internally
|
|
9
|
+
* consistent after cloud-to-cloud migration or a copy to different host content.
|
|
10
|
+
*
|
|
11
|
+
* Source nodes (`bodiedSyncBlock`) carry a bare UUID as both `resourceId` and `localId` -
|
|
12
|
+
* the host content ID never appears in the ADF, only in the block ARI, which Block
|
|
13
|
+
* Service derives from the cloud ID and parent content ID at runtime. Reference nodes
|
|
14
|
+
* (`syncBlock`) carry `{product}/{contentId}/{sourceUuid}`. So preserving the UUID (the
|
|
15
|
+
* default) needs no edit on source nodes, and only remaps the `contentId` segment on
|
|
16
|
+
* references - which also keeps re-runs idempotent.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Bails to `undefined` on anything that isn't a syncBlock/bodiedSyncBlock attrs shape. */
|
|
20
|
+
var parseSyncBlockAttrs = function parseSyncBlockAttrs(attrs) {
|
|
21
|
+
var resourceId = attrs.resourceId,
|
|
22
|
+
localId = attrs.localId;
|
|
23
|
+
if (typeof resourceId !== 'string' || resourceId === '') {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
resourceId: resourceId,
|
|
28
|
+
localId: typeof localId === 'string' ? localId : undefined
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
var migrateAttrs = function migrateAttrs(attrs, resolvers, unresolvedContentIds) {
|
|
32
|
+
var _resolvers$resolveUui3;
|
|
33
|
+
var resourceId = attrs.resourceId,
|
|
34
|
+
localId = attrs.localId;
|
|
35
|
+
var parsed = parseResourceId(resourceId);
|
|
36
|
+
if (parsed) {
|
|
37
|
+
var _resolvers$resolveUui, _resolvers$resolveUui2;
|
|
38
|
+
var mappedContentId = resolvers.resolveContentId(parsed.contentId, parsed.product);
|
|
39
|
+
if (mappedContentId === undefined) {
|
|
40
|
+
unresolvedContentIds.add(parsed.contentId);
|
|
41
|
+
}
|
|
42
|
+
var nextContentId = mappedContentId !== null && mappedContentId !== void 0 ? mappedContentId : parsed.contentId;
|
|
43
|
+
var _nextUuid = (_resolvers$resolveUui = (_resolvers$resolveUui2 = resolvers.resolveUuid) === null || _resolvers$resolveUui2 === void 0 ? void 0 : _resolvers$resolveUui2.call(resolvers, parsed.uuid)) !== null && _resolvers$resolveUui !== void 0 ? _resolvers$resolveUui : parsed.uuid;
|
|
44
|
+
if (nextContentId === parsed.contentId && _nextUuid === parsed.uuid) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
resourceId: createResourceIdForReference(parsed.product, nextContentId, _nextUuid),
|
|
49
|
+
// Only mirror the UUID when this node's localId tracked it in the first place.
|
|
50
|
+
localId: localId === parsed.uuid ? _nextUuid : localId
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// bare-UUID source node: no content ID segment to remap
|
|
55
|
+
var nextUuid = (_resolvers$resolveUui3 = resolvers.resolveUuid) === null || _resolvers$resolveUui3 === void 0 ? void 0 : _resolvers$resolveUui3.call(resolvers, resourceId);
|
|
56
|
+
if (nextUuid === undefined || nextUuid === resourceId) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
resourceId: nextUuid,
|
|
61
|
+
localId: localId === resourceId ? nextUuid : localId
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** `isTransformed` is `false` when no node changed, so callers can skip persisting the result. */
|
|
66
|
+
export var migrateSyncBlockIds = function migrateSyncBlockIds(adf, resolvers) {
|
|
67
|
+
var unresolvedContentIds = new Set();
|
|
68
|
+
var isTransformed = false;
|
|
69
|
+
|
|
70
|
+
// Always returns a copy, even when nothing changes: traverse() falls back to mutating
|
|
71
|
+
// the original node in place (its `content` array gets reassigned) whenever a visitor
|
|
72
|
+
// returns undefined, so returning undefined here would leak that mutation onto the
|
|
73
|
+
// caller's input document.
|
|
74
|
+
var migrateNode = function migrateNode(node) {
|
|
75
|
+
var syncBlockAttrs = node.attrs && parseSyncBlockAttrs(node.attrs);
|
|
76
|
+
if (!syncBlockAttrs) {
|
|
77
|
+
return _objectSpread({}, node);
|
|
78
|
+
}
|
|
79
|
+
var nextAttrs = migrateAttrs(syncBlockAttrs, resolvers, unresolvedContentIds);
|
|
80
|
+
if (!nextAttrs) {
|
|
81
|
+
return _objectSpread({}, node);
|
|
82
|
+
}
|
|
83
|
+
isTransformed = true;
|
|
84
|
+
return _objectSpread(_objectSpread({}, node), {}, {
|
|
85
|
+
attrs: _objectSpread(_objectSpread({}, node.attrs), nextAttrs)
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
var transformedAdf = traverse(adf, {
|
|
89
|
+
syncBlock: migrateNode,
|
|
90
|
+
bodiedSyncBlock: migrateNode
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// traverse() only returns false when a visitor deletes the root node; migrateNode never does.
|
|
94
|
+
if (transformedAdf === false) {
|
|
95
|
+
throw new Error('migrateSyncBlockIds: traverse unexpectedly removed the root node');
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
transformedAdf: transformedAdf,
|
|
99
|
+
isTransformed: isTransformed,
|
|
100
|
+
unresolvedContentIds: Array.from(unresolvedContentIds)
|
|
101
|
+
};
|
|
102
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ADFEntity } from '@atlaskit/adf-utils/types';
|
|
2
|
+
import type { SyncBlockProduct } from '../common/types';
|
|
3
|
+
export type SyncBlockIdResolvers = {
|
|
4
|
+
/** Return `undefined` for an unknown content ID - it's left untouched and reported via `unresolvedContentIds`. */
|
|
5
|
+
resolveContentId: (contentId: string, product: SyncBlockProduct) => string | undefined;
|
|
6
|
+
/** Omit to preserve UUIDs (recommended). Return `undefined` to preserve one UUID while remapping others. */
|
|
7
|
+
resolveUuid?: (uuid: string) => string | undefined;
|
|
8
|
+
};
|
|
9
|
+
export type SyncBlockIdMigrationResult = {
|
|
10
|
+
isTransformed: boolean;
|
|
11
|
+
transformedAdf: ADFEntity;
|
|
12
|
+
/** Reference content IDs with no mapping - a signal to investigate, not necessarily a failure. */
|
|
13
|
+
unresolvedContentIds: string[];
|
|
14
|
+
};
|
|
15
|
+
/** `isTransformed` is `false` when no node changed, so callers can skip persisting the result. */
|
|
16
|
+
export declare const migrateSyncBlockIds: (adf: ADFEntity, resolvers: SyncBlockIdResolvers) => SyncBlockIdMigrationResult;
|
package/package.json
CHANGED
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
],
|
|
17
17
|
"atlaskit:src": "src/index.ts",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@atlaskit/adf-utils": "^20.
|
|
19
|
+
"@atlaskit/adf-utils": "^20.9.0",
|
|
20
20
|
"@atlaskit/browser-apis": "^1.2.0",
|
|
21
21
|
"@atlaskit/editor-json-transformer": "^9.8.0",
|
|
22
22
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
23
23
|
"@atlaskit/node-data-provider": "^17.0.0",
|
|
24
24
|
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
25
25
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
26
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
26
|
+
"@atlaskit/tmp-editor-statsig": "^174.0.0",
|
|
27
27
|
"@babel/runtime": "^7.0.0",
|
|
28
28
|
"@compiled/react": "^1.0.2",
|
|
29
29
|
"bind-event-listener": "^3.0.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"uuid": "^3.1.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@atlaskit/editor-common": "^120.
|
|
36
|
+
"@atlaskit/editor-common": "^120.13.0",
|
|
37
37
|
"react": "^18.2.0 || ^19.2.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"react-dom": "^19.2.0"
|
|
43
43
|
},
|
|
44
44
|
"name": "@atlaskit/editor-synced-block-provider",
|
|
45
|
-
"version": "12.1
|
|
45
|
+
"version": "12.2.1",
|
|
46
46
|
"description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
|
|
47
47
|
"author": "Atlassian Pty Ltd",
|
|
48
48
|
"license": "Apache-2.0",
|