easy-peasy
Version:
Vegetarian friendly state for React
1,337 lines (1,159 loc) • 42 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var immerPeasy = require('immer-peasy');
var React = require('react');
var React__default = _interopDefault(React);
var redux = require('redux');
var reduxThunk = _interopDefault(require('redux-thunk'));
var memoizerific = _interopDefault(require('memoizerific'));
var isPlainObject = _interopDefault(require('is-plain-object'));
var debounce = _interopDefault(require('debounce'));
var StoreContext = React.createContext();
// To get around it, we can conditionally useEffect on the server (no-op) and
// useLayoutEffect in the browser. We need useLayoutEffect to ensure the store
// subscription callback always has the selector from the latest render commit
// available, otherwise a store update may happen between render and the effect,
// which may cause missed updates; we also must ensure the store subscription
// is created synchronously, otherwise a store update may occur before the
// subscription is created and an inconsistent state may be observed
var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
function createStoreStateHook(Context) {
return function useStoreState(mapState) {
var store = React.useContext(Context);
var mapStateRef = React.useRef(mapState);
var stateRef = React.useRef();
var mountedRef = React.useRef(true);
var subscriptionMapStateError = React.useRef();
var _useReducer = React.useReducer(function (s) {
return s + 1;
}, 0),
forceRender = _useReducer[1];
if (subscriptionMapStateError.current || mapStateRef.current !== mapState || stateRef.current === undefined) {
try {
stateRef.current = mapState(store.getState());
} catch (err) {
var errorMessage = "An error occurred trying to map state in a useStoreState hook: " + err.message + ".";
if (subscriptionMapStateError.current) {
errorMessage += "\nThis error may be related to the following error:\n" + subscriptionMapStateError.current.stack + "\n\nOriginal stack trace:";
}
throw new Error(errorMessage);
}
}
useIsomorphicLayoutEffect(function () {
mapStateRef.current = mapState;
subscriptionMapStateError.current = undefined;
});
useIsomorphicLayoutEffect(function () {
var checkMapState = function checkMapState() {
try {
var newState = mapStateRef.current(store.getState());
if (newState === stateRef.current) {
return;
}
stateRef.current = newState;
} catch (err) {
// see https://github.com/reduxjs/react-redux/issues/1179
// There is a possibility mapState will fail due to stale state or
// props, therefore we will just track the error and force our
// component to update. It should then receive the updated state
subscriptionMapStateError.current = err;
}
if (mountedRef.current) {
forceRender({});
}
};
var unsubscribe = store.subscribe(checkMapState);
checkMapState();
return function () {
mountedRef.current = false;
unsubscribe();
};
}, []);
return stateRef.current;
};
}
var useStoreState = createStoreStateHook(StoreContext);
function createStoreActionsHook(Context) {
return function useStoreActions(mapActions) {
var store = React.useContext(Context);
return mapActions(store.getActions());
};
}
var useStoreActions = createStoreActionsHook(StoreContext);
function createStoreDispatchHook(Context) {
return function useStoreDispatch() {
var store = React.useContext(Context);
return store.dispatch;
};
}
var useStoreDispatch = createStoreDispatchHook(StoreContext);
function useStore() {
return React.useContext(StoreContext);
}
function createStoreRehydratedHook(Context) {
return function useStoreRehydrated() {
var store = React.useContext(Context);
var _useState = React.useState(false),
rehydrated = _useState[0],
setRehydrated = _useState[1];
React.useEffect(function () {
store.persist.resolveRehydration().then(function () {
return setRehydrated(true);
});
}, []);
return rehydrated;
};
}
var useStoreRehydrated = createStoreRehydratedHook(StoreContext);
function createTypedHooks() {
return {
useStoreActions: useStoreActions,
useStoreDispatch: useStoreDispatch,
useStoreState: useStoreState,
useStoreRehydrated: useStoreRehydrated,
useStore: useStore
};
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
var actionSymbol = '🙈action🙈';
var actionOnSymbol = '🙈actionOn🙈';
var computedSymbol = '🙈computedSymbol🙈';
var persistSymbol = '🙈persistSymbol🙈';
var reducerSymbol = '🙈reducer🙈';
var thunkOnSymbol = '🙈thunkOn🙈';
var thunkSymbol = '🙈thunk🙈';
var debug = function debug(state) {
if (immerPeasy.isDraft(state)) {
return immerPeasy.original(state);
}
return state;
};
var memo = function memo(fn, cacheSize) {
return memoizerific(cacheSize)(fn);
};
var actionOn = function actionOn(targetResolver, fn) {
fn[actionOnSymbol] = {
targetResolver: targetResolver
};
return fn;
};
var action = function action(fn) {
fn[actionSymbol] = {};
return fn;
};
var defaultStateResolvers = [function (state) {
return state;
}];
var computed = function computed(fnOrStateResolvers, fn) {
if (typeof fn === 'function') {
fn[computedSymbol] = {
stateResolvers: fnOrStateResolvers
};
return fn;
}
fnOrStateResolvers[computedSymbol] = {
stateResolvers: defaultStateResolvers
};
return fnOrStateResolvers;
};
var persist = function persist(model, config) {
var _extends2;
return _extends({}, model, (_extends2 = {}, _extends2[persistSymbol] = config, _extends2));
};
var thunkOn = function thunkOn(targetResolver, fn) {
fn[thunkOnSymbol] = {
targetResolver: targetResolver
};
return fn;
};
var thunk = function thunk(fn) {
fn[thunkSymbol] = {};
return fn;
};
var reducer = function reducer(fn) {
fn[reducerSymbol] = {};
return fn;
};
var deepCloneStateWithoutComputed = function deepCloneStateWithoutComputed(source) {
var recursiveClone = function recursiveClone(current) {
var next = Object.keys(current).reduce(function (acc, key) {
if (Object.getOwnPropertyDescriptor(current, key).get == null) {
acc[key] = current[key];
}
return acc;
}, {});
Object.keys(next).forEach(function (key) {
if (isPlainObject(next[key])) {
next[key] = recursiveClone(next[key]);
}
});
return next;
};
return recursiveClone(source);
};
var isPromise = function isPromise(x) {
return x != null && typeof x === 'object' && typeof x.then === 'function';
};
function get(path, target) {
return path.reduce(function (acc, cur) {
return isPlainObject(acc) ? acc[cur] : undefined;
}, target);
}
function newify(currentPath, currentState, finalValue) {
if (currentPath.length === 0) {
return finalValue;
}
var newState = _extends({}, currentState);
var key = currentPath[0];
if (currentPath.length === 1) {
newState[key] = finalValue;
} else {
newState[key] = newify(currentPath.slice(1), newState[key], finalValue);
}
return newState;
}
var set = function set(path, target, value) {
if (path.length === 0) {
if (typeof value === 'object') {
Object.keys(target).forEach(function (key) {
delete target[key];
});
Object.keys(value).forEach(function (key) {
target[key] = value[key];
});
}
return;
}
path.reduce(function (acc, cur, idx) {
if (idx + 1 === path.length) {
acc[cur] = value;
} else {
acc[cur] = acc[cur] || {};
}
return acc[cur];
}, target);
};
function createSimpleProduce(disableImmer) {
if (disableImmer === void 0) {
disableImmer = false;
}
return function simpleProduce(path, state, fn) {
if (disableImmer) {
var _current = get(path, state);
var next = fn(_current);
if (_current !== next) {
return newify(path, state, next);
}
return state;
}
if (path.length === 0) {
var _draft = immerPeasy.createDraft(state);
var _result = fn(_draft);
if (_result) {
return immerPeasy.isDraft(_result) ? immerPeasy.finishDraft(_result) : _result;
}
return immerPeasy.finishDraft(_draft);
}
var parentPath = path.slice(0, path.length - 1);
var draft = immerPeasy.createDraft(state);
var parent = get(parentPath, state);
var current = get(path, draft);
var result = fn(current);
if (result) {
parent[path[path.length - 1]] = result;
}
return immerPeasy.finishDraft(draft);
};
}
function createReducer(disableImmer, actionReducersDict, customReducers, computedProperties) {
var simpleProduce = createSimpleProduce(disableImmer);
var runActionReducerAtPath = function runActionReducerAtPath(state, action, actionReducer, path) {
return simpleProduce(path, state, function (draft) {
return actionReducer(draft, action.payload);
});
};
var reducerForActions = function reducerForActions(state, action) {
var actionReducer = actionReducersDict[action.type];
if (actionReducer) {
var actionMeta = actionReducer[actionSymbol] || actionReducer[actionOnSymbol];
return runActionReducerAtPath(state, action, actionReducer, actionMeta.parent);
}
return state;
};
var reducerForCustomReducers = function reducerForCustomReducers(state, action) {
return customReducers.reduce(function (acc, _ref) {
var parentPath = _ref.parentPath,
key = _ref.key,
red = _ref.reducer;
return simpleProduce(parentPath, acc, function (draft) {
draft[key] = red(draft[key], action);
return draft;
});
}, state);
};
var rootReducer = function rootReducer(state, action) {
var stateAfterActions = reducerForActions(state, action);
var next = customReducers.length > 0 ? reducerForCustomReducers(stateAfterActions, action) : stateAfterActions;
if (state !== next) {
computedProperties.forEach(function (_ref2) {
var parentPath = _ref2.parentPath,
bindComputedProperty = _ref2.bindComputedProperty;
bindComputedProperty(get(parentPath, next));
});
}
return next;
};
return rootReducer;
}
var noopStorage = {
getItem: function getItem() {
return undefined;
},
setItem: function setItem() {
return undefined;
},
removeItem: function removeItem() {
return undefined;
}
};
var localStorage = typeof window !== 'undefined' && typeof window.localStorage !== 'undefined' ? window.localStorage : noopStorage;
var sessionStorage = typeof window !== 'undefined' && typeof window.sessionStorage !== 'undefined' ? window.sessionStorage : noopStorage;
function createStorageWrapper(storage, transformers) {
if (storage === void 0) {
storage = sessionStorage;
}
if (transformers === void 0) {
transformers = [];
}
if (typeof storage === 'string') {
if (storage === 'localStorage') {
storage = localStorage;
} else if (storage === 'sessionStorage') {
storage = sessionStorage;
} else {
if (process.env.NODE_ENV === 'development') {
console.warn("Invalid storage provider specified for Easy Peasy persist: " + storage + "\nValid values include \"localStorage\", \"sessionStorage\" or a custom storage engine.");
}
storage = noopStorage;
}
}
var outTransformers = transformers.reverse();
var serialize = function serialize(data, key) {
var simpleKey = key.substr(key.indexOf('@') + 1);
var transformed = transformers.reduce(function (acc, cur) {
return cur.in(acc, simpleKey);
}, data);
return storage === localStorage || storage === sessionStorage ? JSON.stringify({
data: transformed
}) : transformed;
};
var deserialize = function deserialize(data, key) {
var simpleKey = key.substr(key.indexOf('@') + 1);
var result = storage === localStorage || storage === sessionStorage ? JSON.parse(data).data : data;
return outTransformers.reduce(function (acc, cur) {
return cur.out(acc, simpleKey);
}, result);
};
var isAsync = isPromise(storage.getItem('_'));
return {
isAsync: isAsync,
getItem: function getItem(key) {
if (isAsync) {
return storage.getItem(key).then(function (wrapped) {
return wrapped != null ? deserialize(wrapped, key) : undefined;
});
}
var wrapped = storage.getItem(key);
return wrapped != null ? deserialize(wrapped, key) : undefined;
},
setItem: function setItem(key, data) {
return storage.setItem(key, serialize(data, key));
},
removeItem: function removeItem(key) {
return storage.removeItem(key);
}
};
}
function extractPersistConfig(path, persistDefinition) {
if (persistDefinition === void 0) {
persistDefinition = {};
}
return {
path: path,
config: {
blacklist: persistDefinition.blacklist || [],
mergeStrategy: persistDefinition.mergeStrategy || 'merge',
storage: createStorageWrapper(persistDefinition.storage, persistDefinition.transformers),
whitelist: persistDefinition.whitelist || []
}
};
}
function resolvePersistTargets(target, whitelist, blacklist) {
var targets = Object.keys(target);
if (whitelist.length > 0) {
targets = targets.reduce(function (acc, cur) {
if (whitelist.findIndex(function (x) {
return x === cur;
}) !== -1) {
return [].concat(acc, [cur]);
}
return acc;
}, []);
}
if (blacklist.length > 0) {
targets = targets.reduce(function (acc, cur) {
if (blacklist.findIndex(function (x) {
return x === cur;
}) !== -1) {
return acc;
}
return [].concat(acc, [cur]);
}, []);
}
return targets;
}
function createPersistor(persistKey, references) {
return debounce(function () {
references.internals.persistenceConfig.forEach(function (_ref) {
var path = _ref.path,
config = _ref.config;
var storage = config.storage,
whitelist = config.whitelist,
blacklist = config.blacklist;
var state = references.getState();
var persistRoot = deepCloneStateWithoutComputed(get(path, state));
var targets = resolvePersistTargets(persistRoot, whitelist, blacklist);
targets.forEach(function (key) {
var targetPath = [].concat(path, [key]);
storage.setItem(persistKey(targetPath), get(targetPath, state));
});
});
}, 1000);
}
function createPersistMiddleware(persistor, references) {
return function () {
return function (next) {
return function (action) {
var state = next(action);
if (action && action.type !== '@action.easyPeasyReplaceState' && references.internals.persistenceConfig.length > 0) {
persistor(state);
}
return state;
};
};
};
}
function createPersistenceClearer(persistKey, references) {
return function () {
return new Promise(function (resolve, reject) {
references.internals.persistenceConfig.forEach(function (_ref2) {
var path = _ref2.path,
config = _ref2.config;
var storage = config.storage,
whitelist = config.whitelist,
blacklist = config.blacklist;
var persistRoot = get(path, references.getState());
var targets = resolvePersistTargets(persistRoot, whitelist, blacklist);
if (targets.length > 0) {
Promise.all(targets.map(function (key) {
var targetPath = [].concat(path, [key]);
return storage.removeItem(persistKey(targetPath));
})).then(function () {
return resolve();
}, reject);
} else {
resolve();
}
});
});
};
}
function rehydrateStateFromPersistIfNeeded(persistKey, replaceState, references) {
// If we have any persist configs we will attemp to perform a state rehydration
var resolveRehydration = Promise.resolve();
if (references.internals.persistenceConfig.length > 0) {
references.internals.persistenceConfig.forEach(function (persistInstance) {
var path = persistInstance.path,
config = persistInstance.config;
var blacklist = config.blacklist,
mergeStrategy = config.mergeStrategy,
storage = config.storage,
whitelist = config.whitelist;
var state = references.internals.defaultState;
var persistRoot = deepCloneStateWithoutComputed(get(path, state));
var targets = resolvePersistTargets(persistRoot, whitelist, blacklist);
var applyRehydrationStrategy = function applyRehydrationStrategy(originalState, rehydratedState) {
if (mergeStrategy === 'overwrite') {
set(path, originalState, rehydratedState);
} else if (mergeStrategy === 'merge') {
var target = get(path, originalState);
Object.keys(rehydratedState).forEach(function (key) {
target[key] = rehydratedState[key];
});
} else if (mergeStrategy === 'mergeDeep') {
var _target = get(path, originalState);
var setAt = function setAt(currentTarget, currentNext) {
Object.keys(currentNext).forEach(function (key) {
var data = currentNext[key];
if (isPlainObject(data)) {
if (!isPlainObject(currentTarget[key])) {
currentTarget[key] = {};
}
setAt(currentTarget[key], data);
} else {
currentTarget[key] = data;
}
});
};
setAt(_target, rehydratedState);
}
};
if (storage.isAsync) {
var asyncStateResolvers = targets.reduce(function (acc, key) {
var targetPath = [].concat(path, [key]);
var dataPromise = storage.getItem(persistKey(targetPath));
if (isPromise(dataPromise)) {
acc.push({
key: key,
dataPromise: dataPromise
});
}
return acc;
}, []);
if (asyncStateResolvers.length > 0) {
resolveRehydration = Promise.all(asyncStateResolvers.map(function (x) {
return x.dataPromise;
})).then(function (resolvedData) {
var next = resolvedData.reduce(function (acc, cur, idx) {
var key = asyncStateResolvers[idx].key;
if (cur !== undefined) {
acc[key] = cur;
}
return acc;
}, {});
if (Object.keys(next).length === 0) {
return;
}
applyRehydrationStrategy(state, next);
replaceState(state);
});
}
} else {
var next = targets.reduce(function (acc, key) {
var targetPath = [].concat(path, [key]);
var data = storage.getItem(persistKey(targetPath));
if (data !== undefined) {
acc[key] = data;
}
return acc;
}, {});
applyRehydrationStrategy(state, next);
replaceState(state);
}
});
}
return resolveRehydration;
}
function createActionCreator(actionDefinition, meta, references) {
var prefix = actionDefinition[actionSymbol] ? '@action' : '@actionOn';
var type = prefix + "." + meta.path.join('.');
var actionMeta = actionDefinition[actionSymbol] || actionDefinition[actionOnSymbol];
actionMeta.actionName = meta.key;
actionMeta.type = type;
actionMeta.parent = meta.parent;
actionMeta.path = meta.path;
var actionCreator = function actionCreator(payload) {
var action = {
type: type,
payload: payload
};
if (actionDefinition[actionOnSymbol] && actionMeta.resolvedTargets) {
payload.resolvedTargets = [].concat(actionMeta.resolvedTargets);
}
var result = references.dispatch(action);
return result;
};
actionCreator.type = type;
return actionCreator;
}
function createThunkHandler(thunkDefinition, meta, references, injections, actionCreators) {
var thunkMeta = thunkDefinition[thunkSymbol] || thunkDefinition[thunkOnSymbol];
return function (payload) {
var helpers = {
dispatch: references.dispatch,
getState: function getState() {
return get(meta.parent, references.getState());
},
getStoreActions: function getStoreActions() {
return actionCreators;
},
getStoreState: references.getState,
injections: injections,
meta: meta
};
if (thunkDefinition[thunkOnSymbol] && thunkMeta.resolvedTargets) {
payload.resolvedTargets = [].concat(thunkMeta.resolvedTargets);
}
return thunkDefinition(get(meta.parent, actionCreators), payload, helpers);
};
}
function createThunkActionsCreator(thunkDefinition, meta, references, thunkHandler) {
var prefix = thunkDefinition[thunkSymbol] ? '@thunk' : '@thunkOn';
var type = prefix + "." + meta.path.join('.');
var startType = type + "(start)";
var successType = type + "(success)";
var failType = type + "(fail)";
var thunkMeta = thunkDefinition[thunkSymbol] || thunkDefinition[thunkOnSymbol];
thunkMeta.type = type;
thunkMeta.actionName = meta.key;
thunkMeta.parent = meta.parent;
thunkMeta.path = meta.path;
var actionCreator = function actionCreator(payload) {
var dispatchError = function dispatchError(err) {
references.dispatch({
type: failType,
payload: payload,
error: err
});
references.dispatch({
type: type,
payload: payload,
error: err
});
};
var dispatchSuccess = function dispatchSuccess(result) {
references.dispatch({
type: successType,
payload: payload,
result: result
});
references.dispatch({
type: type,
payload: payload,
result: result
});
};
references.dispatch({
type: startType,
payload: payload
});
try {
var result = references.dispatch(function () {
return thunkHandler(payload);
});
if (typeof result === 'object' && typeof result.then === 'function') {
return result.then(function (resolved) {
dispatchSuccess(resolved);
return resolved;
}).catch(function (err) {
dispatchError(err);
throw err;
});
}
dispatchSuccess(result);
return result;
} catch (err) {
dispatchError(err);
throw err;
}
};
actionCreator.type = type;
actionCreator.startType = startType;
actionCreator.successType = successType;
actionCreator.failType = failType;
return actionCreator;
}
function createListenerMiddleware(references) {
return function () {
return function (next) {
return function (action) {
var result = next(action);
if (action && references.internals.listenerActionMap[action.type] && references.internals.listenerActionMap[action.type].length > 0) {
var sourceAction = references.internals.actionCreatorDict[action.type];
references.internals.listenerActionMap[action.type].forEach(function (actionCreator) {
actionCreator({
type: sourceAction ? sourceAction.type : action.type,
payload: action.payload,
error: action.error,
result: action.result
});
});
}
return result;
};
};
};
}
function bindListenerDefinitions(listenerDefinitions, actionCreators, actionCreatorDict, listenerActionMap) {
listenerDefinitions.forEach(function (listenerActionOrThunk) {
var listenerMeta = listenerActionOrThunk[actionOnSymbol] || listenerActionOrThunk[thunkOnSymbol];
var targets = listenerMeta.targetResolver(get(listenerMeta.parent, actionCreators), actionCreators);
var targetTypes = (Array.isArray(targets) ? targets : [targets]).reduce(function (acc, target) {
if (typeof target === 'function' && target.type && actionCreatorDict[target.type]) {
acc.push(target.type);
} else if (typeof target === 'string') {
acc.push(target);
}
return acc;
}, []);
listenerMeta.resolvedTargets = targetTypes;
targetTypes.forEach(function (targetType) {
var listenerReg = listenerActionMap[targetType] || [];
listenerReg.push(actionCreatorDict[listenerMeta.type]);
listenerActionMap[targetType] = listenerReg;
});
});
}
function createComputedPropertyBinder(parentPath, key, definition, computedState, references) {
var computedMeta = definition[computedSymbol];
var memoisedResultFn = memoizerific(1)(definition);
return function createComputedProperty(o) {
Object.defineProperty(o, key, {
configurable: true,
enumerable: true,
get: function get$1() {
var storeState;
if (computedState.isInReducer) {
storeState = computedState.currentState;
} else if (references.getState == null) {
return undefined;
} else {
try {
storeState = references.getState();
} catch (err) {
if (process.env.NODE_ENV !== 'production') {
console.warn('Invalid access attempt to a computed property');
}
return undefined;
}
}
var state = get(parentPath, storeState);
var inputs = computedMeta.stateResolvers.map(function (resolver) {
return resolver(state, storeState);
});
return memoisedResultFn.apply(void 0, inputs);
}
});
};
}
function createComputedPropertiesMiddleware(references) {
return function (store) {
return function (next) {
return function (action) {
references.internals.computedState.currentState = store.getState();
references.internals.computedState.isInReducer = true;
return next(action);
};
};
};
}
function extractDataFromModel(model, initialState, injections, references) {
var defaultState = initialState;
var actionCreatorDict = {};
var actionCreators = {};
var actionReducersDict = {};
var actionThunks = {};
var computedProperties = [];
var customReducers = [];
var listenerActionCreators = {};
var listenerActionMap = {};
var listenerDefinitions = [];
var persistenceConfig = [];
var computedState = {
isInReducer: false,
currentState: defaultState
};
var recursiveExtractFromModel = function recursiveExtractFromModel(current, parentPath) {
return Object.keys(current).forEach(function (key) {
var value = current[key];
var path = [].concat(parentPath, [key]);
var meta = {
parent: parentPath,
path: path,
key: key
};
var handleValueAsState = function handleValueAsState() {
var initialParentRef = get(parentPath, initialState);
if (initialParentRef && key in initialParentRef) {
set(path, defaultState, initialParentRef[key]);
} else {
set(path, defaultState, value);
}
};
if (key === persistSymbol) {
persistenceConfig.push(extractPersistConfig(parentPath, value));
return;
}
if (typeof value === 'function') {
if (value[actionSymbol] || value[actionOnSymbol]) {
var actionReducer = value;
var actionCreator = createActionCreator(value, meta, references);
actionCreatorDict[actionCreator.type] = actionCreator;
actionReducersDict[actionCreator.type] = actionReducer;
if (meta.key !== 'easyPeasyReplaceState') {
if (value[actionOnSymbol]) {
listenerDefinitions.push(value);
set(path, listenerActionCreators, actionCreator);
} else {
set(path, actionCreators, actionCreator);
}
}
} else if (value[thunkSymbol] || value[thunkOnSymbol]) {
var thunkHandler = createThunkHandler(value, meta, references, injections, actionCreators);
var _actionCreator = createThunkActionsCreator(value, meta, references, thunkHandler);
set(path, actionThunks, thunkHandler);
actionCreatorDict[_actionCreator.type] = _actionCreator;
if (value[thunkOnSymbol]) {
listenerDefinitions.push(value);
set(path, listenerActionCreators, _actionCreator);
} else {
set(path, actionCreators, _actionCreator);
}
} else if (value[computedSymbol]) {
var parent = get(parentPath, defaultState);
var bindComputedProperty = createComputedPropertyBinder(parentPath, key, value, computedState, references);
bindComputedProperty(parent);
computedProperties.push({
key: key,
parentPath: parentPath,
bindComputedProperty: bindComputedProperty
});
} else if (value[reducerSymbol]) {
customReducers.push({
key: key,
parentPath: parentPath,
reducer: value
});
} else {
handleValueAsState();
}
} else if (isPlainObject(value)) {
var existing = get(path, defaultState);
if (existing == null) {
set(path, defaultState, {});
}
recursiveExtractFromModel(value, path);
} else {
handleValueAsState();
}
});
};
recursiveExtractFromModel(model, []);
bindListenerDefinitions(listenerDefinitions, actionCreators, actionCreatorDict, listenerActionMap);
return {
actionCreatorDict: actionCreatorDict,
actionCreators: actionCreators,
actionReducersDict: actionReducersDict,
computedProperties: computedProperties,
customReducers: customReducers,
computedState: computedState,
defaultState: defaultState,
listenerActionCreators: listenerActionCreators,
listenerActionMap: listenerActionMap,
persistenceConfig: persistenceConfig
};
}
function createStoreInternals(_ref) {
var disableImmer = _ref.disableImmer,
initialState = _ref.initialState,
injections = _ref.injections,
model = _ref.model,
reducerEnhancer = _ref.reducerEnhancer,
references = _ref.references;
var _extractDataFromModel = extractDataFromModel(model, initialState, injections, references),
actionCreatorDict = _extractDataFromModel.actionCreatorDict,
actionCreators = _extractDataFromModel.actionCreators,
actionReducersDict = _extractDataFromModel.actionReducersDict,
computedState = _extractDataFromModel.computedState,
computedProperties = _extractDataFromModel.computedProperties,
customReducers = _extractDataFromModel.customReducers,
defaultState = _extractDataFromModel.defaultState,
listenerActionCreators = _extractDataFromModel.listenerActionCreators,
listenerActionMap = _extractDataFromModel.listenerActionMap,
persistenceConfig = _extractDataFromModel.persistenceConfig;
var rootReducer = createReducer(disableImmer, actionReducersDict, customReducers, computedProperties);
return {
actionCreatorDict: actionCreatorDict,
actionCreators: actionCreators,
computedProperties: computedProperties,
computedState: computedState,
defaultState: defaultState,
listenerActionCreators: listenerActionCreators,
listenerActionMap: listenerActionMap,
persistenceConfig: persistenceConfig,
reducer: reducerEnhancer(rootReducer)
};
}
function createStore(model, options) {
if (options === void 0) {
options = {};
}
var modelClone = deepCloneStateWithoutComputed(model);
var _options = options,
compose = _options.compose,
_options$devTools = _options.devTools,
devTools = _options$devTools === void 0 ? true : _options$devTools,
_options$disableImmer = _options.disableImmer,
disableImmer = _options$disableImmer === void 0 ? false : _options$disableImmer,
_options$enhancers = _options.enhancers,
enhancers = _options$enhancers === void 0 ? [] : _options$enhancers,
_options$initialState = _options.initialState,
initialState = _options$initialState === void 0 ? {} : _options$initialState,
injections = _options.injections,
_options$middleware = _options.middleware,
middleware = _options$middleware === void 0 ? [] : _options$middleware,
_options$mockActions = _options.mockActions,
mockActions = _options$mockActions === void 0 ? false : _options$mockActions,
_options$name = _options.name,
storeName = _options$name === void 0 ? "EasyPeasyStore" : _options$name,
_options$reducerEnhan = _options.reducerEnhancer,
reducerEnhancer = _options$reducerEnhan === void 0 ? function (rootReducer) {
return rootReducer;
} : _options$reducerEnhan;
var bindReplaceState = function bindReplaceState(modelDef) {
return _extends({}, modelDef, {
easyPeasyReplaceState: action(function (_, payload) {
return payload;
})
});
};
var references = {};
var modelDefinition = bindReplaceState(modelClone);
var mockedActions = [];
var persistKey = function persistKey(targetPath) {
return "[" + storeName + "]@" + targetPath.join('.');
};
var persistor = createPersistor(persistKey, references);
var persistMiddleware = createPersistMiddleware(persistor, references);
var clearPersistance = createPersistenceClearer(persistKey, references);
var replaceState = function replaceState(nextState) {
return references.internals.actionCreatorDict['@action.easyPeasyReplaceState'](nextState);
};
var bindStoreInternals = function bindStoreInternals(state) {
if (state === void 0) {
state = {};
}
references.internals = createStoreInternals({
disableImmer: disableImmer,
initialState: state,
injections: injections,
model: modelDefinition,
reducerEnhancer: reducerEnhancer,
references: references
});
};
var mockActionsMiddleware = function mockActionsMiddleware() {
return function () {
return function (action) {
if (action != null) {
mockedActions.push(action);
}
return undefined;
};
};
};
var composeEnhancers = compose || (devTools && typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
name: storeName
}) : redux.compose);
bindStoreInternals(initialState);
var easyPeasyMiddleware = [createComputedPropertiesMiddleware(references), reduxThunk].concat(middleware, [createListenerMiddleware(references), persistMiddleware]);
if (mockActions) {
easyPeasyMiddleware.push(mockActionsMiddleware);
}
var store = redux.createStore(references.internals.reducer, references.internals.defaultState, composeEnhancers.apply(void 0, [redux.applyMiddleware.apply(void 0, easyPeasyMiddleware)].concat(enhancers)));
store.subscribe(function () {
references.internals.computedState.isInReducer = false;
});
references.dispatch = store.dispatch;
references.getState = store.getState;
var bindActionCreators = function bindActionCreators() {
Object.keys(store.dispatch).forEach(function (actionsKey) {
delete store.dispatch[actionsKey];
});
Object.keys(references.internals.actionCreators).forEach(function (key) {
store.dispatch[key] = references.internals.actionCreators[key];
});
};
bindActionCreators();
var rebindStore = function rebindStore(removeKey) {
var currentState = store.getState();
if (removeKey) {
delete currentState[removeKey];
}
bindStoreInternals(currentState);
store.replaceReducer(references.internals.reducer);
replaceState(references.internals.defaultState);
bindActionCreators();
};
var _resolveRehydration = rehydrateStateFromPersistIfNeeded(persistKey, replaceState, references);
return Object.assign(store, {
addModel: function addModel(key, modelForKey) {
if (modelDefinition[key] && process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.warn("easy-peasy: The store model already contains a model definition for \"" + key + "\"");
store.removeModel(key);
}
modelDefinition[key] = modelForKey;
rebindStore();
},
clearMockedActions: function clearMockedActions() {
mockedActions = [];
},
getActions: function getActions() {
return references.internals.actionCreators;
},
getListeners: function getListeners() {
return references.internals.listenerActionCreators;
},
getMockedActions: function getMockedActions() {
return [].concat(mockedActions);
},
persist: {
clear: clearPersistance,
flush: function flush() {
return persistor.flush();
},
resolveRehydration: function resolveRehydration() {
return _resolveRehydration;
}
},
reconfigure: function reconfigure(newModel) {
modelDefinition = bindReplaceState(newModel);
rebindStore();
},
removeModel: function removeModel(key) {
if (!modelDefinition[key]) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.warn("easy-peasy: The store model does not contain a model definition for \"" + key + "\"");
}
return;
}
delete modelDefinition[key];
rebindStore(key);
}
});
}
/* eslint-disable react/prop-types */
function createContextStore(model, config) {
var StoreContext = React.createContext();
function Provider(_ref) {
var children = _ref.children,
initialData = _ref.initialData;
var store = React.useMemo(function () {
return createStore(typeof model === 'function' ? model(initialData) : model, config);
}, []);
return React__default.createElement(StoreContext.Provider, {
value: store
}, children);
}
function useStore() {
return React.useContext(StoreContext);
}
return {
Provider: Provider,
useStore: useStore,
useStoreState: createStoreStateHook(StoreContext),
useStoreActions: createStoreActionsHook(StoreContext),
useStoreDispatch: createStoreDispatchHook(StoreContext),
useStoreRehydrated: createStoreRehydratedHook(StoreContext)
};
}
/**
* Some good references on the topic of reinitialisation:
* - https://github.com/facebook/react/issues/14830
*/
function createComponentStore(model, config) {
return function useLocalStore(initialData) {
var store = React.useMemo(function () {
return createStore(typeof model === 'function' ? model(initialData) : model, config);
}, []);
var previousStateRef = React.useRef(store.getState());
var _useState = React.useState(function () {
return store.getState();
}),
currentState = _useState[0],
setCurrentState = _useState[1];
React.useEffect(function () {
return store.subscribe(function () {
var nextState = store.getState();
if (previousStateRef.current !== nextState) {
previousStateRef.current = nextState;
setCurrentState(nextState);
}
});
}, [store]);
return [currentState, store.getActions()];
};
}
/**
* This file has been copied from redux-persist.
* The intention being to support as much of the redux-persist API as possible.
*/
function createTransform(inbound, outbound, config) {
if (config === void 0) {
config = {};
}
var whitelist = config.whitelist || null;
var blacklist = config.blacklist || null;
function whitelistBlacklistCheck(key) {
if (whitelist && whitelist.indexOf(key) === -1) return true;
if (blacklist && blacklist.indexOf(key) !== -1) return true;
return false;
}
return {
in: function _in(data, key, fullState) {
return !whitelistBlacklistCheck(key) && inbound ? inbound(data, key, fullState) : data;
},
out: function out(data, key, fullState) {
return !whitelistBlacklistCheck(key) && outbound ? outbound(data, key, fullState) : data;
}
};
}
function StoreProvider(_ref) {
var children = _ref.children,
store = _ref.store;
return React__default.createElement(StoreContext.Provider, {
value: store
}, children);
}
/**
* The auto freeze feature of immer doesn't seem to work in our testing. We have
* explicitly disabled it to avoid perf issues.
*/
immerPeasy.setAutoFreeze(false);
exports.StoreProvider = StoreProvider;
exports.action = action;
exports.actionOn = actionOn;
exports.computed = computed;
exports.createComponentStore = createComponentStore;
exports.createContextStore = createContextStore;
exports.createStore = createStore;
exports.createTransform = createTransform;
exports.createTypedHooks = createTypedHooks;
exports.debug = debug;
exports.memo = memo;
exports.persist = persist;
exports.reducer = reducer;
exports.thunk = thunk;
exports.thunkOn = thunkOn;
exports.useStore = useStore;
exports.useStoreActions = useStoreActions;
exports.useStoreDispatch = useStoreDispatch;
exports.useStoreRehydrated = useStoreRehydrated;
exports.useStoreState = useStoreState;
//# sourceMappingURL=easy-peasy.cjs.js.map