redux-dux
Version:
``` npm i --save redux-dux ```
220 lines (176 loc) • 6.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.update = undefined;
exports.combine = combine;
exports.dux = dux;
exports.bindSelectors = bindSelectors;
exports.createStore = createStore;
var _redux = require('redux');
var redux = _interopRequireWildcard(_redux);
var _lodash = require('lodash.snakecase');
var _lodash2 = _interopRequireDefault(_lodash);
var _lodash3 = require('lodash.set');
var _lodash4 = _interopRequireDefault(_lodash3);
var _lodash5 = require('lodash.reduce');
var _lodash6 = _interopRequireDefault(_lodash5);
var _lodash7 = require('lodash.map');
var _lodash8 = _interopRequireDefault(_lodash7);
var _lodash9 = require('lodash.get');
var _lodash10 = _interopRequireDefault(_lodash9);
var _lodash11 = require('lodash.assign');
var _lodash12 = _interopRequireDefault(_lodash11);
var _updateJs = require('update-js');
var _updateJs2 = _interopRequireDefault(_updateJs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
/**
* @module dux
*/
var store = void 0;
var reducers = [];
var combinedReducer = function combinedReducer(s) {
return s;
};
function duxReducer() {
return combinedReducer.apply(undefined, arguments);
}
/**
* Combines an array of reducers into one.
* If reducer doesn't modify the state it should return its first
* argument. In the case nothing is passed, the resulting
* reducer will be an identity function.
* @param {Function[]} [reducers] - Reducers to combine into one.
*/
function combine() {
for (var _len = arguments.length, reducers = Array(_len), _key = 0; _key < _len; _key++) {
reducers[_key] = arguments[_key];
}
return function (state, action) {
for (var i = 0; i < reducers.length; i += 1) {
var newState = reducers[i](state, action);
if (newState && newState !== state) {
return newState;
}
}
return state;
};
}
function sdbm(str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;
}
hash = hash >>> 0;
return hash.toString(16);
}
function hashKeys(o) {
return sdbm((0, _lodash6.default)(o, function (acc, __, key) {
return acc + key;
}, ''));
}
var createReducerCreator = function createReducerCreator(nameToActionType, sliceKey) {
return function (reduceFn, key) {
var actionType = nameToActionType(key);
return function (state, _ref) {
var type = _ref.type,
args = _ref.args;
if (type !== actionType) return state;
var slice = reduceFn.apply(undefined, [(0, _lodash10.default)(state, sliceKey)].concat(_toConsumableArray(args)));
if (slice instanceof Function) {
slice = slice(state);
}
return update(state, sliceKey, slice);
};
};
};
// TODO(ET): deep-freeze slice in dev mode
/**
* Creates a Redux module.
* @param {Object} options - set of key-value pairs, where key is an action
* creator name and value is a reducer function.
* The reducer function receives a slice of the state, corresponding
* to the module, and arguments passed to the action creator: (slice, ...args).
* The reducer function can return either a new slice or a function which
* receives the whole state and returns a new slice.
*
*/
function dux(options, selectors) {
var hash = hashKeys(options);
var nameToActionType = function nameToActionType(key) {
return hash + '/' + (0, _lodash2.default)(key).toUpperCase();
};
var createReducer = createReducerCreator(nameToActionType, hash);
var createAction = function createAction(key) {
return function () {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return store.dispatch({
type: nameToActionType(key),
args: args
});
};
};
var createSelector = function createSelector(fn) {
return function (state) {
return fn((0, _lodash10.default)(state, hash));
};
};
var self = (0, _lodash6.default)(options, function (acc, val, key) {
return (0, _lodash4.default)(acc, key, createAction(key));
}, {});
self.selectors = (0, _lodash6.default)(selectors, function (acc, val, key) {
var selector = createSelector(val);
return (0, _lodash4.default)(acc, key, selector);
}, {});
self.extend = function (duck, selectors) {
var __ = duck.selectors,
actions = _objectWithoutProperties(duck, ['selectors']);
(0, _lodash12.default)(this, actions);
(0, _lodash12.default)(this.selectors, selectors);
return this;
};
reducers.push(combine.apply(undefined, _toConsumableArray((0, _lodash8.default)(options, createReducer))));
combinedReducer = combine.apply(undefined, reducers);
return self;
}
function bindSelectors() {
for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
args[_key3] = arguments[_key3];
}
var selectorsArr = args.slice(0, args.length - 1);
var cb = args[args.length - 1];
return function (state) {
var sliceGetters = selectorsArr.map(function (selectors) {
return Object.defineProperties({}, (0, _lodash6.default)(selectors, function (acc, selector, name) {
return (0, _lodash4.default)(acc, name, { get: function get() {
return selector(state);
} });
}, {}));
});
return cb.apply(undefined, _toConsumableArray(sliceGetters));
};
}
/**
* Creates Redux store.
* See [createStore.md](https://github.com/reduxjs/redux/blob/master/docs/api/createStore.md).
*/
function createStore(reducer, preloadedState, enhancers) {
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancers = preloadedState;
preloadedState = undefined;
}
// TODO: what if createStore is called multiple times?
reducers.push(reducer);
combinedReducer = combine.apply(undefined, reducers);
return store = redux.createStore(duxReducer, preloadedState, enhancers);
}
/**
* Object immutability helper.
* See [update-js](https://github.com/akuzko/update-js).
*/
var update = exports.update = _updateJs2.default;