From 1a929eb4074597034ecd1d2ee0885595b9981378 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Wed, 31 Jul 2019 16:27:31 -0400 Subject: [PATCH] Data: Create registry selector with self-contained registry proxying (#16692) * Data: Create registry selector with self-contained registry proxying * Editor: Fix tests that relied on registry selectors being higher order. * Data: Add typedef import reference for WPDataRegistry * Data: Omit removed registry argument from mapSelectors --- packages/data/src/factory.js | 29 +++++++++++++++++-- packages/data/src/namespace-store/index.js | 26 ++++++----------- packages/data/src/test/registry.js | 32 +++++++++++++++++++++ packages/editor/src/store/test/selectors.js | 7 ++++- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/packages/data/src/factory.js b/packages/data/src/factory.js index f7dbb7f269a86..26fceb9bd456d 100644 --- a/packages/data/src/factory.js +++ b/packages/data/src/factory.js @@ -1,3 +1,12 @@ +/** + * Internal dependencies + */ +import defaultRegistry from './default-registry'; + +/** + * @typedef {import('./registry').WPDataRegistry} WPDataRegistry + */ + /** * Mark a selector as a registry selector. * @@ -6,9 +15,25 @@ * @return {function} marked registry selector. */ export function createRegistrySelector( registrySelector ) { - registrySelector.isRegistrySelector = true; + const selector = ( ...args ) => registrySelector( selector.registry.select )( ...args ); + + /** + * Flag indicating to selector registration mapping that the selector should + * be mapped as a registry selector. + * + * @type {boolean} + */ + selector.isRegistrySelector = true; + + /** + * Registry on which to call `select`, stubbed for non-standard usage to + * use the default registry. + * + * @type {WPDataRegistry} + */ + selector.registry = defaultRegistry; - return registrySelector; + return selector; } /** diff --git a/packages/data/src/namespace-store/index.js b/packages/data/src/namespace-store/index.js index 8d2b009cc4d7d..b3bd639fcddfa 100644 --- a/packages/data/src/namespace-store/index.js +++ b/packages/data/src/namespace-store/index.js @@ -51,16 +51,12 @@ export default function createNamespace( key, options, registry ) { ...mapValues( metadataSelectors, ( selector ) => ( state, ...args ) => selector( state.metadata, ...args ) ), ...mapValues( options.selectors, ( selector ) => { if ( selector.isRegistrySelector ) { - const mappedSelector = ( reg ) => ( state, ...args ) => { - return selector( reg )( state.root, ...args ); - }; - mappedSelector.isRegistrySelector = selector.isRegistrySelector; - return mappedSelector; + selector.registry = registry; } return ( state, ...args ) => selector( state.root, ...args ); } ), - }, store, registry ); + }, store ); if ( options.resolvers ) { const result = mapResolvers( options.resolvers, selectors, store ); resolvers = result.resolvers; @@ -152,21 +148,15 @@ function createReduxStore( key, options, registry ) { /** * Maps selectors to a store. * - * @param {Object} selectors Selectors to register. Keys will be used as - * the public facing API. Selectors will get - * passed the state as first argument. - * @param {Object} store The store to which the selectors should be - * mapped. - * @param {WPDataRegistry} registry Registry reference. + * @param {Object} selectors Selectors to register. Keys will be used as the + * public facing API. Selectors will get passed the + * state as first argument. + * @param {Object} store The store to which the selectors should be mapped. * * @return {Object} Selectors mapped to the provided store. */ -function mapSelectors( selectors, store, registry ) { - const createStateSelector = ( registeredSelector ) => { - const registrySelector = registeredSelector.isRegistrySelector ? - registeredSelector( registry.select ) : - registeredSelector; - +function mapSelectors( selectors, store ) { + const createStateSelector = ( registrySelector ) => { const selector = function runSelector() { // This function is an optimized implementation of: // diff --git a/packages/data/src/test/registry.js b/packages/data/src/test/registry.js index 57b8789e7095c..23a6d399ce778 100644 --- a/packages/data/src/test/registry.js +++ b/packages/data/src/test/registry.js @@ -464,6 +464,38 @@ describe( 'createRegistry', () => { expect( registry.select( 'reducer2' ).selector2() ).toEqual( 'result1' ); } ); + + it( 'should run the registry selector from a non-registry selector', () => { + const selector1 = () => 'result1'; + const selector2 = createRegistrySelector( ( select ) => () => + select( 'reducer1' ).selector1() + ); + const selector3 = () => selector2(); + registry.registerStore( 'reducer1', { + reducer: () => 'state1', + selectors: { + selector1, + }, + } ); + registry.registerStore( 'reducer2', { + reducer: () => 'state1', + selectors: { + selector2, + selector3, + }, + } ); + + expect( registry.select( 'reducer2' ).selector3() ).toEqual( 'result1' ); + } ); + + it( 'gracefully stubs select on selector calls', () => { + const selector = createRegistrySelector( ( select ) => () => select ); + + const maybeSelect = selector(); + + expect( maybeSelect ).toEqual( expect.any( Function ) ); + expect( maybeSelect() ).toEqual( expect.any( Object ) ); + } ); } ); describe( 'subscribe', () => { diff --git a/packages/editor/src/store/test/selectors.js b/packages/editor/src/store/test/selectors.js index f2e30f17372e1..6d10b7f863aea 100644 --- a/packages/editor/src/store/test/selectors.js +++ b/packages/editor/src/store/test/selectors.js @@ -44,7 +44,7 @@ const { isCurrentPostScheduled, isEditedPostPublishable, isEditedPostSaveable, - isEditedPostAutosaveable: isEditedPostAutosaveableRegistrySelector, + isEditedPostAutosaveable: _isEditedPostAutosaveableRegistrySelector, isEditedPostEmpty, isEditedPostBeingScheduled, isEditedPostDateFloating, @@ -71,9 +71,14 @@ const { describe( 'selectors', () => { let cachedSelectors; + let isEditedPostAutosaveableRegistrySelector; beforeAll( () => { cachedSelectors = filter( selectors, ( selector ) => selector.clear ); + isEditedPostAutosaveableRegistrySelector = ( select ) => { + _isEditedPostAutosaveableRegistrySelector.registry = { select }; + return _isEditedPostAutosaveableRegistrySelector; + }; } ); beforeEach( () => {