@wordpress/core-data 7.45.0 → 7.45.1-next.v.202605131006.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 (181) hide show
  1. package/build/actions.cjs +8 -6
  2. package/build/actions.cjs.map +2 -2
  3. package/build/awareness/post-editor-awareness.cjs +1 -1
  4. package/build/awareness/post-editor-awareness.cjs.map +2 -2
  5. package/build/resolvers.cjs +2 -1
  6. package/build/resolvers.cjs.map +2 -2
  7. package/build/types.cjs.map +2 -2
  8. package/build/utils/block-selection-history.cjs +4 -1
  9. package/build/utils/block-selection-history.cjs.map +2 -2
  10. package/build/utils/crdt-blocks.cjs +157 -89
  11. package/build/utils/crdt-blocks.cjs.map +2 -2
  12. package/build/utils/crdt-selection.cjs +1 -1
  13. package/build/utils/crdt-selection.cjs.map +2 -2
  14. package/build/utils/crdt-user-selections.cjs +4 -1
  15. package/build/utils/crdt-user-selections.cjs.map +2 -2
  16. package/build/utils/crdt-utils.cjs +18 -6
  17. package/build/utils/crdt-utils.cjs.map +2 -2
  18. package/build/utils/crdt.cjs +12 -2
  19. package/build/utils/crdt.cjs.map +2 -2
  20. package/build-module/actions.mjs +8 -6
  21. package/build-module/actions.mjs.map +2 -2
  22. package/build-module/awareness/post-editor-awareness.mjs +5 -2
  23. package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
  24. package/build-module/resolvers.mjs +2 -1
  25. package/build-module/resolvers.mjs.map +2 -2
  26. package/build-module/types.mjs.map +2 -2
  27. package/build-module/utils/block-selection-history.mjs +5 -1
  28. package/build-module/utils/block-selection-history.mjs.map +2 -2
  29. package/build-module/utils/crdt-blocks.mjs +162 -90
  30. package/build-module/utils/crdt-blocks.mjs.map +2 -2
  31. package/build-module/utils/crdt-selection.mjs +2 -1
  32. package/build-module/utils/crdt-selection.mjs.map +2 -2
  33. package/build-module/utils/crdt-user-selections.mjs +9 -2
  34. package/build-module/utils/crdt-user-selections.mjs.map +2 -2
  35. package/build-module/utils/crdt-utils.mjs +16 -6
  36. package/build-module/utils/crdt-utils.mjs.map +2 -2
  37. package/build-module/utils/crdt.mjs +13 -2
  38. package/build-module/utils/crdt.mjs.map +2 -2
  39. package/build-types/actions.d.ts +177 -64
  40. package/build-types/actions.d.ts.map +1 -1
  41. package/build-types/awareness/awareness-state.d.ts.map +1 -1
  42. package/build-types/awareness/base-awareness.d.ts +0 -3
  43. package/build-types/awareness/base-awareness.d.ts.map +1 -1
  44. package/build-types/awareness/post-editor-awareness.d.ts +1 -8
  45. package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
  46. package/build-types/awareness/typed-awareness.d.ts.map +1 -1
  47. package/build-types/batch/create-batch.d.ts +1 -1
  48. package/build-types/batch/create-batch.d.ts.map +1 -1
  49. package/build-types/batch/default-processor.d.ts.map +1 -1
  50. package/build-types/batch/index.d.ts +2 -2
  51. package/build-types/batch/index.d.ts.map +1 -1
  52. package/build-types/entities.d.ts +114 -87
  53. package/build-types/entities.d.ts.map +1 -1
  54. package/build-types/entity-context.d.ts +1 -1
  55. package/build-types/entity-context.d.ts.map +1 -1
  56. package/build-types/entity-provider.d.ts +2 -2
  57. package/build-types/entity-provider.d.ts.map +1 -1
  58. package/build-types/entity-types/attachment.d.ts.map +1 -1
  59. package/build-types/entity-types/base-entity-records.d.ts.map +1 -1
  60. package/build-types/entity-types/base.d.ts.map +1 -1
  61. package/build-types/entity-types/comment.d.ts.map +1 -1
  62. package/build-types/entity-types/font-collection.d.ts.map +1 -1
  63. package/build-types/entity-types/font-family.d.ts.map +1 -1
  64. package/build-types/entity-types/global-styles-revision.d.ts.map +1 -1
  65. package/build-types/entity-types/icon.d.ts.map +1 -1
  66. package/build-types/entity-types/menu-location.d.ts.map +1 -1
  67. package/build-types/entity-types/nav-menu-item.d.ts.map +1 -1
  68. package/build-types/entity-types/nav-menu.d.ts.map +1 -1
  69. package/build-types/entity-types/page.d.ts.map +1 -1
  70. package/build-types/entity-types/plugin.d.ts.map +1 -1
  71. package/build-types/entity-types/post-revision.d.ts.map +1 -1
  72. package/build-types/entity-types/post-status.d.ts.map +1 -1
  73. package/build-types/entity-types/post.d.ts.map +1 -1
  74. package/build-types/entity-types/settings.d.ts.map +1 -1
  75. package/build-types/entity-types/sidebar.d.ts.map +1 -1
  76. package/build-types/entity-types/taxonomy.d.ts.map +1 -1
  77. package/build-types/entity-types/term.d.ts.map +1 -1
  78. package/build-types/entity-types/theme.d.ts.map +1 -1
  79. package/build-types/entity-types/type.d.ts.map +1 -1
  80. package/build-types/entity-types/user.d.ts.map +1 -1
  81. package/build-types/entity-types/widget-type.d.ts.map +1 -1
  82. package/build-types/entity-types/widget.d.ts.map +1 -1
  83. package/build-types/entity-types/wp-template-part.d.ts.map +1 -1
  84. package/build-types/entity-types/wp-template.d.ts.map +1 -1
  85. package/build-types/fetch/__experimental-fetch-url-data.d.ts +2 -5
  86. package/build-types/fetch/__experimental-fetch-url-data.d.ts.map +1 -1
  87. package/build-types/fetch/index.d.ts +3 -3
  88. package/build-types/fetch/index.d.ts.map +1 -1
  89. package/build-types/footnotes/get-footnotes-order.d.ts.map +1 -1
  90. package/build-types/footnotes/get-rich-text-values-cached.d.ts.map +1 -1
  91. package/build-types/footnotes/index.d.ts +1 -1
  92. package/build-types/footnotes/index.d.ts.map +1 -1
  93. package/build-types/hooks/use-entity-block-editor.d.ts +1 -1
  94. package/build-types/hooks/use-entity-block-editor.d.ts.map +1 -1
  95. package/build-types/hooks/use-entity-id.d.ts.map +1 -1
  96. package/build-types/hooks/use-entity-prop.d.ts.map +1 -1
  97. package/build-types/hooks/use-resource-permissions.d.ts.map +1 -1
  98. package/build-types/index.d.ts +155 -153
  99. package/build-types/index.d.ts.map +1 -1
  100. package/build-types/locks/actions.d.ts +1 -1
  101. package/build-types/locks/actions.d.ts.map +1 -1
  102. package/build-types/locks/engine.d.ts +1 -1
  103. package/build-types/locks/engine.d.ts.map +1 -1
  104. package/build-types/locks/reducer.d.ts.map +1 -1
  105. package/build-types/locks/selectors.d.ts +2 -2
  106. package/build-types/locks/selectors.d.ts.map +1 -1
  107. package/build-types/locks/utils.d.ts +5 -5
  108. package/build-types/locks/utils.d.ts.map +1 -1
  109. package/build-types/name.d.ts +1 -1
  110. package/build-types/name.d.ts.map +1 -1
  111. package/build-types/private-actions.d.ts +45 -29
  112. package/build-types/private-actions.d.ts.map +1 -1
  113. package/build-types/private-apis.d.ts +1 -1
  114. package/build-types/private-apis.d.ts.map +1 -1
  115. package/build-types/queried-data/actions.d.ts +3 -3
  116. package/build-types/queried-data/actions.d.ts.map +1 -1
  117. package/build-types/queried-data/get-query-parts.d.ts +10 -34
  118. package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
  119. package/build-types/queried-data/index.d.ts +3 -3
  120. package/build-types/queried-data/index.d.ts.map +1 -1
  121. package/build-types/queried-data/reducer.d.ts +7 -23
  122. package/build-types/queried-data/reducer.d.ts.map +1 -1
  123. package/build-types/queried-data/selectors.d.ts +3 -3
  124. package/build-types/queried-data/selectors.d.ts.map +1 -1
  125. package/build-types/reducer.d.ts +40 -32
  126. package/build-types/reducer.d.ts.map +1 -1
  127. package/build-types/resolvers.d.ts +130 -47
  128. package/build-types/resolvers.d.ts.map +1 -1
  129. package/build-types/selectors.d.ts +1 -1
  130. package/build-types/selectors.d.ts.map +1 -1
  131. package/build-types/types.d.ts +61 -6
  132. package/build-types/types.d.ts.map +1 -1
  133. package/build-types/utils/block-selection-history.d.ts.map +1 -1
  134. package/build-types/utils/conservative-map-item.d.ts.map +1 -1
  135. package/build-types/utils/crdt-blocks.d.ts +19 -9
  136. package/build-types/utils/crdt-blocks.d.ts.map +1 -1
  137. package/build-types/utils/crdt-selection.d.ts.map +1 -1
  138. package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
  139. package/build-types/utils/crdt-utils.d.ts +35 -2
  140. package/build-types/utils/crdt-utils.d.ts.map +1 -1
  141. package/build-types/utils/crdt.d.ts.map +1 -1
  142. package/build-types/utils/forward-resolver.d.ts +2 -2
  143. package/build-types/utils/forward-resolver.d.ts.map +1 -1
  144. package/build-types/utils/get-nested-value.d.ts.map +1 -1
  145. package/build-types/utils/get-normalized-comma-separable.d.ts +1 -1
  146. package/build-types/utils/get-normalized-comma-separable.d.ts.map +1 -1
  147. package/build-types/utils/if-matching-action.d.ts +3 -3
  148. package/build-types/utils/if-matching-action.d.ts.map +1 -1
  149. package/build-types/utils/index.d.ts +12 -12
  150. package/build-types/utils/index.d.ts.map +1 -1
  151. package/build-types/utils/is-numeric-id.d.ts.map +1 -1
  152. package/build-types/utils/log-entity-deprecation.d.ts +1 -1
  153. package/build-types/utils/log-entity-deprecation.d.ts.map +1 -1
  154. package/build-types/utils/normalize-query-for-resolution.d.ts.map +1 -1
  155. package/build-types/utils/receive-intermediate-results.d.ts +1 -1
  156. package/build-types/utils/receive-intermediate-results.d.ts.map +1 -1
  157. package/build-types/utils/replace-action.d.ts +3 -3
  158. package/build-types/utils/replace-action.d.ts.map +1 -1
  159. package/build-types/utils/set-nested-value.d.ts.map +1 -1
  160. package/build-types/utils/user-permissions.d.ts +3 -3
  161. package/build-types/utils/user-permissions.d.ts.map +1 -1
  162. package/build-types/utils/with-weak-map-cache.d.ts +1 -1
  163. package/build-types/utils/with-weak-map-cache.d.ts.map +1 -1
  164. package/package.json +20 -20
  165. package/src/actions.js +7 -9
  166. package/src/awareness/post-editor-awareness.ts +5 -2
  167. package/src/resolvers.js +2 -1
  168. package/src/test/actions.js +58 -0
  169. package/src/test/resolvers.js +115 -2
  170. package/src/test/rtc-rich-text-offset-space.test.js +204 -0
  171. package/src/types.ts +63 -6
  172. package/src/utils/block-selection-history.ts +5 -1
  173. package/src/utils/crdt-blocks.ts +316 -116
  174. package/src/utils/crdt-selection.ts +2 -1
  175. package/src/utils/crdt-user-selections.ts +9 -2
  176. package/src/utils/crdt-utils.ts +53 -10
  177. package/src/utils/crdt.ts +30 -4
  178. package/src/utils/test/crdt-blocks.ts +74 -18
  179. package/src/utils/test/crdt-utils.ts +18 -2
  180. package/src/utils/test/rtc-rich-text-cursor-scope.test.js +267 -0
  181. package/src/utils/test/rtc-rich-text-offset-space.test.js +469 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { beforeEach, describe, expect, it, jest } from '@jest/globals';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { Y } from '@wordpress/sync';
10
+
11
+ /**
12
+ * Mock block schemas and sync providers.
13
+ */
14
+ jest.mock( '@wordpress/blocks', () => {
15
+ const actual = jest.requireActual( '@wordpress/blocks' );
16
+
17
+ return {
18
+ ...actual,
19
+ getBlockTypes: () => [
20
+ {
21
+ name: 'test/cursor-scope-bug',
22
+ attributes: {
23
+ first: { type: 'rich-text' },
24
+ second: { type: 'rich-text' },
25
+ },
26
+ },
27
+ ],
28
+ };
29
+ } );
30
+
31
+ jest.mock( '../../../../sync/src/providers', () => ( {
32
+ getProviderCreators: jest.fn(),
33
+ } ) );
34
+
35
+ /**
36
+ * Internal dependencies
37
+ */
38
+ import { createSyncManager } from '../../../../sync/src/manager';
39
+ import { getProviderCreators } from '../../../../sync/src/providers';
40
+ import { CRDT_RECORD_MAP_KEY } from '../../sync';
41
+ import { applyPostChangesToCRDTDoc } from '../crdt';
42
+ import { deserializeBlockAttributes, mergeCrdtBlocks } from '../crdt-blocks';
43
+ import { getRootMap } from '../crdt-utils';
44
+
45
+ const mockGetProviderCreators = jest.mocked( getProviderCreators );
46
+
47
+ const SYNCED_PROPERTIES = new Set( [ 'blocks' ] );
48
+ const INITIAL_SECOND = '<em>b</em><em>i</em>';
49
+ const HIDDEN_SECOND = 'ab<em>b</em><strong>it</strong>';
50
+ const STEP_TWO_SECOND = 'a<strong>it</strong>';
51
+ const FINAL_SECOND = 'ab<em>b</em><strong>i</strong>t';
52
+
53
+ function makeBlock( first, second ) {
54
+ return {
55
+ clientId: 'block-1',
56
+ name: 'test/cursor-scope-bug',
57
+ attributes: { first, second },
58
+ innerBlocks: [],
59
+ };
60
+ }
61
+
62
+ function getSelection( offset ) {
63
+ return {
64
+ selectionStart: {
65
+ clientId: 'block-1',
66
+ attributeKey: 'first',
67
+ offset,
68
+ },
69
+ selectionEnd: {
70
+ clientId: 'block-1',
71
+ attributeKey: 'first',
72
+ offset,
73
+ },
74
+ };
75
+ }
76
+
77
+ function readSecondFromYBlocks( yblocks ) {
78
+ const attrs = yblocks.get( 0 ).get( 'attributes' );
79
+ return attrs.get( 'second' ).toString();
80
+ }
81
+
82
+ function readVisibleSecondFromYBlocks( yblocks ) {
83
+ const second = deserializeBlockAttributes( yblocks.toJSON() )[ 0 ]
84
+ .attributes.second;
85
+
86
+ return typeof second?.toHTMLString === 'function'
87
+ ? second.toHTMLString()
88
+ : String( second );
89
+ }
90
+
91
+ function readSecondFromDoc( ydoc ) {
92
+ const ymap = getRootMap( ydoc, CRDT_RECORD_MAP_KEY );
93
+ const yblocks = ymap.get( 'blocks' );
94
+ return readSecondFromYBlocks( yblocks );
95
+ }
96
+
97
+ function readVisibleSecondFromDoc( ydoc ) {
98
+ const ymap = getRootMap( ydoc, CRDT_RECORD_MAP_KEY );
99
+ const yblocks = ymap.get( 'blocks' );
100
+ return readVisibleSecondFromYBlocks( yblocks );
101
+ }
102
+
103
+ function runSequenceWithMergeCrdtBlocks( yblocks ) {
104
+ mergeCrdtBlocks( yblocks, [ makeBlock( '', INITIAL_SECOND ) ], null );
105
+ mergeCrdtBlocks( yblocks, [ makeBlock( 'x', HIDDEN_SECOND ) ], 1 );
106
+ mergeCrdtBlocks( yblocks, [ makeBlock( 'xy', STEP_TWO_SECOND ) ], 2 );
107
+ mergeCrdtBlocks( yblocks, [ makeBlock( 'xyq', FINAL_SECOND ) ], 3 );
108
+ }
109
+
110
+ function runSequenceWithMergeCrdtBlocksWithoutCursor( yblocks ) {
111
+ mergeCrdtBlocks( yblocks, [ makeBlock( '', INITIAL_SECOND ) ], null );
112
+ mergeCrdtBlocks( yblocks, [ makeBlock( 'x', HIDDEN_SECOND ) ], null );
113
+ mergeCrdtBlocks( yblocks, [ makeBlock( 'xy', STEP_TWO_SECOND ) ], null );
114
+ mergeCrdtBlocks( yblocks, [ makeBlock( 'xyq', FINAL_SECOND ) ], null );
115
+ }
116
+
117
+ function runSecondFieldOnlySequence( yblocks ) {
118
+ mergeCrdtBlocks( yblocks, [ makeBlock( '', INITIAL_SECOND ) ], null );
119
+ mergeCrdtBlocks( yblocks, [ makeBlock( '', HIDDEN_SECOND ) ], null );
120
+ mergeCrdtBlocks( yblocks, [ makeBlock( '', STEP_TWO_SECOND ) ], null );
121
+ mergeCrdtBlocks( yblocks, [ makeBlock( '', FINAL_SECOND ) ], null );
122
+ }
123
+
124
+ function runSequenceWithApplyPostChangesToCRDTDoc( ydoc ) {
125
+ applyPostChangesToCRDTDoc(
126
+ ydoc,
127
+ { blocks: [ makeBlock( '', INITIAL_SECOND ) ] },
128
+ SYNCED_PROPERTIES
129
+ );
130
+ applyPostChangesToCRDTDoc(
131
+ ydoc,
132
+ {
133
+ blocks: [ makeBlock( 'x', HIDDEN_SECOND ) ],
134
+ selection: getSelection( 1 ),
135
+ },
136
+ SYNCED_PROPERTIES
137
+ );
138
+ applyPostChangesToCRDTDoc(
139
+ ydoc,
140
+ {
141
+ blocks: [ makeBlock( 'xy', STEP_TWO_SECOND ) ],
142
+ selection: getSelection( 2 ),
143
+ },
144
+ SYNCED_PROPERTIES
145
+ );
146
+ applyPostChangesToCRDTDoc(
147
+ ydoc,
148
+ {
149
+ blocks: [ makeBlock( 'xyq', FINAL_SECOND ) ],
150
+ selection: getSelection( 3 ),
151
+ },
152
+ SYNCED_PROPERTIES
153
+ );
154
+ }
155
+
156
+ function waitForNextTick() {
157
+ return new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
158
+ }
159
+
160
+ describe( 'RTC rich-text cursor scope bug', () => {
161
+ beforeEach( () => {
162
+ jest.clearAllMocks();
163
+ mockGetProviderCreators.mockReturnValue( [
164
+ jest.fn( async () => ( {
165
+ destroy: jest.fn(),
166
+ on: jest.fn(),
167
+ } ) ),
168
+ ] );
169
+ } );
170
+
171
+ it( 'keeps unrelated rich-text fields correct in mergeCrdtBlocks', () => {
172
+ const doc = new Y.Doc();
173
+ const yblocks = doc.getArray( 'blocks' );
174
+
175
+ runSequenceWithMergeCrdtBlocks( yblocks );
176
+
177
+ expect( readSecondFromYBlocks( yblocks ) ).toBe( FINAL_SECOND );
178
+ expect( readVisibleSecondFromYBlocks( yblocks ) ).toBe( FINAL_SECOND );
179
+ } );
180
+
181
+ it( 'stays correct in mergeCrdtBlocks when the same updates are applied without any cursor hint', () => {
182
+ const doc = new Y.Doc();
183
+ const yblocks = doc.getArray( 'blocks' );
184
+
185
+ runSequenceWithMergeCrdtBlocksWithoutCursor( yblocks );
186
+
187
+ expect( readSecondFromYBlocks( yblocks ) ).toBe( FINAL_SECOND );
188
+ expect( readVisibleSecondFromYBlocks( yblocks ) ).toBe( FINAL_SECOND );
189
+ } );
190
+
191
+ it( 'stays correct in mergeCrdtBlocks when only the second field is updated and no cross-field cursor reuse is possible', () => {
192
+ const doc = new Y.Doc();
193
+ const yblocks = doc.getArray( 'blocks' );
194
+
195
+ runSecondFieldOnlySequence( yblocks );
196
+
197
+ expect( readSecondFromYBlocks( yblocks ) ).toBe( FINAL_SECOND );
198
+ expect( readVisibleSecondFromYBlocks( yblocks ) ).toBe( FINAL_SECOND );
199
+ } );
200
+
201
+ it( 'keeps unrelated rich-text fields correct in applyPostChangesToCRDTDoc', () => {
202
+ const doc = new Y.Doc();
203
+
204
+ runSequenceWithApplyPostChangesToCRDTDoc( doc );
205
+
206
+ expect( readSecondFromDoc( doc ) ).toBe( FINAL_SECOND );
207
+ expect( readVisibleSecondFromDoc( doc ) ).toBe( FINAL_SECOND );
208
+ } );
209
+
210
+ it( 'keeps unrelated rich-text fields correct in SyncManager.update', async () => {
211
+ let capturedDoc;
212
+ const manager = createSyncManager();
213
+ const handlers = {
214
+ addUndoMeta: jest.fn(),
215
+ editRecord: jest.fn(),
216
+ getEditedRecord: jest.fn( async () => ( {
217
+ id: 1,
218
+ blocks: [ makeBlock( '', INITIAL_SECOND ) ],
219
+ } ) ),
220
+ onStatusChange: jest.fn(),
221
+ persistCRDTDoc: jest.fn(),
222
+ refetchRecord: jest.fn( async () => {} ),
223
+ restoreUndoMeta: jest.fn(),
224
+ };
225
+ const syncConfig = {
226
+ applyChangesToCRDTDoc: ( ydoc, changes ) => {
227
+ capturedDoc = ydoc;
228
+ applyPostChangesToCRDTDoc( ydoc, changes, SYNCED_PROPERTIES );
229
+ },
230
+ createAwareness: jest.fn(),
231
+ getChangesFromCRDTDoc: jest.fn( () => ( {} ) ),
232
+ getPersistedCRDTDoc: jest.fn( () => null ),
233
+ };
234
+
235
+ await manager.load(
236
+ syncConfig,
237
+ 'postType/post',
238
+ '1',
239
+ { id: 1, blocks: [ makeBlock( '', INITIAL_SECOND ) ] },
240
+ handlers
241
+ );
242
+
243
+ for ( const [ first, second, offset ] of [
244
+ [ 'x', HIDDEN_SECOND, 1 ],
245
+ [ 'xy', STEP_TWO_SECOND, 2 ],
246
+ [ 'xyq', FINAL_SECOND, 3 ],
247
+ ] ) {
248
+ manager.update(
249
+ 'postType/post',
250
+ '1',
251
+ {
252
+ blocks: [ makeBlock( first, second ) ],
253
+ selection: getSelection( offset ),
254
+ },
255
+ 'LOCAL_EDITOR_ORIGIN'
256
+ );
257
+ // SyncManager.update is deferred through yieldToEventLoop.
258
+ // Wait one tick so the CRDT write has been applied before inspecting it.
259
+ await waitForNextTick();
260
+ }
261
+
262
+ expect( readSecondFromDoc( capturedDoc ) ).toBe( FINAL_SECOND );
263
+ expect( readVisibleSecondFromDoc( capturedDoc ) ).toBe( FINAL_SECOND );
264
+
265
+ manager.unload( 'postType/post', '1' );
266
+ } );
267
+ } );