UNPKG

13.8 kBJavaScriptView Raw
1import { combineReducers, applyMiddleware, createStore, compose } from 'redux';
2export * from 'redux';
3import createNextState from 'immer';
4export { default as createNextState } from 'immer';
5export { createSelector } from 'reselect';
6import { composeWithDevTools } from 'redux-devtools-extension';
7import thunkMiddleware from 'redux-thunk';
8import createImmutableStateInvariantMiddleware from 'redux-immutable-state-invariant';
9
10function _extends() {
11 _extends = Object.assign || function (target) {
12 for (var i = 1; i < arguments.length; i++) {
13 var source = arguments[i];
14
15 for (var key in source) {
16 if (Object.prototype.hasOwnProperty.call(source, key)) {
17 target[key] = source[key];
18 }
19 }
20 }
21
22 return target;
23 };
24
25 return _extends.apply(this, arguments);
26}
27
28/**
29 * Returns true if the passed value is "plain" object, i.e. an object whose
30 * protoype is the root `Object.prototype`. This includes objects created
31 * using object literals, but not for instance for class instances.
32 *
33 * @param {any} value The value to inspect.
34 * @returns {boolean} True if the argument appears to be a plain object.
35 */
36function isPlainObject(value) {
37 if (typeof value !== 'object' || value === null) return false;
38 var proto = value;
39
40 while (Object.getPrototypeOf(proto) !== null) {
41 proto = Object.getPrototypeOf(proto);
42 }
43
44 return Object.getPrototypeOf(value) === proto;
45}
46
47/**
48 * Returns true if the passed value is "plain", i.e. a value that is either
49 * directly JSON-serializable (boolean, number, string, array, plain object)
50 * or `undefined`.
51 *
52 * @param val The value to check.
53 *
54 * @public
55 */
56
57function isPlain(val) {
58 return typeof val === 'undefined' || val === null || typeof val === 'string' || typeof val === 'boolean' || typeof val === 'number' || Array.isArray(val) || isPlainObject(val);
59}
60/**
61 * @public
62 */
63
64function findNonSerializableValue(value, path, isSerializable, getEntries) {
65 if (path === void 0) {
66 path = [];
67 }
68
69 if (isSerializable === void 0) {
70 isSerializable = isPlain;
71 }
72
73 var foundNestedSerializable;
74
75 if (!isSerializable(value)) {
76 return {
77 keyPath: path.join('.') || '<root>',
78 value: value
79 };
80 }
81
82 if (typeof value !== 'object' || value === null) {
83 return false;
84 }
85
86 var entries = getEntries != null ? getEntries(value) : Object.entries(value);
87
88 for (var _iterator = entries, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
89 var _ref;
90
91 if (_isArray) {
92 if (_i >= _iterator.length) break;
93 _ref = _iterator[_i++];
94 } else {
95 _i = _iterator.next();
96 if (_i.done) break;
97 _ref = _i.value;
98 }
99
100 var _ref2 = _ref,
101 property = _ref2[0],
102 nestedValue = _ref2[1];
103 var nestedPath = path.concat(property);
104
105 if (!isSerializable(nestedValue)) {
106 return {
107 keyPath: nestedPath.join('.'),
108 value: nestedValue
109 };
110 }
111
112 if (typeof nestedValue === 'object') {
113 foundNestedSerializable = findNonSerializableValue(nestedValue, nestedPath, isSerializable, getEntries);
114
115 if (foundNestedSerializable) {
116 return foundNestedSerializable;
117 }
118 }
119 }
120
121 return false;
122}
123/**
124 * Creates a middleware that, after every state change, checks if the new
125 * state is serializable. If a non-serializable value is found within the
126 * state, an error is printed to the console.
127 *
128 * @param options Middleware options.
129 *
130 * @public
131 */
132
133function createSerializableStateInvariantMiddleware(options) {
134 if (options === void 0) {
135 options = {};
136 }
137
138 var _options = options,
139 _options$isSerializab = _options.isSerializable,
140 isSerializable = _options$isSerializab === void 0 ? isPlain : _options$isSerializab,
141 getEntries = _options.getEntries,
142 _options$ignoredActio = _options.ignoredActions,
143 ignoredActions = _options$ignoredActio === void 0 ? [] : _options$ignoredActio;
144 return function (storeAPI) {
145 return function (next) {
146 return function (action) {
147 if (ignoredActions.length && ignoredActions.indexOf(action.type) !== -1) {
148 return next(action);
149 }
150
151 var foundActionNonSerializableValue = findNonSerializableValue(action, [], isSerializable, getEntries);
152
153 if (foundActionNonSerializableValue) {
154 var keyPath = foundActionNonSerializableValue.keyPath,
155 value = foundActionNonSerializableValue.value;
156 console.error("A non-serializable value was detected in an action, in the path: `" + keyPath + "`. Value:", value, '\nTake a look at the logic that dispatched this action: ', action, '\n(See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)');
157 }
158
159 var result = next(action);
160 var state = storeAPI.getState();
161 var foundStateNonSerializableValue = findNonSerializableValue(state, [], isSerializable, getEntries);
162
163 if (foundStateNonSerializableValue) {
164 var _keyPath = foundStateNonSerializableValue.keyPath,
165 _value = foundStateNonSerializableValue.value;
166 console.error("A non-serializable value was detected in the state, in the path: `" + _keyPath + "`. Value:", _value, "\nTake a look at the reducer(s) handling this action type: " + action.type + ".\n(See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)");
167 }
168
169 return result;
170 };
171 };
172 };
173}
174
175function isBoolean(x) {
176 return typeof x === 'boolean';
177}
178/**
179 * Returns any array containing the default middleware installed by
180 * `configureStore()`. Useful if you want to configure your store with a custom
181 * `middleware` array but still keep the default set.
182 *
183 * @return The default middleware used by `configureStore()`.
184 *
185 * @public
186 */
187
188
189function getDefaultMiddleware(options) {
190 if (options === void 0) {
191 options = {};
192 }
193
194 var _options = options,
195 _options$thunk = _options.thunk,
196 thunk = _options$thunk === void 0 ? true : _options$thunk,
197 _options$immutableChe = _options.immutableCheck,
198 immutableCheck = _options$immutableChe === void 0 ? true : _options$immutableChe,
199 _options$serializable = _options.serializableCheck,
200 serializableCheck = _options$serializable === void 0 ? true : _options$serializable;
201 var middlewareArray = [];
202
203 if (thunk) {
204 if (isBoolean(thunk)) {
205 middlewareArray.push(thunkMiddleware);
206 } else {
207 middlewareArray.push(thunkMiddleware.withExtraArgument(thunk.extraArgument));
208 }
209 }
210
211 if (process.env.NODE_ENV !== 'production') {
212 if (immutableCheck) {
213 /* PROD_START_REMOVE_UMD */
214 var immutableOptions = {};
215
216 if (!isBoolean(immutableCheck)) {
217 immutableOptions = immutableCheck;
218 }
219
220 middlewareArray.unshift(createImmutableStateInvariantMiddleware(immutableOptions));
221 /* PROD_STOP_REMOVE_UMD */
222 }
223
224 if (serializableCheck) {
225 var serializableOptions = {};
226
227 if (!isBoolean(serializableCheck)) {
228 serializableOptions = serializableCheck;
229 }
230
231 middlewareArray.push(createSerializableStateInvariantMiddleware(serializableOptions));
232 }
233 }
234
235 return middlewareArray;
236}
237
238var IS_PRODUCTION = process.env.NODE_ENV === 'production';
239/**
240 * A friendly abstraction over the standard Redux `createStore()` function.
241 *
242 * @param config The store configuration.
243 * @returns A configured Redux store.
244 *
245 * @public
246 */
247
248function configureStore(options) {
249 var _ref = options || {},
250 _ref$reducer = _ref.reducer,
251 reducer = _ref$reducer === void 0 ? undefined : _ref$reducer,
252 _ref$middleware = _ref.middleware,
253 middleware = _ref$middleware === void 0 ? getDefaultMiddleware() : _ref$middleware,
254 _ref$devTools = _ref.devTools,
255 devTools = _ref$devTools === void 0 ? true : _ref$devTools,
256 _ref$preloadedState = _ref.preloadedState,
257 preloadedState = _ref$preloadedState === void 0 ? undefined : _ref$preloadedState,
258 _ref$enhancers = _ref.enhancers,
259 enhancers = _ref$enhancers === void 0 ? undefined : _ref$enhancers;
260
261 var rootReducer;
262
263 if (typeof reducer === 'function') {
264 rootReducer = reducer;
265 } else if (isPlainObject(reducer)) {
266 rootReducer = combineReducers(reducer);
267 } else {
268 throw new Error('"reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers');
269 }
270
271 var middlewareEnhancer = applyMiddleware.apply(void 0, middleware);
272 var finalCompose = compose;
273
274 if (devTools) {
275 finalCompose = composeWithDevTools(_extends({
276 // Enable capture of stack traces for dispatched Redux actions
277 trace: !IS_PRODUCTION
278 }, typeof devTools === 'object' && devTools));
279 }
280
281 var storeEnhancers = [middlewareEnhancer];
282
283 if (Array.isArray(enhancers)) {
284 storeEnhancers = [middlewareEnhancer].concat(enhancers);
285 } else if (typeof enhancers === 'function') {
286 storeEnhancers = enhancers(storeEnhancers);
287 }
288
289 var composedEnhancer = finalCompose.apply(void 0, storeEnhancers);
290 return createStore(rootReducer, preloadedState, composedEnhancer);
291}
292
293function createAction(type, prepareAction) {
294 function actionCreator() {
295 if (prepareAction) {
296 var prepared = prepareAction.apply(void 0, arguments);
297
298 if (!prepared) {
299 throw new Error('prepareAction did not return an object');
300 }
301
302 return _extends({
303 type: type,
304 payload: prepared.payload
305 }, 'meta' in prepared && {
306 meta: prepared.meta
307 }, {}, 'error' in prepared && {
308 error: prepared.error
309 });
310 }
311
312 return {
313 type: type,
314 payload: arguments.length <= 0 ? undefined : arguments[0]
315 };
316 }
317
318 actionCreator.toString = function () {
319 return "" + type;
320 };
321
322 actionCreator.type = type;
323
324 actionCreator.match = function (action) {
325 return action.type === type;
326 };
327
328 return actionCreator;
329}
330/**
331 * Returns the action type of the actions created by the passed
332 * `createAction()`-generated action creator (arbitrary action creators
333 * are not supported).
334 *
335 * @param action The action creator whose action type to get.
336 * @returns The action type used by the action creator.
337 *
338 * @public
339 */
340
341function getType(actionCreator) {
342 return "" + actionCreator;
343}
344
345function executeReducerBuilderCallback(builderCallback) {
346 var actionsMap = {};
347 var builder = {
348 addCase: function addCase(typeOrActionCreator, reducer) {
349 var type = typeof typeOrActionCreator === 'string' ? typeOrActionCreator : typeOrActionCreator.type;
350
351 if (type in actionsMap) {
352 throw new Error('addCase cannot be called with two reducers for the same action type');
353 }
354
355 actionsMap[type] = reducer;
356 return builder;
357 }
358 };
359 builderCallback(builder);
360 return actionsMap;
361}
362
363function createReducer(initialState, mapOrBuilderCallback) {
364 var actionsMap = typeof mapOrBuilderCallback === 'function' ? executeReducerBuilderCallback(mapOrBuilderCallback) : mapOrBuilderCallback;
365 return function (state, action) {
366 if (state === void 0) {
367 state = initialState;
368 }
369
370 // @ts-ignore createNextState() produces an Immutable<Draft<S>> rather
371 // than an Immutable<S>, and TypeScript cannot find out how to reconcile
372 // these two types.
373 return createNextState(state, function (draft) {
374 var caseReducer = actionsMap[action.type];
375 return caseReducer ? caseReducer(draft, action) : undefined;
376 });
377 };
378}
379
380function getType$1(slice, actionKey) {
381 return slice + "/" + actionKey;
382}
383/**
384 * A function that accepts an initial state, an object full of reducer
385 * functions, and a "slice name", and automatically generates
386 * action creators and action types that correspond to the
387 * reducers and state.
388 *
389 * The `reducer` argument is passed to `createReducer()`.
390 *
391 * @public
392 */
393
394
395function createSlice(options) {
396 var name = options.name,
397 initialState = options.initialState;
398
399 if (!name) {
400 throw new Error('`name` is a required option for createSlice');
401 }
402
403 var reducers = options.reducers || {};
404 var extraReducers = typeof options.extraReducers === 'undefined' ? {} : typeof options.extraReducers === 'function' ? executeReducerBuilderCallback(options.extraReducers) : options.extraReducers;
405 var reducerNames = Object.keys(reducers);
406 var sliceCaseReducersByName = {};
407 var sliceCaseReducersByType = {};
408 var actionCreators = {};
409 reducerNames.forEach(function (reducerName) {
410 var maybeReducerWithPrepare = reducers[reducerName];
411 var type = getType$1(name, reducerName);
412 var caseReducer;
413 var prepareCallback;
414
415 if ('reducer' in maybeReducerWithPrepare) {
416 caseReducer = maybeReducerWithPrepare.reducer;
417 prepareCallback = maybeReducerWithPrepare.prepare;
418 } else {
419 caseReducer = maybeReducerWithPrepare;
420 }
421
422 sliceCaseReducersByName[reducerName] = caseReducer;
423 sliceCaseReducersByType[type] = caseReducer;
424 actionCreators[reducerName] = prepareCallback ? createAction(type, prepareCallback) : createAction(type);
425 });
426
427 var finalCaseReducers = _extends({}, extraReducers, {}, sliceCaseReducersByType);
428
429 var reducer = createReducer(initialState, finalCaseReducers);
430 return {
431 name: name,
432 reducer: reducer,
433 actions: actionCreators,
434 caseReducers: sliceCaseReducersByName
435 };
436}
437
438export { configureStore, createAction, createReducer, createSerializableStateInvariantMiddleware, createSlice, findNonSerializableValue, getDefaultMiddleware, getType, isPlain };
439//# sourceMappingURL=redux-toolkit.esm.js.map