@wordpress/core-data 4.0.1 → 4.0.5

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 (116) hide show
  1. package/README.md +13 -7
  2. package/build/actions.js +178 -122
  3. package/build/actions.js.map +1 -1
  4. package/build/batch/default-processor.js +58 -27
  5. package/build/batch/default-processor.js.map +1 -1
  6. package/build/entities.js +70 -23
  7. package/build/entities.js.map +1 -1
  8. package/build/fetch/__experimental-fetch-url-data.js +1 -1
  9. package/build/fetch/__experimental-fetch-url-data.js.map +1 -1
  10. package/build/index.js +9 -17
  11. package/build/index.js.map +1 -1
  12. package/build/locks/actions.js +17 -77
  13. package/build/locks/actions.js.map +1 -1
  14. package/build/locks/engine.js +77 -0
  15. package/build/locks/engine.js.map +1 -0
  16. package/build/locks/reducer.js +1 -5
  17. package/build/locks/reducer.js.map +1 -1
  18. package/build/locks/selectors.js +6 -6
  19. package/build/locks/selectors.js.map +1 -1
  20. package/build/queried-data/get-query-parts.js +9 -4
  21. package/build/queried-data/get-query-parts.js.map +1 -1
  22. package/build/queried-data/selectors.js +3 -9
  23. package/build/queried-data/selectors.js.map +1 -1
  24. package/build/reducer.js +17 -22
  25. package/build/reducer.js.map +1 -1
  26. package/build/resolvers.js +151 -97
  27. package/build/resolvers.js.map +1 -1
  28. package/build/selectors.js +79 -14
  29. package/build/selectors.js.map +1 -1
  30. package/build/utils/forward-resolver.js +23 -0
  31. package/build/utils/forward-resolver.js.map +1 -0
  32. package/build/utils/index.js +11 -3
  33. package/build/utils/index.js.map +1 -1
  34. package/build/utils/is-raw-attribute.js +19 -0
  35. package/build/utils/is-raw-attribute.js.map +1 -0
  36. package/build-module/actions.js +155 -112
  37. package/build-module/actions.js.map +1 -1
  38. package/build-module/batch/default-processor.js +57 -27
  39. package/build-module/batch/default-processor.js.map +1 -1
  40. package/build-module/entities.js +65 -19
  41. package/build-module/entities.js.map +1 -1
  42. package/build-module/fetch/__experimental-fetch-url-data.js +1 -1
  43. package/build-module/fetch/__experimental-fetch-url-data.js.map +1 -1
  44. package/build-module/index.js +10 -14
  45. package/build-module/index.js.map +1 -1
  46. package/build-module/locks/actions.js +14 -68
  47. package/build-module/locks/actions.js.map +1 -1
  48. package/build-module/locks/engine.js +66 -0
  49. package/build-module/locks/engine.js.map +1 -0
  50. package/build-module/locks/reducer.js +1 -2
  51. package/build-module/locks/reducer.js.map +1 -1
  52. package/build-module/locks/selectors.js +4 -4
  53. package/build-module/locks/selectors.js.map +1 -1
  54. package/build-module/queried-data/get-query-parts.js +9 -4
  55. package/build-module/queried-data/get-query-parts.js.map +1 -1
  56. package/build-module/queried-data/selectors.js +3 -9
  57. package/build-module/queried-data/selectors.js.map +1 -1
  58. package/build-module/reducer.js +15 -19
  59. package/build-module/reducer.js.map +1 -1
  60. package/build-module/resolvers.js +123 -81
  61. package/build-module/resolvers.js.map +1 -1
  62. package/build-module/selectors.js +74 -13
  63. package/build-module/selectors.js.map +1 -1
  64. package/build-module/utils/forward-resolver.js +15 -0
  65. package/build-module/utils/forward-resolver.js.map +1 -0
  66. package/build-module/utils/index.js +2 -1
  67. package/build-module/utils/index.js.map +1 -1
  68. package/build-module/utils/is-raw-attribute.js +12 -0
  69. package/build-module/utils/is-raw-attribute.js.map +1 -0
  70. package/package.json +10 -11
  71. package/src/actions.js +163 -194
  72. package/src/batch/default-processor.js +57 -26
  73. package/src/batch/test/default-processor.js +53 -26
  74. package/src/entities.js +47 -19
  75. package/src/fetch/__experimental-fetch-url-data.js +1 -1
  76. package/src/index.js +7 -10
  77. package/src/locks/actions.js +10 -61
  78. package/src/locks/engine.js +43 -0
  79. package/src/locks/reducer.js +1 -3
  80. package/src/locks/selectors.js +4 -4
  81. package/src/locks/test/engine.js +135 -0
  82. package/src/locks/test/reducer.js +1 -1
  83. package/src/locks/test/selectors.js +105 -124
  84. package/src/queried-data/get-query-parts.js +11 -6
  85. package/src/queried-data/selectors.js +2 -9
  86. package/src/queried-data/test/get-query-parts.js +1 -1
  87. package/src/queried-data/test/selectors.js +1 -0
  88. package/src/reducer.js +14 -19
  89. package/src/resolvers.js +132 -120
  90. package/src/selectors.js +156 -44
  91. package/src/test/actions.js +330 -170
  92. package/src/test/entities.js +40 -26
  93. package/src/test/resolvers.js +270 -223
  94. package/src/test/selectors.js +127 -1
  95. package/src/utils/forward-resolver.js +14 -0
  96. package/src/utils/index.js +2 -1
  97. package/src/utils/is-raw-attribute.js +11 -0
  98. package/src/utils/test/is-raw-attribute.js +22 -0
  99. package/build/controls.js +0 -44
  100. package/build/controls.js.map +0 -1
  101. package/build/locks/index.js +0 -47
  102. package/build/locks/index.js.map +0 -1
  103. package/build/utils/if-not-resolved.js +0 -46
  104. package/build/utils/if-not-resolved.js.map +0 -1
  105. package/build-module/controls.js +0 -31
  106. package/build-module/controls.js.map +0 -1
  107. package/build-module/locks/index.js +0 -4
  108. package/build-module/locks/index.js.map +0 -1
  109. package/build-module/utils/if-not-resolved.js +0 -36
  110. package/build-module/utils/if-not-resolved.js.map +0 -1
  111. package/src/controls.js +0 -31
  112. package/src/locks/index.js +0 -3
  113. package/src/locks/test/actions.js +0 -307
  114. package/src/test/integration.js +0 -264
  115. package/src/utils/if-not-resolved.js +0 -40
  116. package/src/utils/test/if-not-resolved.js +0 -75
@@ -1,10 +1,23 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { chunk } from 'lodash';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
4
9
  import apiFetch from '@wordpress/api-fetch';
5
10
 
6
11
  /**
7
- * Default batch processor. Sends its input requests to /v1/batch.
12
+ * Maximum number of requests to place in a single batch request. Obtained by
13
+ * sending a preflight OPTIONS request to /batch/v1/.
14
+ *
15
+ * @type {number?}
16
+ */
17
+ let maxItems = null;
18
+
19
+ /**
20
+ * Default batch processor. Sends its input requests to /batch/v1.
8
21
  *
9
22
  * @param {Array} requests List of API requests to perform at once.
10
23
  *
@@ -13,33 +26,51 @@ import apiFetch from '@wordpress/api-fetch';
13
26
  * (if not ).
14
27
  */
15
28
  export default async function defaultProcessor( requests ) {
16
- const batchResponse = await apiFetch( {
17
- path: '/batch/v1',
18
- method: 'POST',
19
- data: {
20
- validation: 'require-all-validate',
21
- requests: requests.map( ( request ) => ( {
22
- path: request.path,
23
- body: request.data, // Rename 'data' to 'body'.
24
- method: request.method,
25
- headers: request.headers,
26
- } ) ),
27
- },
28
- } );
29
-
30
- if ( batchResponse.failed ) {
31
- return batchResponse.responses.map( ( response ) => ( {
32
- error: response?.body,
33
- } ) );
29
+ if ( maxItems === null ) {
30
+ const preflightResponse = await apiFetch( {
31
+ path: '/batch/v1',
32
+ method: 'OPTIONS',
33
+ } );
34
+ maxItems = preflightResponse.endpoints[ 0 ].args.requests.maxItems;
34
35
  }
35
36
 
36
- return batchResponse.responses.map( ( response ) => {
37
- const result = {};
38
- if ( response.status >= 200 && response.status < 300 ) {
39
- result.output = response.body;
37
+ const results = [];
38
+
39
+ for ( const batchRequests of chunk( requests, maxItems ) ) {
40
+ const batchResponse = await apiFetch( {
41
+ path: '/batch/v1',
42
+ method: 'POST',
43
+ data: {
44
+ validation: 'require-all-validate',
45
+ requests: batchRequests.map( ( request ) => ( {
46
+ path: request.path,
47
+ body: request.data, // Rename 'data' to 'body'.
48
+ method: request.method,
49
+ headers: request.headers,
50
+ } ) ),
51
+ },
52
+ } );
53
+
54
+ let batchResults;
55
+
56
+ if ( batchResponse.failed ) {
57
+ batchResults = batchResponse.responses.map( ( response ) => ( {
58
+ error: response?.body,
59
+ } ) );
40
60
  } else {
41
- result.error = response.body;
61
+ batchResults = batchResponse.responses.map( ( response ) => {
62
+ const result = {};
63
+ if ( response.status >= 200 && response.status < 300 ) {
64
+ result.output = response.body;
65
+ } else {
66
+ result.error = response.body;
67
+ }
68
+ return result;
69
+ } );
42
70
  }
43
- return result;
44
- } );
71
+
72
+ results.push( ...batchResults );
73
+ }
74
+
75
+ return results;
45
76
  }
@@ -11,6 +11,18 @@ import defaultProcessor from '../default-processor';
11
11
  jest.mock( '@wordpress/api-fetch' );
12
12
 
13
13
  describe( 'defaultProcessor', () => {
14
+ const preflightResponse = {
15
+ endpoints: [
16
+ {
17
+ args: {
18
+ requests: {
19
+ maxItems: 25,
20
+ },
21
+ },
22
+ },
23
+ ],
24
+ };
25
+
14
26
  const requests = [
15
27
  {
16
28
  path: '/v1/cricketers',
@@ -26,7 +38,12 @@ describe( 'defaultProcessor', () => {
26
38
  },
27
39
  ];
28
40
 
29
- const expectedFetchOptions = {
41
+ const expectedPreflightOptions = {
42
+ path: '/batch/v1',
43
+ method: 'OPTIONS',
44
+ };
45
+
46
+ const expectedBatchOptions = {
30
47
  path: '/batch/v1',
31
48
  method: 'POST',
32
49
  data: {
@@ -49,21 +66,26 @@ describe( 'defaultProcessor', () => {
49
66
  };
50
67
 
51
68
  it( 'handles a successful request', async () => {
52
- apiFetch.mockImplementation( async () => ( {
53
- failed: false,
54
- responses: [
55
- {
56
- status: 200,
57
- body: 'Lyon',
58
- },
59
- {
60
- status: 400,
61
- body: 'Error!',
62
- },
63
- ],
64
- } ) );
69
+ apiFetch.mockImplementation( async ( { method } ) =>
70
+ method === 'OPTIONS'
71
+ ? preflightResponse
72
+ : {
73
+ failed: false,
74
+ responses: [
75
+ {
76
+ status: 200,
77
+ body: 'Lyon',
78
+ },
79
+ {
80
+ status: 400,
81
+ body: 'Error!',
82
+ },
83
+ ],
84
+ }
85
+ );
65
86
  const results = await defaultProcessor( requests );
66
- expect( apiFetch ).toHaveBeenCalledWith( expectedFetchOptions );
87
+ expect( apiFetch ).toHaveBeenCalledWith( expectedPreflightOptions );
88
+ expect( apiFetch ).toHaveBeenCalledWith( expectedBatchOptions );
67
89
  expect( results ).toEqual( [
68
90
  { output: 'Lyon' },
69
91
  { error: 'Error!' },
@@ -71,18 +93,23 @@ describe( 'defaultProcessor', () => {
71
93
  } );
72
94
 
73
95
  it( 'handles a failed request', async () => {
74
- apiFetch.mockImplementation( async () => ( {
75
- failed: true,
76
- responses: [
77
- null,
78
- {
79
- status: 400,
80
- body: 'Error!',
81
- },
82
- ],
83
- } ) );
96
+ apiFetch.mockImplementation( async ( { method } ) =>
97
+ method === 'OPTIONS'
98
+ ? preflightResponse
99
+ : {
100
+ failed: true,
101
+ responses: [
102
+ null,
103
+ {
104
+ status: 400,
105
+ body: 'Error!',
106
+ },
107
+ ],
108
+ }
109
+ );
84
110
  const results = await defaultProcessor( requests );
85
- expect( apiFetch ).toHaveBeenCalledWith( expectedFetchOptions );
111
+ expect( apiFetch ).toHaveBeenCalledWith( expectedPreflightOptions );
112
+ expect( apiFetch ).toHaveBeenCalledWith( expectedBatchOptions );
86
113
  expect( results ).toEqual( [
87
114
  { error: undefined },
88
115
  { error: 'Error!' },
package/src/entities.js CHANGED
@@ -6,24 +6,24 @@ import { upperFirst, camelCase, map, find, get, startCase } from 'lodash';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { controls } from '@wordpress/data';
10
- import { apiFetch } from '@wordpress/data-controls';
9
+ import apiFetch from '@wordpress/api-fetch';
11
10
  import { __ } from '@wordpress/i18n';
12
11
 
13
12
  /**
14
13
  * Internal dependencies
15
14
  */
16
15
  import { addEntities } from './actions';
17
- import { STORE_NAME } from './name';
18
16
 
19
17
  export const DEFAULT_ENTITY_KEY = 'id';
20
18
 
19
+ const POST_RAW_ATTRIBUTES = [ 'title', 'excerpt', 'content' ];
20
+
21
21
  export const defaultEntities = [
22
22
  {
23
23
  label: __( 'Base' ),
24
24
  name: '__unstableBase',
25
25
  kind: 'root',
26
- baseURL: '',
26
+ baseURL: '/',
27
27
  },
28
28
  {
29
29
  label: __( 'Site' ),
@@ -41,6 +41,7 @@ export const defaultEntities = [
41
41
  key: 'slug',
42
42
  baseURL: '/wp/v2/types',
43
43
  baseURLParams: { context: 'edit' },
44
+ rawAttributes: POST_RAW_ATTRIBUTES,
44
45
  },
45
46
  {
46
47
  name: 'media',
@@ -115,6 +116,7 @@ export const defaultEntities = [
115
116
  baseURLParams: { context: 'edit' },
116
117
  plural: 'menuItems',
117
118
  label: __( 'Menu Item' ),
119
+ rawAttributes: [ 'title', 'content' ],
118
120
  },
119
121
  {
120
122
  name: 'menuLocation',
@@ -125,6 +127,33 @@ export const defaultEntities = [
125
127
  label: __( 'Menu Location' ),
126
128
  key: 'name',
127
129
  },
130
+ {
131
+ name: 'navigationArea',
132
+ kind: 'root',
133
+ baseURL: '/__experimental/block-navigation-areas',
134
+ baseURLParams: { context: 'edit' },
135
+ plural: 'navigationAreas',
136
+ label: __( 'Navigation Area' ),
137
+ key: 'name',
138
+ getTitle: ( record ) => record?.description,
139
+ },
140
+ {
141
+ label: __( 'Global Styles' ),
142
+ name: 'globalStyles',
143
+ kind: 'root',
144
+ baseURL: '/wp/v2/global-styles',
145
+ baseURLParams: { context: 'edit' },
146
+ plural: 'globalStylesVariations', // should be different than name
147
+ getTitle: ( record ) => record?.title?.rendered || record?.title,
148
+ },
149
+ {
150
+ label: __( 'Themes' ),
151
+ name: 'theme',
152
+ kind: 'root',
153
+ baseURL: '/wp/v2/themes',
154
+ baseURLParams: { context: 'edit' },
155
+ key: 'stylesheet',
156
+ },
128
157
  ];
129
158
 
130
159
  export const kinds = [
@@ -167,15 +196,16 @@ export const prePersistPostType = ( persistedRecord, edits ) => {
167
196
  *
168
197
  * @return {Promise} Entities promise
169
198
  */
170
- function* loadPostTypeEntities() {
171
- const postTypes = yield apiFetch( { path: '/wp/v2/types?context=edit' } );
199
+ async function loadPostTypeEntities() {
200
+ const postTypes = await apiFetch( { path: '/wp/v2/types?context=edit' } );
172
201
  return map( postTypes, ( postType, name ) => {
173
202
  const isTemplate = [ 'wp_template', 'wp_template_part' ].includes(
174
203
  name
175
204
  );
205
+ const namespace = postType?.rest_namespace ?? 'wp/v2';
176
206
  return {
177
207
  kind: 'postType',
178
- baseURL: '/wp/v2/' + postType.rest_base,
208
+ baseURL: `/${ namespace }/${ postType.rest_base }`,
179
209
  baseURLParams: { context: 'edit' },
180
210
  name,
181
211
  label: postType.labels.singular_name,
@@ -184,6 +214,7 @@ function* loadPostTypeEntities() {
184
214
  selection: true,
185
215
  },
186
216
  mergedEdits: { meta: true },
217
+ rawAttributes: POST_RAW_ATTRIBUTES,
187
218
  getTitle: ( record ) =>
188
219
  record?.title?.rendered ||
189
220
  record?.title ||
@@ -199,14 +230,15 @@ function* loadPostTypeEntities() {
199
230
  *
200
231
  * @return {Promise} Entities promise
201
232
  */
202
- function* loadTaxonomyEntities() {
203
- const taxonomies = yield apiFetch( {
233
+ async function loadTaxonomyEntities() {
234
+ const taxonomies = await apiFetch( {
204
235
  path: '/wp/v2/taxonomies?context=edit',
205
236
  } );
206
237
  return map( taxonomies, ( taxonomy, name ) => {
238
+ const namespace = taxonomy?.rest_namespace ?? 'wp/v2';
207
239
  return {
208
240
  kind: 'taxonomy',
209
- baseURL: '/wp/v2/' + taxonomy.rest_base,
241
+ baseURL: `/${ namespace }/${ taxonomy.rest_base }`,
210
242
  baseURLParams: { context: 'edit' },
211
243
  name,
212
244
  label: taxonomy.labels.singular_name,
@@ -248,12 +280,8 @@ export const getMethodName = (
248
280
  *
249
281
  * @return {Array} Entities
250
282
  */
251
- export function* getKindEntities( kind ) {
252
- let entities = yield controls.select(
253
- STORE_NAME,
254
- 'getEntitiesByKind',
255
- kind
256
- );
283
+ export const getKindEntities = ( kind ) => async ( { select, dispatch } ) => {
284
+ let entities = select.getEntitiesByKind( kind );
257
285
  if ( entities && entities.length !== 0 ) {
258
286
  return entities;
259
287
  }
@@ -263,8 +291,8 @@ export function* getKindEntities( kind ) {
263
291
  return [];
264
292
  }
265
293
 
266
- entities = yield kindConfig.loadEntities();
267
- yield addEntities( entities );
294
+ entities = await kindConfig.loadEntities();
295
+ dispatch( addEntities( entities ) );
268
296
 
269
297
  return entities;
270
- }
298
+ };
@@ -45,7 +45,7 @@ const CACHE = new Map();
45
45
  * @return {Promise< WPRemoteUrlData[] >} Remote URL data.
46
46
  */
47
47
  const fetchUrlData = async ( url, options = {} ) => {
48
- const endpoint = '/__experimental/url-details';
48
+ const endpoint = '/wp-block-editor/v1/url-details';
49
49
 
50
50
  const args = {
51
51
  url: prependHTTP( url ),
package/src/index.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { createReduxStore, register } from '@wordpress/data';
5
- import { controls } from '@wordpress/data-controls';
6
5
 
7
6
  /**
8
7
  * Internal dependencies
@@ -11,9 +10,7 @@ import reducer from './reducer';
11
10
  import * as selectors from './selectors';
12
11
  import * as actions from './actions';
13
12
  import * as resolvers from './resolvers';
14
- import * as locksSelectors from './locks/selectors';
15
- import * as locksActions from './locks/actions';
16
- import customControls from './controls';
13
+ import createLocksActions from './locks/actions';
17
14
  import { defaultEntities, getMethodName } from './entities';
18
15
  import { STORE_NAME } from './name';
19
16
 
@@ -57,13 +54,13 @@ const entityActions = defaultEntities.reduce( ( result, entity ) => {
57
54
  return result;
58
55
  }, {} );
59
56
 
60
- const storeConfig = {
57
+ const storeConfig = () => ( {
61
58
  reducer,
62
- controls: { ...customControls, ...controls },
63
- actions: { ...actions, ...entityActions, ...locksActions },
64
- selectors: { ...selectors, ...entitySelectors, ...locksSelectors },
59
+ actions: { ...actions, ...entityActions, ...createLocksActions() },
60
+ selectors: { ...selectors, ...entitySelectors },
65
61
  resolvers: { ...resolvers, ...entityResolvers },
66
- };
62
+ __experimentalUseThunks: true,
63
+ } );
67
64
 
68
65
  /**
69
66
  * Store definition for the code data namespace.
@@ -72,7 +69,7 @@ const storeConfig = {
72
69
  *
73
70
  * @type {Object}
74
71
  */
75
- export const store = createReduxStore( STORE_NAME, storeConfig );
72
+ export const store = createReduxStore( STORE_NAME, storeConfig() );
76
73
 
77
74
  register( store );
78
75
 
@@ -1,69 +1,18 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import { __unstableAwaitPromise } from '@wordpress/data-controls';
5
- import { controls } from '@wordpress/data';
6
-
7
1
  /**
8
2
  * Internal dependencies
9
3
  */
10
- import { STORE_NAME } from '../name';
4
+ import createLocks from './engine';
11
5
 
12
- export function* __unstableAcquireStoreLock( store, path, { exclusive } ) {
13
- const promise = yield* __unstableEnqueueLockRequest( store, path, {
14
- exclusive,
15
- } );
16
- yield* __unstableProcessPendingLockRequests();
17
- return yield __unstableAwaitPromise( promise );
18
- }
6
+ export default function createLocksActions() {
7
+ const locks = createLocks();
19
8
 
20
- export function* __unstableEnqueueLockRequest( store, path, { exclusive } ) {
21
- let notifyAcquired;
22
- const promise = new Promise( ( resolve ) => {
23
- notifyAcquired = resolve;
24
- } );
25
- yield {
26
- type: 'ENQUEUE_LOCK_REQUEST',
27
- request: { store, path, exclusive, notifyAcquired },
28
- };
29
- return promise;
30
- }
31
-
32
- export function* __unstableReleaseStoreLock( lock ) {
33
- yield {
34
- type: 'RELEASE_LOCK',
35
- lock,
36
- };
37
- yield* __unstableProcessPendingLockRequests();
38
- }
9
+ function __unstableAcquireStoreLock( store, path, { exclusive } ) {
10
+ return () => locks.acquire( store, path, exclusive );
11
+ }
39
12
 
40
- export function* __unstableProcessPendingLockRequests() {
41
- yield {
42
- type: 'PROCESS_PENDING_LOCK_REQUESTS',
43
- };
44
- const lockRequests = yield controls.select(
45
- STORE_NAME,
46
- '__unstableGetPendingLockRequests'
47
- );
48
- for ( const request of lockRequests ) {
49
- const { store, path, exclusive, notifyAcquired } = request;
50
- const isAvailable = yield controls.select(
51
- STORE_NAME,
52
- '__unstableIsLockAvailable',
53
- store,
54
- path,
55
- {
56
- exclusive,
57
- }
58
- );
59
- if ( isAvailable ) {
60
- const lock = { store, path, exclusive };
61
- yield {
62
- type: 'GRANT_LOCK_REQUEST',
63
- lock,
64
- request,
65
- };
66
- notifyAcquired( lock );
67
- }
13
+ function __unstableReleaseStoreLock( lock ) {
14
+ return () => locks.release( lock );
68
15
  }
16
+
17
+ return { __unstableAcquireStoreLock, __unstableReleaseStoreLock };
69
18
  }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import reducer from './reducer';
5
+ import { isLockAvailable, getPendingLockRequests } from './selectors';
6
+
7
+ export default function createLocks() {
8
+ let state = reducer( undefined, { type: '@@INIT' } );
9
+
10
+ function processPendingLockRequests() {
11
+ for ( const request of getPendingLockRequests( state ) ) {
12
+ const { store, path, exclusive, notifyAcquired } = request;
13
+ if ( isLockAvailable( state, store, path, { exclusive } ) ) {
14
+ const lock = { store, path, exclusive };
15
+ state = reducer( state, {
16
+ type: 'GRANT_LOCK_REQUEST',
17
+ lock,
18
+ request,
19
+ } );
20
+ notifyAcquired( lock );
21
+ }
22
+ }
23
+ }
24
+
25
+ function acquire( store, path, exclusive ) {
26
+ return new Promise( ( resolve ) => {
27
+ state = reducer( state, {
28
+ type: 'ENQUEUE_LOCK_REQUEST',
29
+ request: { store, path, exclusive, notifyAcquired: resolve },
30
+ } );
31
+ processPendingLockRequests();
32
+ } );
33
+ }
34
+ function release( lock ) {
35
+ state = reducer( state, {
36
+ type: 'RELEASE_LOCK',
37
+ lock,
38
+ } );
39
+ processPendingLockRequests();
40
+ }
41
+
42
+ return { acquire, release };
43
+ }
@@ -19,7 +19,7 @@ const DEFAULT_STATE = {
19
19
  *
20
20
  * @return {Object} Updated state.
21
21
  */
22
- export function locks( state = DEFAULT_STATE, action ) {
22
+ export default function locks( state = DEFAULT_STATE, action ) {
23
23
  switch ( action.type ) {
24
24
  case 'ENQUEUE_LOCK_REQUEST': {
25
25
  const { request } = action;
@@ -60,5 +60,3 @@ export function locks( state = DEFAULT_STATE, action ) {
60
60
 
61
61
  return state;
62
62
  }
63
-
64
- export default locks;
@@ -8,13 +8,13 @@ import {
8
8
  getNode,
9
9
  } from './utils';
10
10
 
11
- export function __unstableGetPendingLockRequests( state ) {
12
- return state.locks.requests;
11
+ export function getPendingLockRequests( state ) {
12
+ return state.requests;
13
13
  }
14
14
 
15
- export function __unstableIsLockAvailable( state, store, path, { exclusive } ) {
15
+ export function isLockAvailable( state, store, path, { exclusive } ) {
16
16
  const storePath = [ store, ...path ];
17
- const locks = state.locks.tree;
17
+ const locks = state.tree;
18
18
 
19
19
  // Validate all parents and the node itself
20
20
  for ( const node of iteratePath( locks, storePath ) ) {