UNPKG

13.6 kBJavaScriptView Raw
1import * as Redux from 'redux';
2
3function _extends() {
4 _extends = Object.assign || function (target) {
5 for (var i = 1; i < arguments.length; i++) {
6 var source = arguments[i];
7
8 for (var key in source) {
9 if (Object.prototype.hasOwnProperty.call(source, key)) {
10 target[key] = source[key];
11 }
12 }
13 }
14
15 return target;
16 };
17
18 return _extends.apply(this, arguments);
19}
20
21function createReduxStore(bag) {
22 var _bag$reduxConfig;
23
24 bag.models.forEach(function (model) {
25 return createModelReducer(bag, model);
26 });
27 var rootReducer = createRootReducer(bag);
28 var middlewares = Redux.applyMiddleware.apply(Redux, bag.reduxConfig.middlewares);
29 var enhancers = bag.reduxConfig.devtoolComposer ? (_bag$reduxConfig = bag.reduxConfig).devtoolComposer.apply(_bag$reduxConfig, bag.reduxConfig.enhancers.concat([middlewares])) : composeEnhancersWithDevtools(bag.reduxConfig.devtoolOptions).apply(void 0, bag.reduxConfig.enhancers.concat([middlewares]));
30 var createStore = bag.reduxConfig.createStore || Redux.createStore;
31 var bagInitialState = bag.reduxConfig.initialState;
32 var initialState = bagInitialState === undefined ? {} : bagInitialState;
33 return createStore(rootReducer, initialState, enhancers);
34}
35function createModelReducer(bag, model) {
36 var modelReducers = {};
37 var modelReducerKeys = Object.keys(model.reducers);
38 modelReducerKeys.forEach(function (reducerKey) {
39 var actionName = isAlreadyActionName(reducerKey) ? reducerKey : model.name + "/" + reducerKey;
40 modelReducers[actionName] = model.reducers[reducerKey];
41 });
42
43 var combinedReducer = function combinedReducer(state, action) {
44 if (state === void 0) {
45 state = model.state;
46 }
47
48 if (action.type in modelReducers) {
49 return modelReducers[action.type](state, action.payload, action.meta);
50 }
51
52 return state;
53 };
54
55 var modelBaseReducer = model.baseReducer;
56 var reducer = !modelBaseReducer ? combinedReducer : function (state, action) {
57 if (state === void 0) {
58 state = model.state;
59 }
60
61 return combinedReducer(modelBaseReducer(state, action), action);
62 };
63 bag.forEachPlugin('onReducer', function (onReducer) {
64 reducer = onReducer(reducer, model.name, bag) || reducer;
65 });
66 bag.reduxConfig.reducers[model.name] = reducer;
67}
68function createRootReducer(bag) {
69 var rootReducers = bag.reduxConfig.rootReducers;
70 var mergedReducers = mergeReducers(bag.reduxConfig);
71 var rootReducer = mergedReducers;
72
73 if (rootReducers && Object.keys(rootReducers).length) {
74 rootReducer = function rootReducer(state, action) {
75 var actionRootReducer = rootReducers[action.type];
76
77 if (actionRootReducer) {
78 return mergedReducers(actionRootReducer(state, action), action);
79 }
80
81 return mergedReducers(state, action);
82 };
83 }
84
85 bag.forEachPlugin('onRootReducer', function (onRootReducer) {
86 rootReducer = onRootReducer(rootReducer, bag) || rootReducer;
87 });
88 return rootReducer;
89}
90
91function mergeReducers(reduxConfig) {
92 var combineReducers = reduxConfig.combineReducers || Redux.combineReducers;
93
94 if (!Object.keys(reduxConfig.reducers).length) {
95 return function (state) {
96 return state;
97 };
98 }
99
100 return combineReducers(reduxConfig.reducers);
101}
102
103function composeEnhancersWithDevtools(devtoolOptions) {
104 if (devtoolOptions === void 0) {
105 devtoolOptions = {};
106 }
107
108 return !devtoolOptions.disabled && typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__(devtoolOptions) : Redux.compose;
109}
110
111function isAlreadyActionName(reducerKey) {
112 return reducerKey.indexOf('/') > -1;
113}
114
115var isObject = function isObject(obj) {
116 return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
117};
118var ifDefinedIsFunction = function ifDefinedIsFunction(func) {
119 return !func || typeof func === 'function';
120};
121
122var validate = function validate(runValidations) {
123 if (process.env.NODE_ENV !== 'production') {
124 var validations = runValidations();
125 var errors = [];
126 validations.forEach(function (validation) {
127 var isInvalid = validation[0];
128 var errorMessage = validation[1];
129
130 if (isInvalid) {
131 errors.push(errorMessage);
132 }
133 });
134
135 if (errors.length > 0) {
136 throw new Error(errors.join(', '));
137 }
138 }
139};
140
141var validateConfig = function validateConfig(config) {
142 validate(function () {
143 return [[!Array.isArray(config.plugins), 'init config.plugins must be an array'], [!isObject(config.models), 'init config.models must be an object'], [!isObject(config.redux.reducers), 'init config.redux.reducers must be an object'], [!Array.isArray(config.redux.middlewares), 'init config.redux.middlewares must be an array'], [!Array.isArray(config.redux.enhancers), 'init config.redux.enhancers must be an array of functions'], [!ifDefinedIsFunction(config.redux.combineReducers), 'init config.redux.combineReducers must be a function'], [!ifDefinedIsFunction(config.redux.createStore), 'init config.redux.createStore must be a function']];
144 });
145};
146var validateModel = function validateModel(model) {
147 validate(function () {
148 return [[!model, 'model config is required'], [typeof model.name !== 'string', 'model "name" [string] is required'], [model.state === undefined && model.baseReducer === undefined, 'model "state" is required'], [!ifDefinedIsFunction(model.baseReducer), 'model "baseReducer" must be a function']];
149 });
150};
151var validatePlugin = function validatePlugin(plugin) {
152 validate(function () {
153 return [[!ifDefinedIsFunction(plugin.onStoreCreated), 'Plugin onStoreCreated must be a function'], [!ifDefinedIsFunction(plugin.onModel), 'Plugin onModel must be a function'], [!ifDefinedIsFunction(plugin.onReducer), 'Plugin onReducer must be a function'], [!ifDefinedIsFunction(plugin.onRootReducer), 'Plugin onRootReducer must be a function'], [!ifDefinedIsFunction(plugin.createMiddleware), 'Plugin createMiddleware must be a function']];
154 });
155};
156var validateModelReducer = function validateModelReducer(modelName, reducers, reducerName) {
157 validate(function () {
158 return [[!!reducerName.match(/\/.+\//), "Invalid reducer name (" + modelName + "/" + reducerName + ")"], [typeof reducers[reducerName] !== 'function', "Invalid reducer (" + modelName + "/" + reducerName + "). Must be a function"]];
159 });
160};
161var validateModelEffect = function validateModelEffect(modelName, effects, effectName) {
162 validate(function () {
163 return [[!!effectName.match(/\//), "Invalid effect name (" + modelName + "/" + effectName + ")"], [typeof effects[effectName] !== 'function', "Invalid effect (" + modelName + "/" + effectName + "). Must be a function"]];
164 });
165};
166
167var createActionDispatcher = function createActionDispatcher(rematch, modelName, actionName, isEffect) {
168 return Object.assign(function (payload, meta) {
169 var action = {
170 type: modelName + "/" + actionName
171 };
172
173 if (typeof payload !== 'undefined') {
174 action.payload = payload;
175 }
176
177 if (typeof meta !== 'undefined') {
178 action.meta = meta;
179 }
180
181 return rematch.dispatch(action);
182 }, {
183 isEffect: isEffect
184 });
185};
186
187var createReducerDispatcher = function createReducerDispatcher(rematch, model) {
188 var modelDispatcher = rematch.dispatch[model.name];
189 var modelReducersKeys = Object.keys(model.reducers);
190 modelReducersKeys.forEach(function (reducerName) {
191 validateModelReducer(model.name, model.reducers, reducerName);
192 modelDispatcher[reducerName] = createActionDispatcher(rematch, model.name, reducerName, false);
193 });
194};
195var createEffectDispatcher = function createEffectDispatcher(rematch, bag, model) {
196 var modelDispatcher = rematch.dispatch[model.name];
197 var effects = {};
198
199 if (model.effects) {
200 effects = typeof model.effects === 'function' ? model.effects(rematch.dispatch) : model.effects;
201 }
202
203 var effectKeys = Object.keys(effects);
204 effectKeys.forEach(function (effectName) {
205 validateModelEffect(model.name, effects, effectName);
206 bag.effects[model.name + "/" + effectName] = effects[effectName].bind(modelDispatcher);
207 modelDispatcher[effectName] = createActionDispatcher(rematch, model.name, effectName, true);
208 });
209};
210
211function createRematchBag(config) {
212 return {
213 models: createNamedModels(config.models),
214 reduxConfig: config.redux,
215 forEachPlugin: function forEachPlugin(method, fn) {
216 config.plugins.forEach(function (plugin) {
217 if (plugin[method]) {
218 fn(plugin[method]);
219 }
220 });
221 },
222 effects: {}
223 };
224}
225
226function createNamedModels(models) {
227 return Object.keys(models).map(function (modelName) {
228 var model = createNamedModel(modelName, models[modelName]);
229 validateModel(model);
230 return model;
231 });
232}
233
234function createNamedModel(name, model) {
235 return _extends({
236 name: name,
237 reducers: {}
238 }, model);
239}
240
241function createRematchStore(config) {
242 var bag = createRematchBag(config);
243 bag.reduxConfig.middlewares.push(createEffectsMiddleware(bag));
244 bag.forEachPlugin('createMiddleware', function (createMiddleware) {
245 bag.reduxConfig.middlewares.push(createMiddleware(bag));
246 });
247 var reduxStore = createReduxStore(bag);
248
249 var rematchStore = _extends({}, reduxStore, {
250 name: config.name,
251 addModel: function addModel(model) {
252 validateModel(model);
253 createModelReducer(bag, model);
254 prepareModel(rematchStore, model);
255 enhanceModel(rematchStore, bag, model);
256 reduxStore.replaceReducer(createRootReducer(bag));
257 reduxStore.dispatch({
258 type: '@@redux/REPLACE'
259 });
260 }
261 });
262
263 addExposed(rematchStore, config.plugins);
264 bag.models.forEach(function (model) {
265 return prepareModel(rematchStore, model);
266 });
267 bag.models.forEach(function (model) {
268 return enhanceModel(rematchStore, bag, model);
269 });
270 bag.forEachPlugin('onStoreCreated', function (onStoreCreated) {
271 rematchStore = onStoreCreated(rematchStore, bag) || rematchStore;
272 });
273 return rematchStore;
274}
275
276function createEffectsMiddleware(bag) {
277 return function (store) {
278 return function (next) {
279 return function (action) {
280 if (action.type in bag.effects) {
281 next(action);
282 return bag.effects[action.type](action.payload, store.getState(), action.meta);
283 }
284
285 return next(action);
286 };
287 };
288 };
289}
290
291function prepareModel(rematchStore, model) {
292 var modelDispatcher = {};
293 rematchStore.dispatch["" + model.name] = modelDispatcher;
294 createReducerDispatcher(rematchStore, model);
295}
296
297function enhanceModel(rematchStore, bag, model) {
298 createEffectDispatcher(rematchStore, bag, model);
299 bag.forEachPlugin('onModel', function (onModel) {
300 onModel(model, rematchStore);
301 });
302}
303
304function addExposed(store, plugins) {
305 plugins.forEach(function (plugin) {
306 if (!plugin.exposed) return;
307 var pluginKeys = Object.keys(plugin.exposed);
308 pluginKeys.forEach(function (key) {
309 if (!plugin.exposed) return;
310 var exposedItem = plugin.exposed[key];
311 var isExposedFunction = typeof exposedItem === 'function';
312 store[key] = isExposedFunction ? function () {
313 for (var _len = arguments.length, params = new Array(_len), _key = 0; _key < _len; _key++) {
314 params[_key] = arguments[_key];
315 }
316
317 return exposedItem.apply(void 0, [store].concat(params));
318 } : Object.create(plugin.exposed[key]);
319 });
320 });
321}
322
323var count = 0;
324function createConfig(initConfig) {
325 var _initConfig$name, _initConfig$redux$dev, _initConfig$redux;
326
327 var storeName = (_initConfig$name = initConfig.name) != null ? _initConfig$name : "Rematch Store " + count;
328 count += 1;
329 var config = {
330 name: storeName,
331 models: initConfig.models || {},
332 plugins: initConfig.plugins || [],
333 redux: _extends({
334 reducers: {},
335 rootReducers: {},
336 enhancers: [],
337 middlewares: []
338 }, initConfig.redux, {
339 devtoolOptions: _extends({
340 name: storeName
341 }, (_initConfig$redux$dev = (_initConfig$redux = initConfig.redux) == null ? void 0 : _initConfig$redux.devtoolOptions) != null ? _initConfig$redux$dev : {})
342 })
343 };
344 validateConfig(config);
345 config.plugins.forEach(function (plugin) {
346 if (plugin.config) {
347 config.models = merge(config.models, plugin.config.models);
348
349 if (plugin.config.redux) {
350 config.redux.initialState = merge(config.redux.initialState, plugin.config.redux.initialState);
351 config.redux.reducers = merge(config.redux.reducers, plugin.config.redux.reducers);
352 config.redux.rootReducers = merge(config.redux.rootReducers, plugin.config.redux.reducers);
353 config.redux.enhancers = [].concat(config.redux.enhancers, plugin.config.redux.enhancers || []);
354 config.redux.middlewares = [].concat(config.redux.middlewares, plugin.config.redux.middlewares || []);
355 config.redux.combineReducers = config.redux.combineReducers || plugin.config.redux.combineReducers;
356 config.redux.createStore = config.redux.createStore || plugin.config.redux.createStore;
357 }
358 }
359
360 validatePlugin(plugin);
361 });
362 return config;
363}
364
365function merge(original, extra) {
366 return extra ? _extends({}, extra, original) : original;
367}
368
369var init = function init(initConfig) {
370 var config = createConfig(initConfig || {});
371 return createRematchStore(config);
372};
373var createModel = function createModel() {
374 return function (mo) {
375 return mo;
376 };
377};
378var index = {
379 init: init,
380 createModel: createModel
381};
382
383export { createModel, index as default, init };
384//# sourceMappingURL=core.esm.js.map