2018-01-29 22:20:38 +00:00
|
|
|
// @flow
|
2017-09-01 21:25:48 +00:00
|
|
|
|
2017-04-23 20:17:31 +00:00
|
|
|
import _ from 'lodash';
|
2019-03-21 16:38:29 +00:00
|
|
|
import { connect as reduxConnect } from 'react-redux';
|
2017-04-23 20:17:31 +00:00
|
|
|
|
2016-12-12 00:29:13 +00:00
|
|
|
/**
|
|
|
|
* Sets specific properties of a specific state to specific values and prevents
|
|
|
|
* unnecessary state changes.
|
|
|
|
*
|
|
|
|
* @param {Object} target - The state on which the specified properties are to
|
|
|
|
* be set.
|
|
|
|
* @param {Object} source - The map of properties to values which are to be set
|
|
|
|
* on the specified target.
|
|
|
|
* @returns {Object} The specified target if the values of the specified
|
|
|
|
* properties equal the specified values; otherwise, a new state constructed
|
|
|
|
* from the specified target by setting the specified properties to the
|
|
|
|
* specified values.
|
|
|
|
*/
|
2017-09-01 21:25:48 +00:00
|
|
|
export function assign(target: Object, source: Object) {
|
2016-12-12 00:29:13 +00:00
|
|
|
let t = target;
|
|
|
|
|
|
|
|
for (const property in source) { // eslint-disable-line guard-for-in
|
2017-10-26 14:50:00 +00:00
|
|
|
t = _set(t, property, source[property], t === target);
|
2016-12-12 00:29:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2019-03-21 16:38:29 +00:00
|
|
|
/**
|
|
|
|
* Wrapper function for the react-redux connect function to avoid having to
|
|
|
|
* declare function types for flow, but still let flow warn for other errors.
|
|
|
|
*
|
|
|
|
* @param {Function?} mapStateToProps - Redux mapStateToProps function.
|
|
|
|
* @param {Function?} mapDispatchToProps - Redux mapDispatchToProps function.
|
|
|
|
* @returns {Connector}
|
|
|
|
*/
|
|
|
|
export function connect(
|
|
|
|
mapStateToProps?: Function, mapDispatchToProps?: Function) {
|
|
|
|
return reduxConnect<*, *, *, *, *, *>(mapStateToProps, mapDispatchToProps);
|
|
|
|
}
|
|
|
|
|
2017-04-23 20:17:31 +00:00
|
|
|
/**
|
|
|
|
* Determines whether {@code a} equals {@code b} according to deep comparison
|
|
|
|
* (which makes sense for Redux and its state definition).
|
|
|
|
*
|
|
|
|
* @param {*} a - The value to compare to {@code b}.
|
|
|
|
* @param {*} b - The value to compare to {@code a}.
|
|
|
|
* @returns {boolean} True if {@code a} equals {@code b} (according to deep
|
|
|
|
* comparison); false, otherwise.
|
|
|
|
*/
|
2017-09-01 21:25:48 +00:00
|
|
|
export function equals(a: any, b: any) {
|
2017-04-23 20:17:31 +00:00
|
|
|
return _.isEqual(a, b);
|
|
|
|
}
|
|
|
|
|
2016-12-05 15:14:50 +00:00
|
|
|
/**
|
|
|
|
* Sets a specific property of a specific state to a specific value. Prevents
|
2017-10-01 06:35:19 +00:00
|
|
|
* unnecessary state changes (when the specified {@code value} is equal to the
|
|
|
|
* value of the specified {@code property} of the specified {@code state}).
|
2016-12-05 15:14:50 +00:00
|
|
|
*
|
|
|
|
* @param {Object} state - The (Redux) state from which a new state is to be
|
2017-10-01 06:35:19 +00:00
|
|
|
* constructed by setting the specified {@code property} to the specified
|
|
|
|
* {@code value}.
|
|
|
|
* @param {string} property - The property of {@code state} which is to be
|
|
|
|
* assigned the specified {@code value} (in the new state).
|
|
|
|
* @param {*} value - The value to assign to the specified {@code property}.
|
|
|
|
* @returns {Object} The specified {@code state} if the value of the specified
|
|
|
|
* {@code property} equals the specified <tt>value/tt>; otherwise, a new state
|
|
|
|
* constructed from the specified {@code state} by setting the specified
|
|
|
|
* {@code property} to the specified {@code value}.
|
2016-12-05 15:14:50 +00:00
|
|
|
*/
|
2017-09-01 21:25:48 +00:00
|
|
|
export function set(state: Object, property: string, value: any) {
|
2017-04-22 22:57:08 +00:00
|
|
|
return _set(state, property, value, /* copyOnWrite */ true);
|
2016-12-12 00:29:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* eslint-disable max-params */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets a specific property of a specific state to a specific value. Prevents
|
2017-10-01 06:35:19 +00:00
|
|
|
* unnecessary state changes (when the specified {@code value} is equal to the
|
|
|
|
* value of the specified {@code property} of the specified {@code state}).
|
2016-12-12 00:29:13 +00:00
|
|
|
*
|
|
|
|
* @param {Object} state - The (Redux) state from which a state is to be
|
2017-10-01 06:35:19 +00:00
|
|
|
* constructed by setting the specified {@code property} to the specified
|
|
|
|
* {@code value}.
|
|
|
|
* @param {string} property - The property of {@code state} which is to be
|
|
|
|
* assigned the specified {@code value}.
|
|
|
|
* @param {*} value - The value to assign to the specified {@code property}.
|
|
|
|
* @param {boolean} copyOnWrite - If the specified {@code state} is to not be
|
|
|
|
* modified, {@code true}; otherwise, {@code false}.
|
|
|
|
* @returns {Object} The specified {@code state} if the value of the specified
|
|
|
|
* {@code property} equals the specified <tt>value/tt> or {@code copyOnWrite}
|
2016-12-12 00:29:13 +00:00
|
|
|
* is truthy; otherwise, a new state constructed from the specified
|
2017-10-01 06:35:19 +00:00
|
|
|
* {@code state} by setting the specified {@code property} to the specified
|
|
|
|
* {@code value}.
|
2016-12-12 00:29:13 +00:00
|
|
|
*/
|
2017-09-01 21:25:48 +00:00
|
|
|
function _set(
|
|
|
|
state: Object,
|
|
|
|
property: string,
|
|
|
|
value: any,
|
|
|
|
copyOnWrite: boolean) {
|
2016-12-05 15:14:50 +00:00
|
|
|
// Delete state properties that are to be set to undefined. (It is a matter
|
|
|
|
// of personal preference, mostly.)
|
|
|
|
if (typeof value === 'undefined'
|
|
|
|
&& Object.prototype.hasOwnProperty.call(state, property)) {
|
2016-12-12 00:29:13 +00:00
|
|
|
const newState = copyOnWrite ? { ...state } : state;
|
2016-12-05 15:14:50 +00:00
|
|
|
|
|
|
|
if (delete newState[property]) {
|
|
|
|
return newState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state[property] !== value) {
|
2016-12-12 00:29:13 +00:00
|
|
|
if (copyOnWrite) {
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
[property]: value
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
state[property] = value;
|
2016-12-05 15:14:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
2016-12-12 00:29:13 +00:00
|
|
|
|
|
|
|
/* eslint-enable max-params */
|
2017-09-01 21:25:48 +00:00
|
|
|
|
|
|
|
/**
|
2017-10-01 06:35:19 +00:00
|
|
|
* Returns redux state from the specified {@code stateful} which is presumed to
|
2018-11-08 12:25:02 +00:00
|
|
|
* be related to the redux state (e.g. The redux store, the redux
|
2017-10-01 06:35:19 +00:00
|
|
|
* {@code getState} function).
|
2017-09-01 21:25:48 +00:00
|
|
|
*
|
2017-09-18 20:52:10 +00:00
|
|
|
* @param {Function|Object} stateful - The entity such as the redux store or the
|
2017-10-01 06:35:19 +00:00
|
|
|
* redux {@code getState} function from which the redux state is to be
|
2017-09-18 20:52:10 +00:00
|
|
|
* returned.
|
2017-09-01 21:25:48 +00:00
|
|
|
* @returns {Object} The redux state.
|
|
|
|
*/
|
2017-09-18 20:52:10 +00:00
|
|
|
export function toState(stateful: Function | Object) {
|
|
|
|
if (stateful) {
|
|
|
|
if (typeof stateful === 'function') {
|
|
|
|
return stateful();
|
|
|
|
}
|
|
|
|
|
|
|
|
const { getState } = stateful;
|
|
|
|
|
2017-09-25 17:31:19 +00:00
|
|
|
if (typeof getState === 'function') {
|
2017-09-18 20:52:10 +00:00
|
|
|
return getState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return stateful;
|
2017-09-01 21:25:48 +00:00
|
|
|
}
|