@wordpress/core-data 7.40.2-next.v.202602271551.0 → 7.40.2
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/README.md +0 -27
- package/build/actions.cjs +9 -26
- package/build/actions.cjs.map +2 -2
- package/build/awareness/post-editor-awareness.cjs +45 -6
- package/build/awareness/post-editor-awareness.cjs.map +2 -2
- package/build/awareness/types.cjs.map +1 -1
- package/build/entities.cjs +36 -16
- package/build/entities.cjs.map +2 -2
- package/build/entity-provider.cjs +15 -6
- package/build/entity-provider.cjs.map +2 -2
- package/build/hooks/use-entity-prop.cjs +33 -2
- package/build/hooks/use-entity-prop.cjs.map +2 -2
- package/build/hooks/use-post-editor-awareness-state.cjs +120 -1
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/index.cjs +0 -3
- package/build/index.cjs.map +2 -2
- package/build/private-actions.cjs +27 -3
- package/build/private-actions.cjs.map +2 -2
- package/build/private-apis.cjs +14 -5
- package/build/private-apis.cjs.map +3 -3
- package/build/private-selectors.cjs +22 -2
- package/build/private-selectors.cjs.map +2 -2
- package/build/queried-data/actions.cjs +1 -1
- package/build/queried-data/actions.cjs.map +2 -2
- package/build/queried-data/reducer.cjs +19 -13
- package/build/queried-data/reducer.cjs.map +2 -2
- package/build/reducer.cjs +19 -2
- package/build/reducer.cjs.map +2 -2
- package/build/resolvers.cjs +24 -17
- package/build/resolvers.cjs.map +2 -2
- package/build/selectors.cjs +0 -15
- package/build/selectors.cjs.map +2 -2
- package/build/sync.cjs +12 -3
- package/build/sync.cjs.map +2 -2
- package/build/types.cjs.map +1 -1
- package/build/utils/block-selection-history.cjs +1 -1
- package/build/utils/block-selection-history.cjs.map +2 -2
- package/build/utils/crdt-blocks.cjs +85 -28
- package/build/utils/crdt-blocks.cjs.map +2 -2
- package/build/utils/crdt-selection.cjs +4 -1
- package/build/utils/crdt-selection.cjs.map +2 -2
- package/build/utils/crdt-text.cjs +52 -0
- package/build/utils/crdt-text.cjs.map +7 -0
- package/build/utils/crdt-user-selections.cjs +16 -6
- package/build/utils/crdt-user-selections.cjs.map +3 -3
- package/build/utils/crdt-utils.cjs +54 -2
- package/build/utils/crdt-utils.cjs.map +2 -2
- package/build/utils/crdt.cjs +26 -28
- package/build/utils/crdt.cjs.map +2 -2
- package/build-module/actions.mjs +14 -26
- package/build-module/actions.mjs.map +2 -2
- package/build-module/awareness/post-editor-awareness.mjs +47 -7
- package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
- package/build-module/entities.mjs +37 -16
- package/build-module/entities.mjs.map +2 -2
- package/build-module/entity-provider.mjs +15 -6
- package/build-module/entity-provider.mjs.map +2 -2
- package/build-module/hooks/use-entity-prop.mjs +34 -3
- package/build-module/hooks/use-entity-prop.mjs.map +2 -2
- package/build-module/hooks/use-post-editor-awareness-state.mjs +117 -1
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/index.mjs +0 -2
- package/build-module/index.mjs.map +2 -2
- package/build-module/private-actions.mjs +24 -2
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/private-apis.mjs +21 -6
- package/build-module/private-apis.mjs.map +3 -3
- package/build-module/private-selectors.mjs +19 -1
- package/build-module/private-selectors.mjs.map +2 -2
- package/build-module/queried-data/actions.mjs +1 -1
- package/build-module/queried-data/actions.mjs.map +2 -2
- package/build-module/queried-data/reducer.mjs +19 -13
- package/build-module/queried-data/reducer.mjs.map +2 -2
- package/build-module/reducer.mjs +18 -2
- package/build-module/reducer.mjs.map +2 -2
- package/build-module/resolvers.mjs +24 -17
- package/build-module/resolvers.mjs.map +2 -2
- package/build-module/selectors.mjs +0 -14
- package/build-module/selectors.mjs.map +2 -2
- package/build-module/sync.mjs +8 -2
- package/build-module/sync.mjs.map +2 -2
- package/build-module/utils/block-selection-history.mjs +5 -2
- package/build-module/utils/block-selection-history.mjs.map +2 -2
- package/build-module/utils/crdt-blocks.mjs +84 -28
- package/build-module/utils/crdt-blocks.mjs.map +2 -2
- package/build-module/utils/crdt-selection.mjs +8 -2
- package/build-module/utils/crdt-selection.mjs.map +2 -2
- package/build-module/utils/crdt-text.mjs +26 -0
- package/build-module/utils/crdt-text.mjs.map +7 -0
- package/build-module/utils/crdt-user-selections.mjs +16 -7
- package/build-module/utils/crdt-user-selections.mjs.map +3 -3
- package/build-module/utils/crdt-utils.mjs +51 -1
- package/build-module/utils/crdt-utils.mjs.map +2 -2
- package/build-module/utils/crdt.mjs +26 -28
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-types/actions.d.ts +0 -11
- package/build-types/actions.d.ts.map +1 -1
- package/build-types/awareness/post-editor-awareness.d.ts +2 -2
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/awareness/types.d.ts +6 -1
- package/build-types/awareness/types.d.ts.map +1 -1
- package/build-types/entities.d.ts +20 -1
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/entity-provider.d.ts +11 -6
- package/build-types/entity-provider.d.ts.map +1 -1
- package/build-types/hooks/use-entity-prop.d.ts.map +1 -1
- package/build-types/hooks/use-post-editor-awareness-state.d.ts +40 -7
- package/build-types/hooks/use-post-editor-awareness-state.d.ts.map +1 -1
- package/build-types/index.d.ts +0 -3
- package/build-types/index.d.ts.map +1 -1
- package/build-types/parsed-blocks-cache.d.ts +10 -0
- package/build-types/parsed-blocks-cache.d.ts.map +1 -0
- package/build-types/private-actions.d.ts +12 -0
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/private-apis.d.ts +21 -1
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/private-selectors.d.ts +17 -0
- package/build-types/private-selectors.d.ts.map +1 -1
- package/build-types/queried-data/reducer.d.ts.map +1 -1
- package/build-types/reducer.d.ts +15 -0
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/selectors.d.ts +1 -9
- package/build-types/selectors.d.ts.map +1 -1
- package/build-types/sync.d.ts +2 -2
- package/build-types/sync.d.ts.map +1 -1
- package/build-types/types.d.ts +10 -2
- package/build-types/types.d.ts.map +1 -1
- package/build-types/utils/block-selection-history.d.ts.map +1 -1
- package/build-types/utils/crdt-blocks.d.ts +11 -0
- package/build-types/utils/crdt-blocks.d.ts.map +1 -1
- package/build-types/utils/crdt-selection.d.ts.map +1 -1
- package/build-types/utils/crdt-text.d.ts +16 -0
- package/build-types/utils/crdt-text.d.ts.map +1 -0
- package/build-types/utils/crdt-user-selections.d.ts +17 -4
- package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
- package/build-types/utils/crdt-utils.d.ts +20 -0
- package/build-types/utils/crdt-utils.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts +13 -7
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/build-types/utils/normalize-query-for-resolution.d.ts +12 -0
- package/build-types/utils/normalize-query-for-resolution.d.ts.map +1 -0
- package/build-types/utils/save-crdt-doc.d.ts +8 -0
- package/build-types/utils/save-crdt-doc.d.ts.map +1 -0
- package/build-types/utils/test/crdt-utils.d.ts +2 -0
- package/build-types/utils/test/crdt-utils.d.ts.map +1 -0
- package/package.json +18 -18
- package/src/actions.js +26 -41
- package/src/awareness/post-editor-awareness.ts +106 -7
- package/src/awareness/test/post-editor-awareness.ts +50 -10
- package/src/awareness/types.ts +7 -1
- package/src/entities.js +43 -17
- package/src/entity-provider.js +24 -11
- package/src/hooks/test/use-post-editor-awareness-state.ts +446 -3
- package/src/hooks/use-entity-prop.js +43 -3
- package/src/hooks/use-post-editor-awareness-state.ts +229 -7
- package/src/index.js +0 -6
- package/src/private-actions.js +43 -1
- package/src/{private-apis.js → private-apis.ts} +21 -3
- package/src/private-selectors.ts +43 -0
- package/src/queried-data/actions.js +1 -1
- package/src/queried-data/reducer.js +26 -14
- package/src/reducer.js +36 -1
- package/src/resolvers.js +33 -23
- package/src/selectors.ts +1 -32
- package/src/sync.ts +6 -0
- package/src/test/entities.js +204 -16
- package/src/test/private-actions.js +1 -1
- package/src/test/resolvers.js +144 -57
- package/src/test/store.js +116 -0
- package/src/types.ts +20 -2
- package/src/utils/block-selection-history.ts +5 -2
- package/src/utils/crdt-blocks.ts +159 -56
- package/src/utils/crdt-selection.ts +8 -2
- package/src/utils/crdt-text.ts +43 -0
- package/src/utils/crdt-user-selections.ts +29 -8
- package/src/utils/crdt-utils.ts +99 -0
- package/src/utils/crdt.ts +50 -40
- package/src/utils/test/crdt-blocks.ts +588 -24
- package/src/utils/test/crdt-user-selections.ts +5 -0
- package/src/utils/test/crdt-utils.ts +387 -0
- package/src/utils/test/crdt.ts +291 -54
package/src/utils/test/crdt.ts
CHANGED
|
@@ -8,12 +8,56 @@ import { Y } from '@wordpress/sync';
|
|
|
8
8
|
*/
|
|
9
9
|
import { describe, expect, it, jest, beforeEach } from '@jest/globals';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Mock getBlockTypes so isRichTextAttribute can identify rich-text attrs.
|
|
13
|
+
*/
|
|
14
|
+
jest.mock( '@wordpress/blocks', () => {
|
|
15
|
+
const actual = jest.requireActual( '@wordpress/blocks' ) as Record<
|
|
16
|
+
string,
|
|
17
|
+
unknown
|
|
18
|
+
>;
|
|
19
|
+
return {
|
|
20
|
+
...actual,
|
|
21
|
+
getBlockTypes: () => [
|
|
22
|
+
{
|
|
23
|
+
name: 'core/paragraph',
|
|
24
|
+
attributes: { content: { type: 'rich-text' } },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'core/table',
|
|
28
|
+
attributes: {
|
|
29
|
+
hasFixedLayout: { type: 'boolean' },
|
|
30
|
+
caption: { type: 'rich-text' },
|
|
31
|
+
body: {
|
|
32
|
+
type: 'array',
|
|
33
|
+
query: {
|
|
34
|
+
cells: {
|
|
35
|
+
type: 'array',
|
|
36
|
+
query: {
|
|
37
|
+
content: { type: 'rich-text' },
|
|
38
|
+
tag: { type: 'string' },
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
} );
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* WordPress dependencies
|
|
51
|
+
*/
|
|
52
|
+
import { RichTextData } from '@wordpress/rich-text';
|
|
53
|
+
|
|
11
54
|
/**
|
|
12
55
|
* Internal dependencies
|
|
13
56
|
*/
|
|
14
57
|
import { CRDT_RECORD_MAP_KEY } from '../../sync';
|
|
15
58
|
import {
|
|
16
59
|
applyPostChangesToCRDTDoc,
|
|
60
|
+
defaultCollectionSyncConfig,
|
|
17
61
|
getPostChangesFromCRDTDoc,
|
|
18
62
|
POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
19
63
|
type PostChanges,
|
|
@@ -22,7 +66,59 @@ import {
|
|
|
22
66
|
import type { YBlock, YBlockRecord, YBlocks } from '../crdt-blocks';
|
|
23
67
|
import { updateSelectionHistory } from '../crdt-selection';
|
|
24
68
|
import { createYMap, getRootMap, type YMapWrap } from '../crdt-utils';
|
|
25
|
-
import type { Post
|
|
69
|
+
import type { Post } from '../../entity-types';
|
|
70
|
+
|
|
71
|
+
// Default synced properties matching the base set built in entities.js,
|
|
72
|
+
// plus 'categories' and 'tags' as example taxonomy rest_base values.
|
|
73
|
+
const defaultSyncedProperties = new Set< string >( [
|
|
74
|
+
'blocks',
|
|
75
|
+
'categories',
|
|
76
|
+
'content',
|
|
77
|
+
'date',
|
|
78
|
+
'excerpt',
|
|
79
|
+
'meta',
|
|
80
|
+
'slug',
|
|
81
|
+
'status',
|
|
82
|
+
'tags',
|
|
83
|
+
'title',
|
|
84
|
+
] );
|
|
85
|
+
|
|
86
|
+
describe( 'defaultCollectionSyncConfig', () => {
|
|
87
|
+
it( 'has no-op applyChangesToCRDTDoc', () => {
|
|
88
|
+
const doc = new Y.Doc();
|
|
89
|
+
// Should not throw and return undefined.
|
|
90
|
+
expect(
|
|
91
|
+
defaultCollectionSyncConfig.applyChangesToCRDTDoc( doc, {
|
|
92
|
+
title: 'test',
|
|
93
|
+
} )
|
|
94
|
+
).toBeUndefined();
|
|
95
|
+
doc.destroy();
|
|
96
|
+
} );
|
|
97
|
+
|
|
98
|
+
it( 'has getChangesFromCRDTDoc that returns empty object', () => {
|
|
99
|
+
const doc = new Y.Doc();
|
|
100
|
+
const result = defaultCollectionSyncConfig.getChangesFromCRDTDoc( doc, {
|
|
101
|
+
title: 'test',
|
|
102
|
+
} );
|
|
103
|
+
expect( result ).toEqual( {} );
|
|
104
|
+
doc.destroy();
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
it( 'shouldSync returns true when objectId is null (collection)', () => {
|
|
108
|
+
expect(
|
|
109
|
+
defaultCollectionSyncConfig.shouldSync?.( 'comment', null )
|
|
110
|
+
).toBe( true );
|
|
111
|
+
} );
|
|
112
|
+
|
|
113
|
+
it( 'shouldSync returns false when objectId is provided (individual record)', () => {
|
|
114
|
+
expect(
|
|
115
|
+
defaultCollectionSyncConfig.shouldSync?.( 'comment', '123' )
|
|
116
|
+
).toBe( false );
|
|
117
|
+
expect(
|
|
118
|
+
defaultCollectionSyncConfig.shouldSync?.( 'comment', 'foo' )
|
|
119
|
+
).toBe( false );
|
|
120
|
+
} );
|
|
121
|
+
} );
|
|
26
122
|
|
|
27
123
|
describe( 'crdt', () => {
|
|
28
124
|
let doc: Y.Doc;
|
|
@@ -37,8 +133,6 @@ describe( 'crdt', () => {
|
|
|
37
133
|
} );
|
|
38
134
|
|
|
39
135
|
describe( 'applyPostChangesToCRDTDoc', () => {
|
|
40
|
-
const mockPostType = {} as Type;
|
|
41
|
-
|
|
42
136
|
let map: YMapWrap< YPostRecord >;
|
|
43
137
|
|
|
44
138
|
beforeEach( () => {
|
|
@@ -50,7 +144,7 @@ describe( 'crdt', () => {
|
|
|
50
144
|
title: 'New Title',
|
|
51
145
|
} as PostChanges;
|
|
52
146
|
|
|
53
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
147
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
54
148
|
|
|
55
149
|
const title = map.get( 'title' );
|
|
56
150
|
expect( title ).toBeInstanceOf( Y.Text );
|
|
@@ -63,7 +157,7 @@ describe( 'crdt', () => {
|
|
|
63
157
|
unsyncedProperty: 'value',
|
|
64
158
|
} as unknown as PostChanges;
|
|
65
159
|
|
|
66
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
160
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
67
161
|
|
|
68
162
|
expect( map.has( 'unsyncedProperty' ) ).toBe( false );
|
|
69
163
|
expect( map.get( 'title' )?.toString() ).toBe( 'New Title' );
|
|
@@ -74,7 +168,7 @@ describe( 'crdt', () => {
|
|
|
74
168
|
title: () => 'function value',
|
|
75
169
|
} as unknown as PostChanges;
|
|
76
170
|
|
|
77
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
171
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
78
172
|
|
|
79
173
|
expect( map.has( 'title' ) ).toBe( false );
|
|
80
174
|
} );
|
|
@@ -84,7 +178,7 @@ describe( 'crdt', () => {
|
|
|
84
178
|
title: { raw: 'Raw Title', rendered: 'Rendered Title' },
|
|
85
179
|
};
|
|
86
180
|
|
|
87
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
181
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
88
182
|
|
|
89
183
|
const title = map.get( 'title' );
|
|
90
184
|
expect( title ).toBeInstanceOf( Y.Text );
|
|
@@ -96,7 +190,7 @@ describe( 'crdt', () => {
|
|
|
96
190
|
title: 'Auto Draft',
|
|
97
191
|
} as PostChanges;
|
|
98
192
|
|
|
99
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
193
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
100
194
|
|
|
101
195
|
const title = map.get( 'title' );
|
|
102
196
|
expect( title ).toBeInstanceOf( Y.Text );
|
|
@@ -108,7 +202,7 @@ describe( 'crdt', () => {
|
|
|
108
202
|
applyPostChangesToCRDTDoc(
|
|
109
203
|
doc,
|
|
110
204
|
{ title: '' } as PostChanges,
|
|
111
|
-
|
|
205
|
+
defaultSyncedProperties
|
|
112
206
|
);
|
|
113
207
|
|
|
114
208
|
const title = map.get( 'title' );
|
|
@@ -119,7 +213,7 @@ describe( 'crdt', () => {
|
|
|
119
213
|
applyPostChangesToCRDTDoc(
|
|
120
214
|
doc,
|
|
121
215
|
{ title: 'Auto Draft' } as PostChanges,
|
|
122
|
-
|
|
216
|
+
defaultSyncedProperties
|
|
123
217
|
);
|
|
124
218
|
|
|
125
219
|
expect( map.get( 'title' )?.toString() ).toBe( '' );
|
|
@@ -134,7 +228,7 @@ describe( 'crdt', () => {
|
|
|
134
228
|
},
|
|
135
229
|
};
|
|
136
230
|
|
|
137
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
231
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
138
232
|
|
|
139
233
|
const excerpt = map.get( 'excerpt' );
|
|
140
234
|
expect( excerpt ).toBeInstanceOf( Y.Text );
|
|
@@ -146,7 +240,7 @@ describe( 'crdt', () => {
|
|
|
146
240
|
slug: '',
|
|
147
241
|
};
|
|
148
242
|
|
|
149
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
243
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
150
244
|
|
|
151
245
|
expect( map.has( 'slug' ) ).toBe( false );
|
|
152
246
|
} );
|
|
@@ -156,7 +250,7 @@ describe( 'crdt', () => {
|
|
|
156
250
|
slug: 'my-post-slug',
|
|
157
251
|
};
|
|
158
252
|
|
|
159
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
253
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
160
254
|
|
|
161
255
|
expect( map.get( 'slug' ) ).toBe( 'my-post-slug' );
|
|
162
256
|
} );
|
|
@@ -174,7 +268,7 @@ describe( 'crdt', () => {
|
|
|
174
268
|
],
|
|
175
269
|
};
|
|
176
270
|
|
|
177
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
271
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
178
272
|
|
|
179
273
|
expect( ( map.get( 'blocks' ) as YBlocks ).toJSON() ).toEqual(
|
|
180
274
|
changes.blocks
|
|
@@ -186,7 +280,7 @@ describe( 'crdt', () => {
|
|
|
186
280
|
blocks: [],
|
|
187
281
|
};
|
|
188
282
|
|
|
189
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
283
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
190
284
|
|
|
191
285
|
const blocks = map.get( 'blocks' );
|
|
192
286
|
expect( blocks ).toBeInstanceOf( Y.Array );
|
|
@@ -200,7 +294,7 @@ describe( 'crdt', () => {
|
|
|
200
294
|
blocks: undefined,
|
|
201
295
|
};
|
|
202
296
|
|
|
203
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
297
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
204
298
|
|
|
205
299
|
// The key should still exist, but the value should be undefined.
|
|
206
300
|
expect( map.has( 'blocks' ) ).toBe( true );
|
|
@@ -212,7 +306,7 @@ describe( 'crdt', () => {
|
|
|
212
306
|
content: 'Hello, world!',
|
|
213
307
|
} as PostChanges;
|
|
214
308
|
|
|
215
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
309
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
216
310
|
|
|
217
311
|
const content = map.get( 'content' );
|
|
218
312
|
expect( content ).toBeInstanceOf( Y.Text );
|
|
@@ -227,7 +321,7 @@ describe( 'crdt', () => {
|
|
|
227
321
|
},
|
|
228
322
|
} as PostChanges;
|
|
229
323
|
|
|
230
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
324
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
231
325
|
|
|
232
326
|
const content = map.get( 'content' );
|
|
233
327
|
expect( content ).toBeInstanceOf( Y.Text );
|
|
@@ -241,7 +335,7 @@ describe( 'crdt', () => {
|
|
|
241
335
|
applyPostChangesToCRDTDoc(
|
|
242
336
|
doc,
|
|
243
337
|
{ title: 'Old Title' } as PostChanges,
|
|
244
|
-
|
|
338
|
+
defaultSyncedProperties
|
|
245
339
|
);
|
|
246
340
|
const titleRef = map.get( 'title' );
|
|
247
341
|
|
|
@@ -249,7 +343,7 @@ describe( 'crdt', () => {
|
|
|
249
343
|
applyPostChangesToCRDTDoc(
|
|
250
344
|
doc,
|
|
251
345
|
{ title: 'New Title' } as PostChanges,
|
|
252
|
-
|
|
346
|
+
defaultSyncedProperties
|
|
253
347
|
);
|
|
254
348
|
|
|
255
349
|
expect( map.get( 'title' ) ).toBe( titleRef );
|
|
@@ -261,7 +355,7 @@ describe( 'crdt', () => {
|
|
|
261
355
|
applyPostChangesToCRDTDoc(
|
|
262
356
|
doc,
|
|
263
357
|
{ content: 'Old content' } as PostChanges,
|
|
264
|
-
|
|
358
|
+
defaultSyncedProperties
|
|
265
359
|
);
|
|
266
360
|
const contentRef = map.get( 'content' );
|
|
267
361
|
|
|
@@ -269,7 +363,7 @@ describe( 'crdt', () => {
|
|
|
269
363
|
applyPostChangesToCRDTDoc(
|
|
270
364
|
doc,
|
|
271
365
|
{ content: 'New content' } as PostChanges,
|
|
272
|
-
|
|
366
|
+
defaultSyncedProperties
|
|
273
367
|
);
|
|
274
368
|
|
|
275
369
|
expect( map.get( 'content' ) ).toBe( contentRef );
|
|
@@ -281,7 +375,7 @@ describe( 'crdt', () => {
|
|
|
281
375
|
applyPostChangesToCRDTDoc(
|
|
282
376
|
doc,
|
|
283
377
|
{ excerpt: 'Old excerpt' } as PostChanges,
|
|
284
|
-
|
|
378
|
+
defaultSyncedProperties
|
|
285
379
|
);
|
|
286
380
|
const excerptRef = map.get( 'excerpt' );
|
|
287
381
|
|
|
@@ -289,7 +383,7 @@ describe( 'crdt', () => {
|
|
|
289
383
|
applyPostChangesToCRDTDoc(
|
|
290
384
|
doc,
|
|
291
385
|
{ excerpt: 'New excerpt' } as PostChanges,
|
|
292
|
-
|
|
386
|
+
defaultSyncedProperties
|
|
293
387
|
);
|
|
294
388
|
|
|
295
389
|
expect( map.get( 'excerpt' ) ).toBe( excerptRef );
|
|
@@ -307,7 +401,7 @@ describe( 'crdt', () => {
|
|
|
307
401
|
metaMap.set( 'some_meta', 'old value' );
|
|
308
402
|
map.set( 'meta', metaMap );
|
|
309
403
|
|
|
310
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
404
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
311
405
|
|
|
312
406
|
expect( metaMap.get( 'some_meta' ) ).toBe( 'new value' );
|
|
313
407
|
} );
|
|
@@ -323,7 +417,7 @@ describe( 'crdt', () => {
|
|
|
323
417
|
metaMap.set( 'some_meta', 'old value' );
|
|
324
418
|
map.set( 'meta', metaMap );
|
|
325
419
|
|
|
326
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
420
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
327
421
|
|
|
328
422
|
expect( metaMap.get( 'some_meta' ) ).toStrictEqual( [
|
|
329
423
|
'value',
|
|
@@ -338,23 +432,40 @@ describe( 'crdt', () => {
|
|
|
338
432
|
},
|
|
339
433
|
};
|
|
340
434
|
|
|
341
|
-
applyPostChangesToCRDTDoc( doc, changes,
|
|
435
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
342
436
|
|
|
343
437
|
const metaMap = map.get( 'meta' );
|
|
344
438
|
expect( metaMap ).toBeInstanceOf( Y.Map );
|
|
345
439
|
expect( metaMap?.get( 'custom_field' ) ).toBe( 'value' );
|
|
346
440
|
} );
|
|
441
|
+
|
|
442
|
+
it( 'syncs taxonomy rest_base values included in syncedProperties', () => {
|
|
443
|
+
const changes = {
|
|
444
|
+
categories: [ 1, 2, 3 ],
|
|
445
|
+
genre: [ 10, 20 ], // should be ignored
|
|
446
|
+
tags: [ 4, 5 ],
|
|
447
|
+
} as unknown as PostChanges;
|
|
448
|
+
|
|
449
|
+
applyPostChangesToCRDTDoc( doc, changes, defaultSyncedProperties );
|
|
450
|
+
|
|
451
|
+
expect( map.get( 'categories' ) ).toEqual( [ 1, 2, 3 ] );
|
|
452
|
+
expect( map.get( 'genre' ) ).toBeUndefined();
|
|
453
|
+
expect( map.get( 'tags' ) ).toEqual( [ 4, 5 ] );
|
|
454
|
+
|
|
455
|
+
const customSyncedProperties = new Set( [
|
|
456
|
+
...defaultSyncedProperties,
|
|
457
|
+
'genre', // now included
|
|
458
|
+
] );
|
|
459
|
+
|
|
460
|
+
applyPostChangesToCRDTDoc( doc, changes, customSyncedProperties );
|
|
461
|
+
|
|
462
|
+
expect( map.get( 'categories' ) ).toEqual( [ 1, 2, 3 ] );
|
|
463
|
+
expect( map.get( 'genre' ) ).toEqual( [ 10, 20 ] );
|
|
464
|
+
expect( map.get( 'tags' ) ).toEqual( [ 4, 5 ] );
|
|
465
|
+
} );
|
|
347
466
|
} );
|
|
348
467
|
|
|
349
468
|
describe( 'getPostChangesFromCRDTDoc', () => {
|
|
350
|
-
const mockPostType = {
|
|
351
|
-
slug: 'post',
|
|
352
|
-
supports: {
|
|
353
|
-
title: true,
|
|
354
|
-
editor: true,
|
|
355
|
-
},
|
|
356
|
-
} as unknown as Type;
|
|
357
|
-
|
|
358
469
|
let map: YMapWrap< YPostRecord >;
|
|
359
470
|
|
|
360
471
|
beforeEach( () => {
|
|
@@ -373,7 +484,7 @@ describe( 'crdt', () => {
|
|
|
373
484
|
const changes = getPostChangesFromCRDTDoc(
|
|
374
485
|
doc,
|
|
375
486
|
editedRecord,
|
|
376
|
-
|
|
487
|
+
defaultSyncedProperties
|
|
377
488
|
);
|
|
378
489
|
|
|
379
490
|
expect( changes.title ).toBe( 'CRDT Title' );
|
|
@@ -388,7 +499,7 @@ describe( 'crdt', () => {
|
|
|
388
499
|
const changes = getPostChangesFromCRDTDoc(
|
|
389
500
|
doc,
|
|
390
501
|
editedRecord,
|
|
391
|
-
|
|
502
|
+
defaultSyncedProperties
|
|
392
503
|
);
|
|
393
504
|
|
|
394
505
|
expect( changes ).not.toHaveProperty( 'unsyncedProp' );
|
|
@@ -405,7 +516,7 @@ describe( 'crdt', () => {
|
|
|
405
516
|
const changes = getPostChangesFromCRDTDoc(
|
|
406
517
|
doc,
|
|
407
518
|
editedRecord,
|
|
408
|
-
|
|
519
|
+
defaultSyncedProperties
|
|
409
520
|
);
|
|
410
521
|
|
|
411
522
|
expect( changes ).not.toHaveProperty( 'status' );
|
|
@@ -424,7 +535,7 @@ describe( 'crdt', () => {
|
|
|
424
535
|
const changesWithEmptyDate = getPostChangesFromCRDTDoc(
|
|
425
536
|
doc,
|
|
426
537
|
editedRecord,
|
|
427
|
-
|
|
538
|
+
defaultSyncedProperties
|
|
428
539
|
);
|
|
429
540
|
|
|
430
541
|
expect( changesWithEmptyDate ).not.toHaveProperty( 'date' );
|
|
@@ -434,7 +545,7 @@ describe( 'crdt', () => {
|
|
|
434
545
|
const changesWithDefinedDate = getPostChangesFromCRDTDoc(
|
|
435
546
|
doc,
|
|
436
547
|
editedRecord,
|
|
437
|
-
|
|
548
|
+
defaultSyncedProperties
|
|
438
549
|
);
|
|
439
550
|
|
|
440
551
|
expect( changesWithDefinedDate ).not.toHaveProperty( 'date' );
|
|
@@ -453,7 +564,7 @@ describe( 'crdt', () => {
|
|
|
453
564
|
const changesWithEmptyDate = getPostChangesFromCRDTDoc(
|
|
454
565
|
doc,
|
|
455
566
|
editedRecord,
|
|
456
|
-
|
|
567
|
+
defaultSyncedProperties
|
|
457
568
|
);
|
|
458
569
|
|
|
459
570
|
expect( changesWithEmptyDate ).not.toHaveProperty( 'date' );
|
|
@@ -463,7 +574,7 @@ describe( 'crdt', () => {
|
|
|
463
574
|
const changesWithDefinedDate = getPostChangesFromCRDTDoc(
|
|
464
575
|
doc,
|
|
465
576
|
editedRecord,
|
|
466
|
-
|
|
577
|
+
defaultSyncedProperties
|
|
467
578
|
);
|
|
468
579
|
|
|
469
580
|
expect( changesWithDefinedDate ).not.toHaveProperty( 'date' );
|
|
@@ -479,12 +590,74 @@ describe( 'crdt', () => {
|
|
|
479
590
|
const changes = getPostChangesFromCRDTDoc(
|
|
480
591
|
doc,
|
|
481
592
|
editedRecord,
|
|
482
|
-
|
|
593
|
+
defaultSyncedProperties
|
|
483
594
|
);
|
|
484
595
|
|
|
485
596
|
expect( changes ).toHaveProperty( 'blocks' );
|
|
486
597
|
} );
|
|
487
598
|
|
|
599
|
+
it( 'returns rich-text block attributes as RichTextData, not strings', () => {
|
|
600
|
+
// Simulate User A writing a paragraph block into the CRDT doc.
|
|
601
|
+
addBlockToDoc( map, 'block-1', 'Hello world' );
|
|
602
|
+
|
|
603
|
+
// Simulate User B reading the CRDT doc with no local blocks.
|
|
604
|
+
const editedRecord = { blocks: [] } as unknown as Post;
|
|
605
|
+
|
|
606
|
+
const changes = getPostChangesFromCRDTDoc(
|
|
607
|
+
doc,
|
|
608
|
+
editedRecord,
|
|
609
|
+
defaultSyncedProperties
|
|
610
|
+
);
|
|
611
|
+
|
|
612
|
+
const block = ( changes.blocks as any[] )?.[ 0 ];
|
|
613
|
+
expect( block ).toBeDefined();
|
|
614
|
+
expect( block.attributes.content ).toBeInstanceOf( RichTextData );
|
|
615
|
+
expect( block.attributes.content.text ).toBe( 'Hello world' );
|
|
616
|
+
} );
|
|
617
|
+
|
|
618
|
+
it( 'returns nested rich-text in array attributes as RichTextData', () => {
|
|
619
|
+
// Add a table block to the CRDT doc with nested cell content
|
|
620
|
+
// stored as plain strings.
|
|
621
|
+
let blocks = map.get( 'blocks' );
|
|
622
|
+
if ( ! ( blocks instanceof Y.Array ) ) {
|
|
623
|
+
blocks = new Y.Array< YBlock >();
|
|
624
|
+
map.set( 'blocks', blocks );
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const tableBlock = createYMap< YBlockRecord >();
|
|
628
|
+
tableBlock.set( 'name', 'core/table' );
|
|
629
|
+
tableBlock.set( 'clientId', 'table-1' );
|
|
630
|
+
const attrs = new Y.Map();
|
|
631
|
+
attrs.set( 'body', [
|
|
632
|
+
{
|
|
633
|
+
cells: [
|
|
634
|
+
{ content: '<strong>Cell</strong>', tag: 'td' },
|
|
635
|
+
{ content: 'Plain', tag: 'td' },
|
|
636
|
+
],
|
|
637
|
+
},
|
|
638
|
+
] );
|
|
639
|
+
tableBlock.set( 'attributes', attrs );
|
|
640
|
+
tableBlock.set( 'innerBlocks', new Y.Array() );
|
|
641
|
+
( blocks as YBlocks ).push( [ tableBlock ] );
|
|
642
|
+
|
|
643
|
+
const editedRecord = { blocks: [] } as unknown as Post;
|
|
644
|
+
|
|
645
|
+
const changes = getPostChangesFromCRDTDoc(
|
|
646
|
+
doc,
|
|
647
|
+
editedRecord,
|
|
648
|
+
defaultSyncedProperties
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
const block = ( changes.blocks as any[] )?.[ 0 ];
|
|
652
|
+
expect( block ).toBeDefined();
|
|
653
|
+
|
|
654
|
+
const cell = block.attributes.body[ 0 ].cells[ 0 ];
|
|
655
|
+
expect( cell.content ).toBeInstanceOf( RichTextData );
|
|
656
|
+
expect( ( cell.content as RichTextData ).toHTMLString() ).toBe(
|
|
657
|
+
'<strong>Cell</strong>'
|
|
658
|
+
);
|
|
659
|
+
} );
|
|
660
|
+
|
|
488
661
|
it( 'includes undefined blocks in changes', () => {
|
|
489
662
|
map.set( 'blocks', undefined );
|
|
490
663
|
|
|
@@ -501,7 +674,7 @@ describe( 'crdt', () => {
|
|
|
501
674
|
const changes = getPostChangesFromCRDTDoc(
|
|
502
675
|
doc,
|
|
503
676
|
editedRecord,
|
|
504
|
-
|
|
677
|
+
defaultSyncedProperties
|
|
505
678
|
);
|
|
506
679
|
|
|
507
680
|
expect( changes ).toHaveProperty( 'blocks' );
|
|
@@ -518,7 +691,7 @@ describe( 'crdt', () => {
|
|
|
518
691
|
const changes = getPostChangesFromCRDTDoc(
|
|
519
692
|
doc,
|
|
520
693
|
editedRecord,
|
|
521
|
-
|
|
694
|
+
defaultSyncedProperties
|
|
522
695
|
);
|
|
523
696
|
|
|
524
697
|
expect( changes.content ).toBe( 'New content' );
|
|
@@ -534,7 +707,7 @@ describe( 'crdt', () => {
|
|
|
534
707
|
const changes = getPostChangesFromCRDTDoc(
|
|
535
708
|
doc,
|
|
536
709
|
editedRecord,
|
|
537
|
-
|
|
710
|
+
defaultSyncedProperties
|
|
538
711
|
);
|
|
539
712
|
|
|
540
713
|
expect( changes.content ).toBe( 'New content' );
|
|
@@ -550,7 +723,7 @@ describe( 'crdt', () => {
|
|
|
550
723
|
const changes = getPostChangesFromCRDTDoc(
|
|
551
724
|
doc,
|
|
552
725
|
editedRecord,
|
|
553
|
-
|
|
726
|
+
defaultSyncedProperties
|
|
554
727
|
);
|
|
555
728
|
|
|
556
729
|
expect( changes ).not.toHaveProperty( 'content' );
|
|
@@ -570,7 +743,7 @@ describe( 'crdt', () => {
|
|
|
570
743
|
const changes = getPostChangesFromCRDTDoc(
|
|
571
744
|
doc,
|
|
572
745
|
editedRecord,
|
|
573
|
-
|
|
746
|
+
defaultSyncedProperties
|
|
574
747
|
);
|
|
575
748
|
|
|
576
749
|
expect( changes.meta ).toEqual( {
|
|
@@ -592,7 +765,7 @@ describe( 'crdt', () => {
|
|
|
592
765
|
const changes = getPostChangesFromCRDTDoc(
|
|
593
766
|
doc,
|
|
594
767
|
editedRecord,
|
|
595
|
-
|
|
768
|
+
defaultSyncedProperties
|
|
596
769
|
);
|
|
597
770
|
|
|
598
771
|
expect( changes.meta ).toEqual( {
|
|
@@ -600,6 +773,30 @@ describe( 'crdt', () => {
|
|
|
600
773
|
} );
|
|
601
774
|
} );
|
|
602
775
|
|
|
776
|
+
it( 'excludes orphaned meta keys not present on the edited record', () => {
|
|
777
|
+
// If post meta is registered, saved (landing in a CRDT doc),
|
|
778
|
+
// then unregistered, it can permanently mark the record dirty.
|
|
779
|
+
// Orphaned values should not show up as a change.
|
|
780
|
+
const metaMap = createYMap();
|
|
781
|
+
metaMap.set( 'registered_meta', 'value' );
|
|
782
|
+
metaMap.set( 'orphaned_meta', 'stale value' );
|
|
783
|
+
map.set( 'meta', metaMap );
|
|
784
|
+
|
|
785
|
+
const editedRecord = {
|
|
786
|
+
meta: {
|
|
787
|
+
registered_meta: 'value',
|
|
788
|
+
},
|
|
789
|
+
} as unknown as Post;
|
|
790
|
+
|
|
791
|
+
const changes = getPostChangesFromCRDTDoc(
|
|
792
|
+
doc,
|
|
793
|
+
editedRecord,
|
|
794
|
+
defaultSyncedProperties
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
expect( changes ).not.toHaveProperty( 'meta' );
|
|
798
|
+
} );
|
|
799
|
+
|
|
603
800
|
it( 'excludes disallowed meta keys in changes', () => {
|
|
604
801
|
const metaMap = createYMap();
|
|
605
802
|
metaMap.set( 'public_meta', 'new value' );
|
|
@@ -615,7 +812,7 @@ describe( 'crdt', () => {
|
|
|
615
812
|
const changes = getPostChangesFromCRDTDoc(
|
|
616
813
|
doc,
|
|
617
814
|
editedRecord,
|
|
618
|
-
|
|
815
|
+
defaultSyncedProperties
|
|
619
816
|
);
|
|
620
817
|
|
|
621
818
|
expect( changes.meta ).toEqual( {
|
|
@@ -626,6 +823,43 @@ describe( 'crdt', () => {
|
|
|
626
823
|
);
|
|
627
824
|
} );
|
|
628
825
|
|
|
826
|
+
it( 'returns taxonomy rest_base changes when in syncedProperties', () => {
|
|
827
|
+
map.set( 'categories', [ 1, 2 ] );
|
|
828
|
+
map.set( 'genre', [ 10, 20 ] );
|
|
829
|
+
map.set( 'tags', [ 3 ] );
|
|
830
|
+
|
|
831
|
+
const editedRecord = {
|
|
832
|
+
categories: [ 1 ],
|
|
833
|
+
genre: [ 10 ], // should be ignored
|
|
834
|
+
tags: [],
|
|
835
|
+
} as unknown as Post;
|
|
836
|
+
|
|
837
|
+
const changes = getPostChangesFromCRDTDoc(
|
|
838
|
+
doc,
|
|
839
|
+
editedRecord,
|
|
840
|
+
defaultSyncedProperties
|
|
841
|
+
) as Record< string, unknown >;
|
|
842
|
+
|
|
843
|
+
expect( changes.categories ).toEqual( [ 1, 2 ] );
|
|
844
|
+
expect( changes.genre ).toBeUndefined();
|
|
845
|
+
expect( changes.tags ).toEqual( [ 3 ] );
|
|
846
|
+
|
|
847
|
+
const customSyncedProperties = new Set( [
|
|
848
|
+
...defaultSyncedProperties,
|
|
849
|
+
'genre', // now included
|
|
850
|
+
] );
|
|
851
|
+
|
|
852
|
+
const changes2 = getPostChangesFromCRDTDoc(
|
|
853
|
+
doc,
|
|
854
|
+
editedRecord,
|
|
855
|
+
customSyncedProperties
|
|
856
|
+
) as Record< string, unknown >;
|
|
857
|
+
|
|
858
|
+
expect( changes2.categories ).toEqual( [ 1, 2 ] );
|
|
859
|
+
expect( changes2.genre ).toEqual( [ 10, 20 ] );
|
|
860
|
+
expect( changes2.tags ).toEqual( [ 3 ] );
|
|
861
|
+
} );
|
|
862
|
+
|
|
629
863
|
describe( 'selection recalculation', () => {
|
|
630
864
|
it( 'includes recalculated selection when text is inserted before cursor', () => {
|
|
631
865
|
const ytext = addBlockToDoc( map, 'block-1', 'Hello world' );
|
|
@@ -656,7 +890,7 @@ describe( 'crdt', () => {
|
|
|
656
890
|
const changes = getPostChangesFromCRDTDoc(
|
|
657
891
|
doc,
|
|
658
892
|
editedRecord,
|
|
659
|
-
|
|
893
|
+
defaultSyncedProperties
|
|
660
894
|
);
|
|
661
895
|
|
|
662
896
|
expect( changes.selection ).toBeDefined();
|
|
@@ -699,7 +933,7 @@ describe( 'crdt', () => {
|
|
|
699
933
|
const changes = getPostChangesFromCRDTDoc(
|
|
700
934
|
doc,
|
|
701
935
|
editedRecord,
|
|
702
|
-
|
|
936
|
+
defaultSyncedProperties
|
|
703
937
|
);
|
|
704
938
|
|
|
705
939
|
expect( changes.selection ).toBeDefined();
|
|
@@ -718,7 +952,7 @@ describe( 'crdt', () => {
|
|
|
718
952
|
const changes = getPostChangesFromCRDTDoc(
|
|
719
953
|
doc,
|
|
720
954
|
editedRecord,
|
|
721
|
-
|
|
955
|
+
defaultSyncedProperties
|
|
722
956
|
);
|
|
723
957
|
|
|
724
958
|
expect( changes.selection ).toBeUndefined();
|
|
@@ -734,11 +968,13 @@ describe( 'crdt', () => {
|
|
|
734
968
|
* @param map
|
|
735
969
|
* @param clientId Block client ID.
|
|
736
970
|
* @param content Initial text content.
|
|
971
|
+
* @param name Block name (default: 'core/paragraph').
|
|
737
972
|
*/
|
|
738
973
|
function addBlockToDoc(
|
|
739
974
|
map: YMapWrap< YPostRecord >,
|
|
740
975
|
clientId: string,
|
|
741
|
-
content: string
|
|
976
|
+
content: string,
|
|
977
|
+
name = 'core/paragraph'
|
|
742
978
|
): Y.Text {
|
|
743
979
|
let blocks = map.get( 'blocks' );
|
|
744
980
|
if ( ! ( blocks instanceof Y.Array ) ) {
|
|
@@ -747,6 +983,7 @@ function addBlockToDoc(
|
|
|
747
983
|
}
|
|
748
984
|
|
|
749
985
|
const block = createYMap< YBlockRecord >();
|
|
986
|
+
block.set( 'name', name );
|
|
750
987
|
block.set( 'clientId', clientId );
|
|
751
988
|
const attrs = new Y.Map();
|
|
752
989
|
const ytext = new Y.Text( content );
|