@wordpress/core-data 7.41.2-next.v.202603161435.0 → 7.43.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 +3 -1
- package/build/awareness/post-editor-awareness.cjs +12 -5
- package/build/awareness/post-editor-awareness.cjs.map +2 -2
- package/build/entities.cjs +30 -5
- package/build/entities.cjs.map +2 -2
- package/build/hooks/use-post-editor-awareness-state.cjs +1 -1
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/private-actions.cjs +10 -0
- package/build/private-actions.cjs.map +2 -2
- package/build/private-selectors.cjs +20 -3
- package/build/private-selectors.cjs.map +2 -2
- package/build/queried-data/get-query-parts.cjs +8 -0
- package/build/queried-data/get-query-parts.cjs.map +2 -2
- package/build/queried-data/reducer.cjs +15 -9
- package/build/queried-data/reducer.cjs.map +2 -2
- package/build/queried-data/selectors.cjs +10 -2
- package/build/queried-data/selectors.cjs.map +2 -2
- package/build/reducer.cjs +22 -3
- package/build/reducer.cjs.map +2 -2
- package/build/resolvers.cjs +16 -8
- package/build/resolvers.cjs.map +2 -2
- package/build/selectors.cjs +16 -8
- package/build/selectors.cjs.map +2 -2
- package/build/sync.cjs +3 -0
- package/build/sync.cjs.map +2 -2
- package/build/types.cjs.map +2 -2
- 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 +66 -5
- 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 +1 -1
- package/build/utils/crdt-user-selections.cjs.map +2 -2
- package/build/utils/crdt-utils.cjs +54 -2
- package/build/utils/crdt-utils.cjs.map +2 -2
- package/build/utils/crdt.cjs +9 -23
- package/build/utils/crdt.cjs.map +2 -2
- package/build/utils/index.cjs +0 -3
- package/build/utils/index.cjs.map +2 -2
- package/build-module/awareness/post-editor-awareness.mjs +12 -5
- package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
- package/build-module/entities.mjs +30 -5
- package/build-module/entities.mjs.map +2 -2
- package/build-module/hooks/use-post-editor-awareness-state.mjs +1 -1
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/private-actions.mjs +9 -0
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/private-selectors.mjs +19 -3
- package/build-module/private-selectors.mjs.map +2 -2
- package/build-module/queried-data/get-query-parts.mjs +8 -0
- package/build-module/queried-data/get-query-parts.mjs.map +2 -2
- package/build-module/queried-data/reducer.mjs +15 -9
- package/build-module/queried-data/reducer.mjs.map +2 -2
- package/build-module/queried-data/selectors.mjs +10 -2
- package/build-module/queried-data/selectors.mjs.map +2 -2
- package/build-module/reducer.mjs +20 -2
- package/build-module/reducer.mjs.map +2 -2
- package/build-module/resolvers.mjs +14 -7
- package/build-module/resolvers.mjs.map +2 -2
- package/build-module/selectors.mjs +16 -9
- package/build-module/selectors.mjs.map +2 -2
- package/build-module/sync.mjs +2 -0
- package/build-module/sync.mjs.map +2 -2
- package/build-module/types.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 +65 -5
- 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 +2 -2
- package/build-module/utils/crdt-user-selections.mjs.map +2 -2
- 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 +10 -23
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-module/utils/index.mjs +8 -10
- package/build-module/utils/index.mjs.map +2 -2
- 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/entities.d.ts.map +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/private-actions.d.ts +10 -0
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/private-selectors.d.ts +11 -4
- package/build-types/private-selectors.d.ts.map +1 -1
- package/build-types/queried-data/get-query-parts.d.ts +13 -14
- package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
- package/build-types/queried-data/reducer.d.ts +11 -5
- package/build-types/queried-data/reducer.d.ts.map +1 -1
- package/build-types/queried-data/selectors.d.ts.map +1 -1
- package/build-types/reducer.d.ts +11 -0
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/resolvers.d.ts +3 -0
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/selectors.d.ts +1 -0
- 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 +4 -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 +1 -2
- 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 +6 -7
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/build-types/utils/index.d.ts +0 -1
- 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/awareness/post-editor-awareness.ts +13 -6
- package/src/awareness/test/post-editor-awareness.ts +15 -10
- package/src/entities.js +36 -5
- package/src/hooks/test/use-post-editor-awareness-state.ts +3 -3
- package/src/hooks/use-post-editor-awareness-state.ts +1 -1
- package/src/private-actions.js +18 -0
- package/src/private-selectors.ts +37 -4
- package/src/queried-data/get-query-parts.js +14 -7
- package/src/queried-data/reducer.js +28 -15
- package/src/queried-data/selectors.js +11 -3
- package/src/queried-data/test/get-query-parts.js +34 -0
- package/src/queried-data/test/reducer.js +78 -8
- package/src/queried-data/test/selectors.js +171 -0
- package/src/reducer.js +31 -0
- package/src/resolvers.js +23 -7
- package/src/selectors.ts +20 -19
- package/src/sync.ts +2 -0
- package/src/test/entities.js +185 -1
- package/src/types.ts +8 -2
- package/src/utils/block-selection-history.ts +5 -2
- package/src/utils/crdt-blocks.ts +115 -5
- package/src/utils/crdt-selection.ts +8 -2
- package/src/utils/crdt-text.ts +43 -0
- package/src/utils/crdt-user-selections.ts +13 -13
- package/src/utils/crdt-utils.ts +99 -0
- package/src/utils/crdt.ts +18 -30
- package/src/utils/index.js +0 -1
- package/src/utils/test/crdt-blocks.ts +199 -0
- 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 +229 -54
- package/build/utils/is-raw-attribute.cjs +0 -29
- package/build/utils/is-raw-attribute.cjs.map +0 -7
- package/build-module/utils/is-raw-attribute.mjs +0 -8
- package/build-module/utils/is-raw-attribute.mjs.map +0 -7
- package/build-types/utils/is-raw-attribute.d.ts +0 -10
- package/build-types/utils/is-raw-attribute.d.ts.map +0 -1
- package/src/utils/is-raw-attribute.js +0 -11
- package/src/utils/test/is-raw-attribute.js +0 -22
package/src/utils/crdt.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
*/
|
|
21
21
|
import { BaseAwareness } from '../awareness/base-awareness';
|
|
22
22
|
import {
|
|
23
|
+
deserializeBlockAttributes,
|
|
23
24
|
mergeCrdtBlocks,
|
|
24
25
|
mergeRichTextUpdate,
|
|
25
26
|
type Block,
|
|
@@ -27,7 +28,6 @@ import {
|
|
|
27
28
|
type YBlocks,
|
|
28
29
|
} from './crdt-blocks';
|
|
29
30
|
import { type Post } from '../entity-types/post';
|
|
30
|
-
import { type Type } from '../entity-types';
|
|
31
31
|
import { CRDT_DOC_META_PERSISTENCE_KEY, CRDT_RECORD_MAP_KEY } from '../sync';
|
|
32
32
|
import type { WPSelection } from '../types';
|
|
33
33
|
import {
|
|
@@ -76,27 +76,6 @@ export interface YPostRecord extends YMapRecord {
|
|
|
76
76
|
|
|
77
77
|
export const POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE = '_crdt_document';
|
|
78
78
|
|
|
79
|
-
// Properties that are allowed to be synced for a post.
|
|
80
|
-
const allowedPostProperties = new Set< string >( [
|
|
81
|
-
'author',
|
|
82
|
-
'blocks',
|
|
83
|
-
'content',
|
|
84
|
-
'categories',
|
|
85
|
-
'comment_status',
|
|
86
|
-
'date',
|
|
87
|
-
'excerpt',
|
|
88
|
-
'featured_media',
|
|
89
|
-
'format',
|
|
90
|
-
'meta',
|
|
91
|
-
'ping_status',
|
|
92
|
-
'slug',
|
|
93
|
-
'status',
|
|
94
|
-
'sticky',
|
|
95
|
-
'tags',
|
|
96
|
-
'template',
|
|
97
|
-
'title',
|
|
98
|
-
] );
|
|
99
|
-
|
|
100
79
|
// Post meta keys that should *not* be synced.
|
|
101
80
|
const disallowedPostMetaKeys = new Set< string >( [
|
|
102
81
|
POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
@@ -139,18 +118,18 @@ function defaultApplyChangesToCRDTDoc(
|
|
|
139
118
|
*
|
|
140
119
|
* @param {CRDTDoc} ydoc
|
|
141
120
|
* @param {PostChanges} changes
|
|
142
|
-
* @param {
|
|
121
|
+
* @param {Set<string>} syncedProperties
|
|
143
122
|
* @return {void}
|
|
144
123
|
*/
|
|
145
124
|
export function applyPostChangesToCRDTDoc(
|
|
146
125
|
ydoc: CRDTDoc,
|
|
147
126
|
changes: PostChanges,
|
|
148
|
-
|
|
127
|
+
syncedProperties: Set< string >
|
|
149
128
|
): void {
|
|
150
129
|
const ymap = getRootMap< YPostRecord >( ydoc, CRDT_RECORD_MAP_KEY );
|
|
151
130
|
|
|
152
131
|
Object.keys( changes ).forEach( ( key ) => {
|
|
153
|
-
if ( !
|
|
132
|
+
if ( ! syncedProperties.has( key ) ) {
|
|
154
133
|
return;
|
|
155
134
|
}
|
|
156
135
|
|
|
@@ -289,15 +268,15 @@ function defaultGetChangesFromCRDTDoc( crdtDoc: CRDTDoc ): ObjectData {
|
|
|
289
268
|
* against the local record and determine if there are changes (edits) we want
|
|
290
269
|
* to dispatch.
|
|
291
270
|
*
|
|
292
|
-
* @param {CRDTDoc}
|
|
293
|
-
* @param {Post}
|
|
294
|
-
* @param {
|
|
271
|
+
* @param {CRDTDoc} ydoc
|
|
272
|
+
* @param {Post} editedRecord
|
|
273
|
+
* @param {Set<string>} syncedProperties
|
|
295
274
|
* @return {Partial<PostChanges>} The changes that should be applied to the local record.
|
|
296
275
|
*/
|
|
297
276
|
export function getPostChangesFromCRDTDoc(
|
|
298
277
|
ydoc: CRDTDoc,
|
|
299
278
|
editedRecord: Post,
|
|
300
|
-
|
|
279
|
+
syncedProperties: Set< string >
|
|
301
280
|
): PostChanges {
|
|
302
281
|
const ymap = getRootMap< YPostRecord >( ydoc, CRDT_RECORD_MAP_KEY );
|
|
303
282
|
|
|
@@ -305,7 +284,7 @@ export function getPostChangesFromCRDTDoc(
|
|
|
305
284
|
|
|
306
285
|
const changes = Object.fromEntries(
|
|
307
286
|
Object.entries( ymap.toJSON() ).filter( ( [ key, newValue ] ) => {
|
|
308
|
-
if ( !
|
|
287
|
+
if ( ! syncedProperties.has( key ) ) {
|
|
309
288
|
return false;
|
|
310
289
|
}
|
|
311
290
|
|
|
@@ -404,6 +383,15 @@ export function getPostChangesFromCRDTDoc(
|
|
|
404
383
|
} )
|
|
405
384
|
);
|
|
406
385
|
|
|
386
|
+
// Blocks extracted from the CRDT document have rich-text attributes as
|
|
387
|
+
// plain strings (from Y.Text.toJSON()). Convert them back to RichTextData
|
|
388
|
+
// so block edit components receive the same types as locally-created blocks.
|
|
389
|
+
if ( changes.blocks ) {
|
|
390
|
+
changes.blocks = deserializeBlockAttributes(
|
|
391
|
+
changes.blocks as Block[]
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
407
395
|
// Meta changes must be merged with the edited record since not all meta
|
|
408
396
|
// properties are synced.
|
|
409
397
|
if ( 'object' === typeof changes.meta ) {
|
package/src/utils/index.js
CHANGED
|
@@ -5,7 +5,6 @@ export { default as forwardResolver } from './forward-resolver';
|
|
|
5
5
|
export { default as onSubKey } from './on-sub-key';
|
|
6
6
|
export { default as replaceAction } from './replace-action';
|
|
7
7
|
export { default as withWeakMapCache } from './with-weak-map-cache';
|
|
8
|
-
export { default as isRawAttribute } from './is-raw-attribute';
|
|
9
8
|
export { default as setNestedValue } from './set-nested-value';
|
|
10
9
|
export { default as getNestedValue } from './get-nested-value';
|
|
11
10
|
export { default as isNumericID } from './is-numeric-id';
|
|
@@ -38,9 +38,24 @@ jest.mock( '@wordpress/blocks', () => ( {
|
|
|
38
38
|
url: { type: 'string' },
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
|
+
{
|
|
42
|
+
name: 'core/table',
|
|
43
|
+
attributes: {
|
|
44
|
+
hasFixedLayout: { type: 'boolean' },
|
|
45
|
+
caption: { type: 'rich-text' },
|
|
46
|
+
head: { type: 'array' },
|
|
47
|
+
body: { type: 'array' },
|
|
48
|
+
foot: { type: 'array' },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
41
51
|
],
|
|
42
52
|
} ) );
|
|
43
53
|
|
|
54
|
+
/**
|
|
55
|
+
* WordPress dependencies
|
|
56
|
+
*/
|
|
57
|
+
import { RichTextData } from '@wordpress/rich-text';
|
|
58
|
+
|
|
44
59
|
/**
|
|
45
60
|
* Internal dependencies
|
|
46
61
|
*/
|
|
@@ -52,6 +67,7 @@ import {
|
|
|
52
67
|
type YBlocks,
|
|
53
68
|
type YBlockAttributes,
|
|
54
69
|
} from '../crdt-blocks';
|
|
70
|
+
import { getCachedRichTextData, createRichTextDataCache } from '../crdt-text';
|
|
55
71
|
|
|
56
72
|
describe( 'crdt-blocks', () => {
|
|
57
73
|
let doc: Y.Doc;
|
|
@@ -1089,6 +1105,137 @@ describe( 'crdt-blocks', () => {
|
|
|
1089
1105
|
} );
|
|
1090
1106
|
} );
|
|
1091
1107
|
|
|
1108
|
+
describe( 'table block', () => {
|
|
1109
|
+
it( 'preserves table cell content through CRDT round-trip', () => {
|
|
1110
|
+
const tableBlocks: Block[] = [
|
|
1111
|
+
{
|
|
1112
|
+
name: 'core/table',
|
|
1113
|
+
attributes: {
|
|
1114
|
+
hasFixedLayout: true,
|
|
1115
|
+
body: [
|
|
1116
|
+
{
|
|
1117
|
+
cells: [
|
|
1118
|
+
{
|
|
1119
|
+
content:
|
|
1120
|
+
RichTextData.fromPlainText( '1' ),
|
|
1121
|
+
tag: 'td',
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
content:
|
|
1125
|
+
RichTextData.fromPlainText( '2' ),
|
|
1126
|
+
tag: 'td',
|
|
1127
|
+
},
|
|
1128
|
+
],
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
cells: [
|
|
1132
|
+
{
|
|
1133
|
+
content:
|
|
1134
|
+
RichTextData.fromPlainText( '3' ),
|
|
1135
|
+
tag: 'td',
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
content:
|
|
1139
|
+
RichTextData.fromPlainText( '4' ),
|
|
1140
|
+
tag: 'td',
|
|
1141
|
+
},
|
|
1142
|
+
],
|
|
1143
|
+
},
|
|
1144
|
+
],
|
|
1145
|
+
},
|
|
1146
|
+
innerBlocks: [],
|
|
1147
|
+
},
|
|
1148
|
+
];
|
|
1149
|
+
|
|
1150
|
+
mergeCrdtBlocks( yblocks, tableBlocks, null );
|
|
1151
|
+
|
|
1152
|
+
// Simulate a CRDT encode/decode cycle (persistence or sync).
|
|
1153
|
+
const encoded = Y.encodeStateAsUpdate( doc );
|
|
1154
|
+
const doc2 = new Y.Doc();
|
|
1155
|
+
Y.applyUpdate( doc2, encoded );
|
|
1156
|
+
|
|
1157
|
+
const yblocks2 = doc2.getArray< YBlock >();
|
|
1158
|
+
expect( yblocks2.length ).toBe( 1 );
|
|
1159
|
+
|
|
1160
|
+
const block = yblocks2.get( 0 );
|
|
1161
|
+
const attrs = block.get( 'attributes' ) as YBlockAttributes;
|
|
1162
|
+
const body = attrs.get( 'body' ) as {
|
|
1163
|
+
cells: { content: string; tag: string }[];
|
|
1164
|
+
}[];
|
|
1165
|
+
|
|
1166
|
+
expect( body ).toHaveLength( 2 );
|
|
1167
|
+
expect( body[ 0 ].cells[ 0 ].content ).toBe( '1' );
|
|
1168
|
+
expect( body[ 0 ].cells[ 1 ].content ).toBe( '2' );
|
|
1169
|
+
expect( body[ 1 ].cells[ 0 ].content ).toBe( '3' );
|
|
1170
|
+
expect( body[ 1 ].cells[ 1 ].content ).toBe( '4' );
|
|
1171
|
+
|
|
1172
|
+
doc2.destroy();
|
|
1173
|
+
} );
|
|
1174
|
+
|
|
1175
|
+
it( 'preserves table cell content with HTML formatting', () => {
|
|
1176
|
+
const tableBlocks: Block[] = [
|
|
1177
|
+
{
|
|
1178
|
+
name: 'core/table',
|
|
1179
|
+
attributes: {
|
|
1180
|
+
hasFixedLayout: true,
|
|
1181
|
+
head: [
|
|
1182
|
+
{
|
|
1183
|
+
cells: [
|
|
1184
|
+
{
|
|
1185
|
+
content: RichTextData.fromHTMLString(
|
|
1186
|
+
'<strong>Header</strong>'
|
|
1187
|
+
),
|
|
1188
|
+
tag: 'th',
|
|
1189
|
+
},
|
|
1190
|
+
],
|
|
1191
|
+
},
|
|
1192
|
+
],
|
|
1193
|
+
body: [
|
|
1194
|
+
{
|
|
1195
|
+
cells: [
|
|
1196
|
+
{
|
|
1197
|
+
content: RichTextData.fromHTMLString(
|
|
1198
|
+
'<a href="https://example.com">Link</a>'
|
|
1199
|
+
),
|
|
1200
|
+
tag: 'td',
|
|
1201
|
+
},
|
|
1202
|
+
],
|
|
1203
|
+
},
|
|
1204
|
+
],
|
|
1205
|
+
},
|
|
1206
|
+
innerBlocks: [],
|
|
1207
|
+
},
|
|
1208
|
+
];
|
|
1209
|
+
|
|
1210
|
+
mergeCrdtBlocks( yblocks, tableBlocks, null );
|
|
1211
|
+
|
|
1212
|
+
// Round-trip through encode/decode.
|
|
1213
|
+
const encoded = Y.encodeStateAsUpdate( doc );
|
|
1214
|
+
const doc2 = new Y.Doc();
|
|
1215
|
+
Y.applyUpdate( doc2, encoded );
|
|
1216
|
+
|
|
1217
|
+
const yblocks2 = doc2.getArray< YBlock >();
|
|
1218
|
+
const block = yblocks2.get( 0 );
|
|
1219
|
+
const attrs = block.get( 'attributes' ) as YBlockAttributes;
|
|
1220
|
+
|
|
1221
|
+
const head = attrs.get( 'head' ) as {
|
|
1222
|
+
cells: { content: string }[];
|
|
1223
|
+
}[];
|
|
1224
|
+
expect( head[ 0 ].cells[ 0 ].content ).toBe(
|
|
1225
|
+
'<strong>Header</strong>'
|
|
1226
|
+
);
|
|
1227
|
+
|
|
1228
|
+
const body = attrs.get( 'body' ) as {
|
|
1229
|
+
cells: { content: string }[];
|
|
1230
|
+
}[];
|
|
1231
|
+
expect( body[ 0 ].cells[ 0 ].content ).toBe(
|
|
1232
|
+
'<a href="https://example.com">Link</a>'
|
|
1233
|
+
);
|
|
1234
|
+
|
|
1235
|
+
doc2.destroy();
|
|
1236
|
+
} );
|
|
1237
|
+
} );
|
|
1238
|
+
|
|
1092
1239
|
describe( 'emoji handling', () => {
|
|
1093
1240
|
// Emoji like 😀 (U+1F600) are surrogate pairs in UTF-16 (.length === 2).
|
|
1094
1241
|
// The CRDT sync must preserve them without corruption (no U+FFFD / '�').
|
|
@@ -1435,3 +1582,55 @@ describe( 'crdt-blocks', () => {
|
|
|
1435
1582
|
} );
|
|
1436
1583
|
} );
|
|
1437
1584
|
} );
|
|
1585
|
+
|
|
1586
|
+
describe( 'getCachedRichTextData', () => {
|
|
1587
|
+
let spy: ReturnType< typeof jest.spyOn >;
|
|
1588
|
+
|
|
1589
|
+
beforeEach( () => {
|
|
1590
|
+
spy = jest.spyOn( RichTextData, 'fromHTMLString' );
|
|
1591
|
+
} );
|
|
1592
|
+
|
|
1593
|
+
afterEach( () => {
|
|
1594
|
+
spy.mockRestore();
|
|
1595
|
+
} );
|
|
1596
|
+
|
|
1597
|
+
it( 'does not call fromHTMLString again for the same HTML string', () => {
|
|
1598
|
+
getCachedRichTextData( '<strong>cached-hit</strong>' );
|
|
1599
|
+
getCachedRichTextData( '<strong>cached-hit</strong>' );
|
|
1600
|
+
|
|
1601
|
+
expect( spy ).toHaveBeenCalledTimes( 1 );
|
|
1602
|
+
} );
|
|
1603
|
+
|
|
1604
|
+
it( 'calls fromHTMLString for each unique HTML string', () => {
|
|
1605
|
+
getCachedRichTextData( '<strong>cached-miss-a</strong>' );
|
|
1606
|
+
getCachedRichTextData( '<em>cached-miss-b</em>' );
|
|
1607
|
+
|
|
1608
|
+
expect( spy ).toHaveBeenCalledTimes( 2 );
|
|
1609
|
+
} );
|
|
1610
|
+
|
|
1611
|
+
it( 'calls fromHTMLString again for an evicted entry', () => {
|
|
1612
|
+
const cacheSize = 10;
|
|
1613
|
+
const getCachedValue = createRichTextDataCache( cacheSize );
|
|
1614
|
+
|
|
1615
|
+
const firstString = 'eviction-test-first';
|
|
1616
|
+
|
|
1617
|
+
getCachedValue( firstString );
|
|
1618
|
+
|
|
1619
|
+
for ( let i = 1; i < cacheSize; i++ ) {
|
|
1620
|
+
getCachedValue( `eviction-test-${ i }` );
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// This should push firstString out of the cache.
|
|
1624
|
+
getCachedValue( 'eviction-test-overflow' );
|
|
1625
|
+
|
|
1626
|
+
spy.mockClear();
|
|
1627
|
+
|
|
1628
|
+
// firstString was evicted, so fromHTMLString should be called again.
|
|
1629
|
+
getCachedValue( firstString );
|
|
1630
|
+
expect( spy ).toHaveBeenCalledTimes( 1 );
|
|
1631
|
+
|
|
1632
|
+
// The overflow entry is still cached, so fromHTMLString should not be called.
|
|
1633
|
+
getCachedValue( 'eviction-test-overflow' );
|
|
1634
|
+
expect( spy ).toHaveBeenCalledTimes( 1 );
|
|
1635
|
+
} );
|
|
1636
|
+
} );
|
|
@@ -16,6 +16,11 @@ import { CRDT_RECORD_MAP_KEY } from '../../sync';
|
|
|
16
16
|
|
|
17
17
|
jest.mock( '@wordpress/data', () => ( {
|
|
18
18
|
select: jest.fn(),
|
|
19
|
+
// Needed because @wordpress/rich-text initialises its store at import time.
|
|
20
|
+
combineReducers: jest.fn( () => jest.fn( () => ( {} ) ) ),
|
|
21
|
+
createReduxStore: jest.fn( () => ( {} ) ),
|
|
22
|
+
register: jest.fn(),
|
|
23
|
+
createSelector: ( selector: Function ) => selector,
|
|
19
24
|
} ) );
|
|
20
25
|
|
|
21
26
|
jest.mock( '@wordpress/block-editor', () => ( {
|