@wordpress/data 9.4.0 → 9.5.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 (50) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/use-dispatch/use-dispatch-with-map.js +2 -6
  3. package/build/components/use-dispatch/use-dispatch-with-map.js.map +1 -1
  4. package/build/components/use-select/index.js +1 -1
  5. package/build/components/use-select/index.js.map +1 -1
  6. package/build/controls.js +18 -37
  7. package/build/controls.js.map +1 -1
  8. package/build/factory.js +1 -3
  9. package/build/factory.js.map +1 -1
  10. package/build/redux-store/index.js +100 -197
  11. package/build/redux-store/index.js.map +1 -1
  12. package/build/redux-store/metadata/reducer.js +2 -8
  13. package/build/redux-store/metadata/reducer.js.map +1 -1
  14. package/build/redux-store/metadata/selectors.js +5 -15
  15. package/build/redux-store/metadata/selectors.js.map +1 -1
  16. package/build/redux-store/metadata/utils.js +1 -3
  17. package/build/redux-store/metadata/utils.js.map +1 -1
  18. package/build/registry.js +8 -18
  19. package/build/registry.js.map +1 -1
  20. package/build/resolvers-cache-middleware.js +3 -6
  21. package/build/resolvers-cache-middleware.js.map +1 -1
  22. package/build/store/index.js +2 -10
  23. package/build/store/index.js.map +1 -1
  24. package/build-module/components/use-dispatch/use-dispatch-with-map.js +2 -6
  25. package/build-module/components/use-dispatch/use-dispatch-with-map.js.map +1 -1
  26. package/build-module/components/use-select/index.js +1 -1
  27. package/build-module/components/use-select/index.js.map +1 -1
  28. package/build-module/controls.js +18 -37
  29. package/build-module/controls.js.map +1 -1
  30. package/build-module/factory.js +1 -3
  31. package/build-module/factory.js.map +1 -1
  32. package/build-module/redux-store/index.js +100 -197
  33. package/build-module/redux-store/index.js.map +1 -1
  34. package/build-module/redux-store/metadata/reducer.js +2 -8
  35. package/build-module/redux-store/metadata/reducer.js.map +1 -1
  36. package/build-module/redux-store/metadata/selectors.js +5 -15
  37. package/build-module/redux-store/metadata/selectors.js.map +1 -1
  38. package/build-module/redux-store/metadata/utils.js +1 -3
  39. package/build-module/redux-store/metadata/utils.js.map +1 -1
  40. package/build-module/registry.js +8 -18
  41. package/build-module/registry.js.map +1 -1
  42. package/build-module/resolvers-cache-middleware.js +3 -6
  43. package/build-module/resolvers-cache-middleware.js.map +1 -1
  44. package/build-module/store/index.js +2 -10
  45. package/build-module/store/index.js.map +1 -1
  46. package/build-types/redux-store/index.d.ts.map +1 -1
  47. package/package.json +9 -9
  48. package/src/redux-store/index.js +129 -208
  49. package/src/test/privateAPIs.js +31 -0
  50. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/data/src/store/index.js"],"names":["coreDataStore","name","instantiate","registry","getCoreDataSelector","selectorName","key","args","select","getCoreDataAction","actionName","dispatch","getSelectors","Object","fromEntries","map","getActions","subscribe"],"mappings":"AAAA,MAAMA,aAAa,GAAG;AACrBC,EAAAA,IAAI,EAAE,WADe;;AAErBC,EAAAA,WAAW,CAAEC,QAAF,EAAa;AACvB,UAAMC,mBAAmB,GACtBC,YAAF,IACA,UAAEC,GAAF,EAAoB;AAAA,wCAAVC,IAAU;AAAVA,QAAAA,IAAU;AAAA;;AACnB,aAAOJ,QAAQ,CAACK,MAAT,CAAiBF,GAAjB,EAAwBD,YAAxB,EAAwC,GAAGE,IAA3C,CAAP;AACA,KAJF;;AAMA,UAAME,iBAAiB,GACpBC,UAAF,IACA,UAAEJ,GAAF,EAAoB;AAAA,yCAAVC,IAAU;AAAVA,QAAAA,IAAU;AAAA;;AACnB,aAAOJ,QAAQ,CAACQ,QAAT,CAAmBL,GAAnB,EAA0BI,UAA1B,EAAwC,GAAGH,IAA3C,CAAP;AACA,KAJF;;AAMA,WAAO;AACNK,MAAAA,YAAY,GAAG;AACd,eAAOC,MAAM,CAACC,WAAP,CACN,CACC,gBADD,EAEC,sBAFD,EAGC,uBAHD,EAIC,aAJD,EAKC,oBALD,EAMEC,GANF,CAMSV,YAAF,IAAoB,CAC1BA,YAD0B,EAE1BD,mBAAmB,CAAEC,YAAF,CAFO,CAN3B,CADM,CAAP;AAYA,OAdK;;AAgBNW,MAAAA,UAAU,GAAG;AACZ,eAAOH,MAAM,CAACC,WAAP,CACN,CACC,iBADD,EAEC,kBAFD,EAGC,sBAHD,EAIC,8BAJD,EAKC,sCALD,EAMEC,GANF,CAMSL,UAAF,IAAkB,CACxBA,UADwB,EAExBD,iBAAiB,CAAEC,UAAF,CAFO,CANzB,CADM,CAAP;AAYA,OA7BK;;AA+BNO,MAAAA,SAAS,GAAG;AACX;AACA;AACA;AACA;AACA,eAAO,MAAM,MAAM,CAAE,CAArB;AACA;;AArCK,KAAP;AAuCA;;AAtDoB,CAAtB;AAyDA,eAAejB,aAAf","sourcesContent":["const coreDataStore = {\n\tname: 'core/data',\n\tinstantiate( registry ) {\n\t\tconst getCoreDataSelector =\n\t\t\t( selectorName ) =>\n\t\t\t( key, ...args ) => {\n\t\t\t\treturn registry.select( key )[ selectorName ]( ...args );\n\t\t\t};\n\n\t\tconst getCoreDataAction =\n\t\t\t( actionName ) =>\n\t\t\t( key, ...args ) => {\n\t\t\t\treturn registry.dispatch( key )[ actionName ]( ...args );\n\t\t\t};\n\n\t\treturn {\n\t\t\tgetSelectors() {\n\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t[\n\t\t\t\t\t\t'getIsResolving',\n\t\t\t\t\t\t'hasStartedResolution',\n\t\t\t\t\t\t'hasFinishedResolution',\n\t\t\t\t\t\t'isResolving',\n\t\t\t\t\t\t'getCachedResolvers',\n\t\t\t\t\t].map( ( selectorName ) => [\n\t\t\t\t\t\tselectorName,\n\t\t\t\t\t\tgetCoreDataSelector( selectorName ),\n\t\t\t\t\t] )\n\t\t\t\t);\n\t\t\t},\n\n\t\t\tgetActions() {\n\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t[\n\t\t\t\t\t\t'startResolution',\n\t\t\t\t\t\t'finishResolution',\n\t\t\t\t\t\t'invalidateResolution',\n\t\t\t\t\t\t'invalidateResolutionForStore',\n\t\t\t\t\t\t'invalidateResolutionForStoreSelector',\n\t\t\t\t\t].map( ( actionName ) => [\n\t\t\t\t\t\tactionName,\n\t\t\t\t\t\tgetCoreDataAction( actionName ),\n\t\t\t\t\t] )\n\t\t\t\t);\n\t\t\t},\n\n\t\t\tsubscribe() {\n\t\t\t\t// There's no reasons to trigger any listener when we subscribe to this store\n\t\t\t\t// because there's no state stored in this store that need to retrigger selectors\n\t\t\t\t// if a change happens, the corresponding store where the tracking stated live\n\t\t\t\t// would have already triggered a \"subscribe\" call.\n\t\t\t\treturn () => () => {};\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default coreDataStore;\n"]}
1
+ {"version":3,"sources":["@wordpress/data/src/store/index.js"],"names":["coreDataStore","name","instantiate","registry","getCoreDataSelector","selectorName","key","args","select","getCoreDataAction","actionName","dispatch","getSelectors","Object","fromEntries","map","getActions","subscribe"],"mappings":"AAAA,MAAMA,aAAa,GAAG;AACrBC,EAAAA,IAAI,EAAE,WADe;;AAErBC,EAAAA,WAAW,CAAEC,QAAF,EAAa;AACvB,UAAMC,mBAAmB,GACtBC,YAAF,IACA,CAAEC,GAAF,EAAO,GAAGC,IAAV,KAAoB;AACnB,aAAOJ,QAAQ,CAACK,MAAT,CAAiBF,GAAjB,EAAwBD,YAAxB,EAAwC,GAAGE,IAA3C,CAAP;AACA,KAJF;;AAMA,UAAME,iBAAiB,GACpBC,UAAF,IACA,CAAEJ,GAAF,EAAO,GAAGC,IAAV,KAAoB;AACnB,aAAOJ,QAAQ,CAACQ,QAAT,CAAmBL,GAAnB,EAA0BI,UAA1B,EAAwC,GAAGH,IAA3C,CAAP;AACA,KAJF;;AAMA,WAAO;AACNK,MAAAA,YAAY,GAAG;AACd,eAAOC,MAAM,CAACC,WAAP,CACN,CACC,gBADD,EAEC,sBAFD,EAGC,uBAHD,EAIC,aAJD,EAKC,oBALD,EAMEC,GANF,CAMSV,YAAF,IAAoB,CAC1BA,YAD0B,EAE1BD,mBAAmB,CAAEC,YAAF,CAFO,CAN3B,CADM,CAAP;AAYA,OAdK;;AAgBNW,MAAAA,UAAU,GAAG;AACZ,eAAOH,MAAM,CAACC,WAAP,CACN,CACC,iBADD,EAEC,kBAFD,EAGC,sBAHD,EAIC,8BAJD,EAKC,sCALD,EAMEC,GANF,CAMSL,UAAF,IAAkB,CACxBA,UADwB,EAExBD,iBAAiB,CAAEC,UAAF,CAFO,CANzB,CADM,CAAP;AAYA,OA7BK;;AA+BNO,MAAAA,SAAS,GAAG;AACX;AACA;AACA;AACA;AACA,eAAO,MAAM,MAAM,CAAE,CAArB;AACA;;AArCK,KAAP;AAuCA;;AAtDoB,CAAtB;AAyDA,eAAejB,aAAf","sourcesContent":["const coreDataStore = {\n\tname: 'core/data',\n\tinstantiate( registry ) {\n\t\tconst getCoreDataSelector =\n\t\t\t( selectorName ) =>\n\t\t\t( key, ...args ) => {\n\t\t\t\treturn registry.select( key )[ selectorName ]( ...args );\n\t\t\t};\n\n\t\tconst getCoreDataAction =\n\t\t\t( actionName ) =>\n\t\t\t( key, ...args ) => {\n\t\t\t\treturn registry.dispatch( key )[ actionName ]( ...args );\n\t\t\t};\n\n\t\treturn {\n\t\t\tgetSelectors() {\n\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t[\n\t\t\t\t\t\t'getIsResolving',\n\t\t\t\t\t\t'hasStartedResolution',\n\t\t\t\t\t\t'hasFinishedResolution',\n\t\t\t\t\t\t'isResolving',\n\t\t\t\t\t\t'getCachedResolvers',\n\t\t\t\t\t].map( ( selectorName ) => [\n\t\t\t\t\t\tselectorName,\n\t\t\t\t\t\tgetCoreDataSelector( selectorName ),\n\t\t\t\t\t] )\n\t\t\t\t);\n\t\t\t},\n\n\t\t\tgetActions() {\n\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t[\n\t\t\t\t\t\t'startResolution',\n\t\t\t\t\t\t'finishResolution',\n\t\t\t\t\t\t'invalidateResolution',\n\t\t\t\t\t\t'invalidateResolutionForStore',\n\t\t\t\t\t\t'invalidateResolutionForStoreSelector',\n\t\t\t\t\t].map( ( actionName ) => [\n\t\t\t\t\t\tactionName,\n\t\t\t\t\t\tgetCoreDataAction( actionName ),\n\t\t\t\t\t] )\n\t\t\t\t);\n\t\t\t},\n\n\t\t\tsubscribe() {\n\t\t\t\t// There's no reasons to trigger any listener when we subscribe to this store\n\t\t\t\t// because there's no state stored in this store that need to retrigger selectors\n\t\t\t\t// if a change happens, the corresponding store where the tracking stated live\n\t\t\t\t// would have already triggered a \"subscribe\" call.\n\t\t\t\treturn () => () => {};\n\t\t\t},\n\t\t};\n\t},\n};\n\nexport default coreDataStore;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/redux-store/index.js"],"names":[],"mappings":"AAwGA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qGAPW,MAAM,+KAoLhB;2BAtRa,OAAO,UAAU,EAAE,YAAY;sEAEhC,OAAO,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC;sFAIrC,OAAO,UAAU,EAAE,gBAAgB,CAAC,KAAK,EAAC,OAAO,EAAC,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/redux-store/index.js"],"names":[],"mappings":"AAuGA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qGAPW,MAAM,+KAoLhB;2BArRa,OAAO,UAAU,EAAE,YAAY;sEAEhC,OAAO,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC;sFAIrC,OAAO,UAAU,EAAE,gBAAgB,CAAC,KAAK,EAAC,OAAO,EAAC,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/data",
3
- "version": "9.4.0",
3
+ "version": "9.5.0",
4
4
  "description": "Data module for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -29,13 +29,13 @@
29
29
  "sideEffects": false,
30
30
  "dependencies": {
31
31
  "@babel/runtime": "^7.16.0",
32
- "@wordpress/compose": "^6.11.0",
33
- "@wordpress/deprecated": "^3.34.0",
34
- "@wordpress/element": "^5.11.0",
35
- "@wordpress/is-shallow-equal": "^4.34.0",
36
- "@wordpress/priority-queue": "^2.34.0",
37
- "@wordpress/private-apis": "^0.16.0",
38
- "@wordpress/redux-routine": "^4.34.0",
32
+ "@wordpress/compose": "^6.12.0",
33
+ "@wordpress/deprecated": "^3.35.0",
34
+ "@wordpress/element": "^5.12.0",
35
+ "@wordpress/is-shallow-equal": "^4.35.0",
36
+ "@wordpress/priority-queue": "^2.35.0",
37
+ "@wordpress/private-apis": "^0.17.0",
38
+ "@wordpress/redux-routine": "^4.35.0",
39
39
  "deepmerge": "^4.3.0",
40
40
  "equivalent-key-map": "^0.2.2",
41
41
  "is-plain-object": "^5.0.0",
@@ -50,5 +50,5 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "c7c79cb11b677adcbf06cf5f8cfb6c5ec1699f19"
53
+ "gitHead": "a92f606309b1541b834ff9b0a76ed2a466fc45ed"
54
54
  }
@@ -54,12 +54,11 @@ const trimUndefinedValues = ( array ) => {
54
54
  * @return {Array} Transformed object.
55
55
  */
56
56
  const mapValues = ( obj, callback ) =>
57
- Object.entries( obj ?? {} ).reduce(
58
- ( acc, [ key, value ] ) => ( {
59
- ...acc,
60
- [ key ]: callback( value, key ),
61
- } ),
62
- {}
57
+ Object.fromEntries(
58
+ Object.entries( obj ?? {} ).map( ( [ key, value ] ) => [
59
+ key,
60
+ callback( value, key ),
61
+ ] )
63
62
  );
64
63
 
65
64
  // Convert Map objects to plain objects
@@ -176,77 +175,77 @@ export default function createReduxStore( key, options ) {
176
175
  lock( store, privateRegistrationFunctions );
177
176
  const resolversCache = createResolversCache();
178
177
 
179
- let resolvers;
180
- const actions = mapActions(
181
- {
182
- ...metadataActions,
183
- ...options.actions,
184
- },
185
- store
186
- );
178
+ function bindAction( action ) {
179
+ return ( ...args ) =>
180
+ Promise.resolve( store.dispatch( action( ...args ) ) );
181
+ }
182
+
183
+ const actions = {
184
+ ...mapValues( metadataActions, bindAction ),
185
+ ...mapValues( options.actions, bindAction ),
186
+ };
187
+
187
188
  lock(
188
189
  actions,
189
190
  new Proxy( privateActions, {
190
191
  get: ( target, prop ) => {
191
- return (
192
- mapActions( privateActions, store )[ prop ] ||
193
- actions[ prop ]
194
- );
192
+ const privateAction = privateActions[ prop ];
193
+ return privateAction
194
+ ? bindAction( privateAction )
195
+ : actions[ prop ];
195
196
  },
196
197
  } )
197
198
  );
198
199
 
199
- let selectors = mapSelectors(
200
- {
201
- ...mapValues(
202
- metadataSelectors,
203
- ( selector ) =>
204
- ( state, ...args ) =>
205
- selector( state.metadata, ...args )
206
- ),
207
- ...mapValues( options.selectors, ( selector ) => {
208
- if ( selector.isRegistrySelector ) {
209
- selector.registry = registry;
210
- }
200
+ function bindSelector( selector ) {
201
+ if ( selector.isRegistrySelector ) {
202
+ selector.registry = registry;
203
+ }
204
+ const boundSelector = ( ...args ) => {
205
+ const state = store.__unstableOriginalGetState();
206
+ return selector( state.root, ...args );
207
+ };
208
+ boundSelector.hasResolver = false;
209
+ return boundSelector;
210
+ }
211
211
 
212
- return ( state, ...args ) =>
213
- selector( state.root, ...args );
214
- } ),
215
- },
216
- store
217
- );
218
- lock(
219
- selectors,
220
- new Proxy( privateSelectors, {
221
- get: ( target, prop ) => {
222
- return (
223
- mapSelectors(
224
- mapValues( privateSelectors, ( selector ) => {
225
- if ( selector.isRegistrySelector ) {
226
- selector.registry = registry;
227
- }
228
-
229
- return ( state, ...args ) =>
230
- selector( state.root, ...args );
231
- } ),
232
- store
233
- )[ prop ] || selectors[ prop ]
234
- );
235
- },
236
- } )
237
- );
212
+ function bindMetadataSelector( selector ) {
213
+ const boundSelector = ( ...args ) => {
214
+ const state = store.__unstableOriginalGetState();
215
+ return selector( state.metadata, ...args );
216
+ };
217
+ boundSelector.hasResolver = false;
218
+ return boundSelector;
219
+ }
238
220
 
221
+ let selectors = {
222
+ ...mapValues( metadataSelectors, bindMetadataSelector ),
223
+ ...mapValues( options.selectors, bindSelector ),
224
+ };
225
+
226
+ let resolvers;
239
227
  if ( options.resolvers ) {
240
- const result = mapResolvers(
241
- options.resolvers,
228
+ resolvers = mapResolvers( options.resolvers );
229
+ selectors = mapSelectorsWithResolvers(
242
230
  selectors,
231
+ resolvers,
243
232
  store,
244
233
  resolversCache
245
234
  );
246
- resolvers = result.resolvers;
247
- selectors = result.selectors;
248
235
  }
249
236
 
237
+ lock(
238
+ selectors,
239
+ new Proxy( privateSelectors, {
240
+ get: ( target, prop ) => {
241
+ const privateSelector = privateSelectors[ prop ];
242
+ return privateSelector
243
+ ? bindSelector( privateSelector )
244
+ : selectors[ prop ];
245
+ },
246
+ } )
247
+ );
248
+
250
249
  const resolveSelectors = mapResolveSelectors( selectors, store );
251
250
  const suspendSelectors = mapSuspendSelectors( selectors, store );
252
251
 
@@ -360,59 +359,6 @@ function instantiateReduxStore( key, options, registry, thunkArgs ) {
360
359
  );
361
360
  }
362
361
 
363
- /**
364
- * Maps selectors to a store.
365
- *
366
- * @param {Object} selectors Selectors to register. Keys will be used as the
367
- * public facing API. Selectors will get passed the
368
- * state as first argument.
369
- * @param {Object} store The store to which the selectors should be mapped.
370
- * @return {Object} Selectors mapped to the provided store.
371
- */
372
- function mapSelectors( selectors, store ) {
373
- const createStateSelector = ( registrySelector ) => {
374
- const selector = function runSelector() {
375
- // This function is an optimized implementation of:
376
- //
377
- // selector( store.getState(), ...arguments )
378
- //
379
- // Where the above would incur an `Array#concat` in its application,
380
- // the logic here instead efficiently constructs an arguments array via
381
- // direct assignment.
382
- const argsLength = arguments.length;
383
- const args = new Array( argsLength + 1 );
384
- args[ 0 ] = store.__unstableOriginalGetState();
385
- for ( let i = 0; i < argsLength; i++ ) {
386
- args[ i + 1 ] = arguments[ i ];
387
- }
388
-
389
- return registrySelector( ...args );
390
- };
391
- selector.hasResolver = false;
392
- return selector;
393
- };
394
-
395
- return mapValues( selectors, createStateSelector );
396
- }
397
-
398
- /**
399
- * Maps actions to dispatch from a given store.
400
- *
401
- * @param {Object} actions Actions to register.
402
- * @param {Object} store The redux store to which the actions should be mapped.
403
- *
404
- * @return {Object} Actions mapped to the redux store provided.
405
- */
406
- function mapActions( actions, store ) {
407
- const createBoundAction =
408
- ( action ) =>
409
- ( ...args ) => {
410
- return Promise.resolve( store.dispatch( action( ...args ) ) );
411
- };
412
-
413
- return mapValues( actions, createBoundAction );
414
- }
415
-
416
362
  /**
417
363
  * Maps selectors to functions that return a resolution promise for them
418
364
  *
@@ -519,20 +465,13 @@ function mapSuspendSelectors( selectors, store ) {
519
465
  }
520
466
 
521
467
  /**
522
- * Returns resolvers with matched selectors for a given namespace.
523
- * Resolvers are side effects invoked once per argument set of a given selector call,
524
- * used in ensuring that the data needs for the selector are satisfied.
468
+ * Convert resolvers to a normalized form, an object with `fulfill` method and
469
+ * optional methods like `isFulfilled`.
525
470
  *
526
- * @param {Object} resolvers Resolvers to register.
527
- * @param {Object} selectors The current selectors to be modified.
528
- * @param {Object} store The redux store to which the resolvers should be mapped.
529
- * @param {Object} resolversCache Resolvers Cache.
471
+ * @param {Object} resolvers Resolver to convert
530
472
  */
531
- function mapResolvers( resolvers, selectors, store, resolversCache ) {
532
- // The `resolver` can be either a function that does the resolution, or, in more advanced
533
- // cases, an object with a `fullfill` method and other optional methods like `isFulfilled`.
534
- // Here we normalize the `resolver` function to an object with `fulfill` method.
535
- const mappedResolvers = mapValues( resolvers, ( resolver ) => {
473
+ function mapResolvers( resolvers ) {
474
+ return mapValues( resolvers, ( resolver ) => {
536
475
  if ( resolver.fulfill ) {
537
476
  return resolver;
538
477
  }
@@ -542,99 +481,81 @@ function mapResolvers( resolvers, selectors, store, resolversCache ) {
542
481
  fulfill: resolver, // Add the fulfill method.
543
482
  };
544
483
  } );
484
+ }
545
485
 
546
- const mapSelector = ( selector, selectorName ) => {
547
- const resolver = resolvers[ selectorName ];
548
- if ( ! resolver ) {
549
- selector.hasResolver = false;
550
- return selector;
486
+ /**
487
+ * Returns resolvers with matched selectors for a given namespace.
488
+ * Resolvers are side effects invoked once per argument set of a given selector call,
489
+ * used in ensuring that the data needs for the selector are satisfied.
490
+ *
491
+ * @param {Object} selectors The current selectors to be modified.
492
+ * @param {Object} resolvers Resolvers to register.
493
+ * @param {Object} store The redux store to which the resolvers should be mapped.
494
+ * @param {Object} resolversCache Resolvers Cache.
495
+ */
496
+ function mapSelectorsWithResolvers(
497
+ selectors,
498
+ resolvers,
499
+ store,
500
+ resolversCache
501
+ ) {
502
+ function fulfillSelector( resolver, selectorName, args ) {
503
+ const state = store.getState();
504
+
505
+ if (
506
+ resolversCache.isRunning( selectorName, args ) ||
507
+ ( typeof resolver.isFulfilled === 'function' &&
508
+ resolver.isFulfilled( state, ...args ) )
509
+ ) {
510
+ return;
551
511
  }
552
512
 
553
- const selectorResolver = ( ...args ) => {
554
- async function fulfillSelector() {
555
- const state = store.getState();
556
-
557
- if (
558
- resolversCache.isRunning( selectorName, args ) ||
559
- ( typeof resolver.isFulfilled === 'function' &&
560
- resolver.isFulfilled( state, ...args ) )
561
- ) {
562
- return;
563
- }
564
-
565
- const { metadata } = store.__unstableOriginalGetState();
513
+ const { metadata } = store.__unstableOriginalGetState();
566
514
 
567
- if (
568
- metadataSelectors.hasStartedResolution(
569
- metadata,
570
- selectorName,
571
- args
572
- )
573
- ) {
574
- return;
575
- }
515
+ if (
516
+ metadataSelectors.hasStartedResolution(
517
+ metadata,
518
+ selectorName,
519
+ args
520
+ )
521
+ ) {
522
+ return;
523
+ }
576
524
 
577
- resolversCache.markAsRunning( selectorName, args );
525
+ resolversCache.markAsRunning( selectorName, args );
578
526
 
579
- setTimeout( async () => {
580
- resolversCache.clear( selectorName, args );
581
- store.dispatch(
582
- metadataActions.startResolution( selectorName, args )
583
- );
584
- try {
585
- await fulfillResolver(
586
- store,
587
- mappedResolvers,
588
- selectorName,
589
- ...args
590
- );
591
- store.dispatch(
592
- metadataActions.finishResolution(
593
- selectorName,
594
- args
595
- )
596
- );
597
- } catch ( error ) {
598
- store.dispatch(
599
- metadataActions.failResolution(
600
- selectorName,
601
- args,
602
- error
603
- )
604
- );
605
- }
606
- } );
527
+ setTimeout( async () => {
528
+ resolversCache.clear( selectorName, args );
529
+ store.dispatch(
530
+ metadataActions.startResolution( selectorName, args )
531
+ );
532
+ try {
533
+ const action = resolver.fulfill( ...args );
534
+ if ( action ) {
535
+ await store.dispatch( action );
536
+ }
537
+ store.dispatch(
538
+ metadataActions.finishResolution( selectorName, args )
539
+ );
540
+ } catch ( error ) {
541
+ store.dispatch(
542
+ metadataActions.failResolution( selectorName, args, error )
543
+ );
607
544
  }
545
+ }, 0 );
546
+ }
547
+
548
+ return mapValues( selectors, ( selector, selectorName ) => {
549
+ const resolver = resolvers[ selectorName ];
550
+ if ( ! resolver ) {
551
+ return selector;
552
+ }
608
553
 
609
- fulfillSelector( ...args );
554
+ const selectorResolver = ( ...args ) => {
555
+ fulfillSelector( resolver, selectorName, args );
610
556
  return selector( ...args );
611
557
  };
612
558
  selectorResolver.hasResolver = true;
613
559
  return selectorResolver;
614
- };
615
-
616
- return {
617
- resolvers: mappedResolvers,
618
- selectors: mapValues( selectors, mapSelector ),
619
- };
620
- }
621
-
622
- /**
623
- * Calls a resolver given arguments
624
- *
625
- * @param {Object} store Store reference, for fulfilling via resolvers
626
- * @param {Object} resolvers Store Resolvers
627
- * @param {string} selectorName Selector name to fulfill.
628
- * @param {Array} args Selector Arguments.
629
- */
630
- async function fulfillResolver( store, resolvers, selectorName, ...args ) {
631
- const resolver = resolvers[ selectorName ];
632
- if ( ! resolver ) {
633
- return;
634
- }
635
-
636
- const action = resolver.fulfill( ...args );
637
- if ( action ) {
638
- await store.dispatch( action );
639
- }
560
+ } );
640
561
  }
@@ -96,6 +96,37 @@ describe( 'Private data APIs', () => {
96
96
  );
97
97
  } );
98
98
 
99
+ it( 'should support combination of private selectors and resolvers', async () => {
100
+ const testStore = createReduxStore( 'test', {
101
+ reducer: ( state = {}, action ) => {
102
+ if ( action.type === 'RECEIVE' ) {
103
+ return { ...state, [ action.key ]: action.value };
104
+ }
105
+ return state;
106
+ },
107
+ selectors: {
108
+ get: ( state, key ) => state[ key ],
109
+ },
110
+ resolvers: {
111
+ get:
112
+ ( key ) =>
113
+ async ( { dispatch } ) => {
114
+ const value = await ( 'resolved-' + key );
115
+ dispatch( { type: 'RECEIVE', key, value } );
116
+ },
117
+ },
118
+ } );
119
+ unlock( testStore ).registerPrivateSelectors( {
120
+ peek: ( state, key ) => state[ key ],
121
+ } );
122
+ registry.register( testStore );
123
+
124
+ await registry.resolveSelect( testStore ).get( 'x' );
125
+ expect( unlock( registry.select( testStore ) ).peek( 'x' ) ).toBe(
126
+ 'resolved-x'
127
+ );
128
+ } );
129
+
99
130
  it( 'should give private selectors access to the state', () => {
100
131
  const groceryStore = createStore();
101
132
  unlock( groceryStore ).registerPrivateSelectors( {