@@ -7,12 +7,21 @@ import {
7
7
get ,
8
8
mapValues ,
9
9
} from 'lodash' ;
10
+ import combineReducers from 'turbo-combine-reducers' ;
11
+
12
+ /**
13
+ * WordPress dependencies
14
+ */
15
+ import createReduxRoutineMiddleware from '@wordpress/redux-routine' ;
10
16
11
17
/**
12
18
* Internal dependencies
13
19
*/
14
- import promise from './promise-middleware' ;
15
- import createResolversCacheMiddleware from './resolvers-cache-middleware' ;
20
+ import promise from '../promise-middleware' ;
21
+ import createResolversCacheMiddleware from '../resolvers-cache-middleware' ;
22
+ import metadataReducer from './metadata/reducer' ;
23
+ import * as metadataSelectors from './metadata/selectors' ;
24
+ import * as metadataActions from './metadata/actions' ;
16
25
17
26
/**
18
27
* Creates a namespace object with a store derived from the reducer given.
@@ -27,29 +36,46 @@ export default function createNamespace( key, options, registry ) {
27
36
const reducer = options . reducer ;
28
37
const store = createReduxStore ( key , options , registry ) ;
29
38
30
- let selectors , actions , resolvers ;
31
- if ( options . actions ) {
32
- actions = mapActions ( options . actions , store ) ;
33
- }
34
- if ( options . selectors ) {
35
- selectors = mapSelectors ( options . selectors , store , registry ) ;
36
- }
39
+ let resolvers ;
40
+ const actions = mapActions ( {
41
+ ...metadataActions ,
42
+ ...options . actions ,
43
+ } , store ) ;
44
+ let selectors = mapSelectors ( {
45
+ ...mapValues ( metadataSelectors , ( selector ) => ( state , ...args ) => selector ( state . metadata , ...args ) ) ,
46
+ ...mapValues ( options . selectors , ( selector ) => {
47
+ if ( selector . isRegistrySelector ) {
48
+ const mappedSelector = ( reg ) => ( state , ...args ) => {
49
+ return selector ( reg ) ( state . root , ...args ) ;
50
+ } ;
51
+ mappedSelector . isRegistrySelector = selector . isRegistrySelector ;
52
+ return mappedSelector ;
53
+ }
54
+
55
+ return ( state , ...args ) => selector ( state . root , ...args ) ;
56
+ } ) ,
57
+ } , store , registry ) ;
37
58
if ( options . resolvers ) {
38
- const fulfillment = getCoreDataFulfillment ( registry , key ) ;
39
- const result = mapResolvers ( options . resolvers , selectors , fulfillment , store ) ;
59
+ const result = mapResolvers ( options . resolvers , selectors , store ) ;
40
60
resolvers = result . resolvers ;
41
61
selectors = result . selectors ;
42
62
}
43
63
44
64
const getSelectors = ( ) => selectors ;
45
65
const getActions = ( ) => actions ;
46
66
67
+ // We have some modules monkey-patching the store object
68
+ // It's wrong to do so but until we refactor all of our effects to controls
69
+ // We need to keep the same "store" instance here.
70
+ store . __unstableOriginalGetState = store . getState ;
71
+ store . getState = ( ) => store . __unstableOriginalGetState ( ) . root ;
72
+
47
73
// Customize subscribe behavior to call listeners only on effective change,
48
74
// not on every dispatch.
49
75
const subscribe = store && function ( listener ) {
50
- let lastState = store . getState ( ) ;
76
+ let lastState = store . __unstableOriginalGetState ( ) ;
51
77
store . subscribe ( ( ) => {
52
- const state = store . getState ( ) ;
78
+ const state = store . __unstableOriginalGetState ( ) ;
53
79
const hasChanged = state !== lastState ;
54
80
lastState = state ;
55
81
@@ -84,15 +110,36 @@ export default function createNamespace( key, options, registry ) {
84
110
* @return {Object } Newly created redux store.
85
111
*/
86
112
function createReduxStore ( key , options , registry ) {
113
+ const middlewares = [
114
+ createResolversCacheMiddleware ( registry , key ) ,
115
+ promise ,
116
+ ] ;
117
+
118
+ if ( options . controls ) {
119
+ const normalizedControls = mapValues ( options . controls , ( control ) => {
120
+ return control . isRegistryControl ? control ( registry ) : control ;
121
+ } ) ;
122
+ middlewares . push ( createReduxRoutineMiddleware ( normalizedControls ) ) ;
123
+ }
124
+
87
125
const enhancers = [
88
- applyMiddleware ( createResolversCacheMiddleware ( registry , key ) , promise ) ,
126
+ applyMiddleware ( ... middlewares ) ,
89
127
] ;
90
128
if ( typeof window !== 'undefined' && window . __REDUX_DEVTOOLS_EXTENSION__ ) {
91
129
enhancers . push ( window . __REDUX_DEVTOOLS_EXTENSION__ ( { name : key , instanceId : key } ) ) ;
92
130
}
93
131
94
132
const { reducer, initialState } = options ;
95
- return createStore ( reducer , initialState , flowRight ( enhancers ) ) ;
133
+ const enhancedReducer = combineReducers ( {
134
+ metadata : metadataReducer ,
135
+ root : reducer ,
136
+ } ) ;
137
+
138
+ return createStore (
139
+ enhancedReducer ,
140
+ { root : initialState } ,
141
+ flowRight ( enhancers )
142
+ ) ;
96
143
}
97
144
98
145
/**
@@ -120,7 +167,7 @@ function mapSelectors( selectors, store, registry ) {
120
167
// direct assignment.
121
168
const argsLength = arguments . length ;
122
169
const args = new Array ( argsLength + 1 ) ;
123
- args [ 0 ] = store . getState ( ) ;
170
+ args [ 0 ] = store . __unstableOriginalGetState ( ) ;
124
171
for ( let i = 0 ; i < argsLength ; i ++ ) {
125
172
args [ i + 1 ] = arguments [ i ] ;
126
173
}
@@ -151,11 +198,15 @@ function mapActions( actions, store ) {
151
198
*
152
199
* @param {Object } resolvers Resolvers to register.
153
200
* @param {Object } selectors The current selectors to be modified.
154
- * @param {Object } fulfillment Fulfillment implementation functions.
155
201
* @param {Object } store The redux store to which the resolvers should be mapped.
156
202
* @return {Object } An object containing updated selectors and resolvers.
157
203
*/
158
- function mapResolvers ( resolvers , selectors , fulfillment , store ) {
204
+ function mapResolvers ( resolvers , selectors , store ) {
205
+ const mappedResolvers = mapValues ( resolvers , ( resolver ) => {
206
+ const { fulfill : resolverFulfill = resolver } = resolver ;
207
+ return { ...resolver , fulfill : resolverFulfill } ;
208
+ } ) ;
209
+
159
210
const mapSelector = ( selector , selectorName ) => {
160
211
const resolver = resolvers [ selectorName ] ;
161
212
if ( ! resolver ) {
@@ -169,68 +220,43 @@ function mapResolvers( resolvers, selectors, fulfillment, store ) {
169
220
return ;
170
221
}
171
222
172
- if ( fulfillment . hasStarted ( selectorName , args ) ) {
223
+ const { metadata } = store . __unstableOriginalGetState ( ) ;
224
+ if ( metadataSelectors . hasStartedResolution ( metadata , selectorName , args ) ) {
173
225
return ;
174
226
}
175
227
176
- fulfillment . start ( selectorName , args ) ;
177
- await fulfillment . fulfill ( selectorName , ...args ) ;
178
- fulfillment . finish ( selectorName , args ) ;
228
+ store . dispatch ( metadataActions . startResolution ( selectorName , args ) ) ;
229
+ await fulfillResolver ( store , mappedResolvers , selectorName , ...args ) ;
230
+ store . dispatch ( metadataActions . finishResolution ( selectorName , args ) ) ;
179
231
}
180
232
181
233
fulfillSelector ( ...args ) ;
182
234
return selector ( ...args ) ;
183
235
} ;
184
236
} ;
185
237
186
- const mappedResolvers = mapValues ( resolvers , ( resolver ) => {
187
- const { fulfill : resolverFulfill = resolver } = resolver ;
188
- return { ...resolver , fulfill : resolverFulfill } ;
189
- } ) ;
190
-
191
238
return {
192
239
resolvers : mappedResolvers ,
193
240
selectors : mapValues ( selectors , mapSelector ) ,
194
241
} ;
195
242
}
196
243
197
- /**
198
- * Bundles up fulfillment functions for resolvers.
199
- * @param {Object } registry Registry reference, for fulfilling via resolvers
200
- * @param {string } key Part of the state shape to register the
201
- * selectors for.
202
- * @return {Object } An object providing fulfillment functions.
203
- */
204
- function getCoreDataFulfillment ( registry , key ) {
205
- const { hasStartedResolution } = registry . select ( 'core/data' ) ;
206
- const { startResolution, finishResolution } = registry . dispatch ( 'core/data' ) ;
207
-
208
- return {
209
- hasStarted : ( ...args ) => hasStartedResolution ( key , ...args ) ,
210
- start : ( ...args ) => startResolution ( key , ...args ) ,
211
- finish : ( ...args ) => finishResolution ( key , ...args ) ,
212
- fulfill : ( ...args ) => fulfillWithRegistry ( registry , key , ...args ) ,
213
- } ;
214
- }
215
-
216
244
/**
217
245
* Calls a resolver given arguments
218
246
*
219
- * @param {Object } registry Registry reference, for fulfilling via resolvers
220
- * @param {string } key Part of the state shape to register the
221
- * selectors for.
247
+ * @param {Object } store Store reference, for fulfilling via resolvers
248
+ * @param {Object } resolvers Store Resolvers
222
249
* @param {string } selectorName Selector name to fulfill.
223
- * @param {Array } args Selector Arguments.
250
+ * @param {Array } args Selector Arguments.
224
251
*/
225
- async function fulfillWithRegistry ( registry , key , selectorName , ...args ) {
226
- const namespace = registry . stores [ key ] ;
227
- const resolver = get ( namespace , [ 'resolvers' , selectorName ] ) ;
252
+ async function fulfillResolver ( store , resolvers , selectorName , ...args ) {
253
+ const resolver = get ( resolvers , [ selectorName ] ) ;
228
254
if ( ! resolver ) {
229
255
return ;
230
256
}
231
257
232
258
const action = resolver . fulfill ( ...args ) ;
233
259
if ( action ) {
234
- await namespace . store . dispatch ( action ) ;
260
+ await store . dispatch ( action ) ;
235
261
}
236
262
}
0 commit comments