UNPKG

redux-pathspace

Version:

> Quickly & easily create path-based namespaces to add actions that map to reducers

388 lines (303 loc) 14.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createPathspace = createPathspace; exports.mapNamespaces = exports.setStore = exports.createReducer = exports.createNamespace = void 0; var _set = _interopRequireDefault(require("ramda/src/set")); var _view = _interopRequireDefault(require("ramda/src/view")); var _lensPath = _interopRequireDefault(require("ramda/src/lensPath")); var _lensProp = _interopRequireDefault(require("ramda/src/lensProp")); var _lensIndex = _interopRequireDefault(require("ramda/src/lensIndex")); var _lodash = _interopRequireDefault(require("lodash.isplainobject")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } function compose() { for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) { funcs[_key] = arguments[_key]; } if (funcs.length === 0) { return function (arg) { return arg; }; } if (funcs.length === 1) { return funcs[0]; } return funcs.reduce(function (a, b) { return function () { return a(b.apply(void 0, arguments)); }; }); } function createPathspace() { var PATH_JOINER = '.'; var PREFIX_SEPERATOR = ':'; var pathStringSymbol = Symbol('@@Pathspace->createNamespace->path[pathString]'); var pathLensSymbol = Symbol('@@Pathspace->createNamespace->path[pathLens]'); var _namespaces = new Map(); var _store; var _actionCreators; function getPathPrefix(path) { if (!Array.isArray(path)) return path; return path.reduce(function (stringified, location) { return typeof location === 'number' ? "".concat(stringified.slice(0, -1), "[").concat(location, "].") : "".concat(stringified).concat(location, "."); }, '').slice(0, -1); } function checkPathArray(arr) { var isValid = arr.reduce(function (bool, val) { if (!bool) return false; if (typeof val === 'string' || typeof val === 'number') { if (typeof val === 'string') return val.split(PATH_JOINER).length === 1; return true; } return false; }, true); return isValid; } function getNamespace(path) { return _namespaces.get(getPathPrefix(path)); } function getNamespaceName(actionType) { var split = actionType.split(PREFIX_SEPERATOR)[0].split(PATH_JOINER); return split.length > 1 ? split : split[0]; } function reducerWrapper(lens, reducer, getPipeline) { var getter = (0, _view.default)(lens); var setter = (0, _set.default)(lens); return function wrappedReducer(state, payload) { var pipe = [function (x) { return setter(reducer(getter(x), payload, x), x); }].concat(_toConsumableArray(getPipeline().map(function (funcOrObj) { return typeof funcOrObj === 'function' ? function (x) { return funcOrObj(x, payload); } : function (x) { return getNamespace(getNamespaceName(funcOrObj.type)).get(funcOrObj.type)(x, funcOrObj.payload); }; }))); return compose.apply(void 0, _toConsumableArray(pipe))(state); }; } function createActionContainer(lens) { var _actions = new Map(); return { set: function set(actionName, reducer, getPipeline) { if (_actions.has(actionName)) throw new Error("The action \"".concat(actionName, "\" already exists for this path")); return _actions.set(actionName, reducerWrapper(lens, reducer, getPipeline)); }, get: function get(actionName) { return _actions.get(actionName); }, has: function has(actionName) { return _actions.has(actionName); } }; } function getActionName(path, actionName) { return !path.length ? actionName : "".concat(getPathPrefix(path)).concat(PREFIX_SEPERATOR).concat(actionName); } function defaultReducer(state, payload) { return payload; } function createNoSideEffect() { return function (payload) { return payload; }; } function validateAddActionArgs(actionType, reducer, meta) { if (typeof reducer !== 'function') throw new Error('The "reducer" property passed to "addAction" must be a function'); if (_typeof(meta) !== 'object') throw new Error('The "meta" property passed to "addAction" must be a plain object'); if (Array.isArray(meta)) throw new Error('The "meta" property passed to "addAction" must be a plain object'); if (typeof actionType !== 'string') throw new Error('The "actionType" property passed to "addAction" must be a string'); } function getSubPath(path, subPath) { if (Array.isArray(path)) { if (Array.isArray(subPath)) { return _toConsumableArray(path).concat(_toConsumableArray(subPath)); } if (typeof subPath === 'string') { return _toConsumableArray(path).concat(_toConsumableArray(subPath.split(PATH_JOINER))); } return _toConsumableArray(path).concat([subPath]); } if (Array.isArray(subPath)) { return "".concat(path, ".").concat(subPath.join(PATH_JOINER)); } if (typeof subPath === 'number') { return _toConsumableArray(path.split(PATH_JOINER)).concat([subPath]); } return "".concat(path, ".").concat(subPath); } function validatePath(path, parentPath) { if (typeof path !== 'number' && !path) throw new Error('No path was provided to "createNamespace" function, which is required'); if (typeof path !== 'string' && !Array.isArray(path) && typeof path !== 'number') throw new Error('The path provided to "createNamespace" function must be a string or array'); if (parentPath && !(parentPath[pathStringSymbol] && parentPath[pathLensSymbol])) throw new Error('When creating a sub path, the parent path must be a valid "path" function returned from "createNamespace"'); if (Array.isArray(path) && !checkPathArray(path)) throw new Error('When using an array to "createNamespace", only strings and numbers are permitted'); } function ensurePath(path) { if (!Array.isArray(path) && typeof path !== 'number') { var split = path.split(PATH_JOINER); if (split.length > 1) return split; return split[0]; } return path; } function createLens(path, parentPath) { var lens; if (Array.isArray(path)) lens = (0, _lensPath.default)(path); if (typeof path === 'number') lens = (0, _lensIndex.default)(path); if (typeof path === 'string') lens = (0, _lensProp.default)(path); return parentPath ? function (x) { return parentPath[pathLensSymbol](lens(x)); } : lens; } function setNamespace(path, parentPath) { validatePath(path, parentPath); var lens = createLens(ensurePath(path), parentPath); var pathString = parentPath ? getSubPath(parentPath[pathStringSymbol], path) : path; var prefix = getPathPrefix(pathString); if (_namespaces.has(prefix)) throw new Error("The path \"".concat(prefix, "\" already exists")); _namespaces.set(prefix, createActionContainer(lens)); return { lens: lens, prefix: prefix }; } function createNamespace(p, parentPath) { var _ref; var _setNamespace = setNamespace(p, parentPath), lens = _setNamespace.lens, prefix = _setNamespace.prefix; function mapActionToReducer(actionType) { var reducer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultReducer; var meta = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; validateAddActionArgs(actionType, reducer, meta); var _pipeline = []; var _createSideEffect = createNoSideEffect; var type = getActionName(prefix, actionType); function getPipeline() { return _pipeline; } getNamespace(prefix).set(type, reducer, getPipeline); function actionCreator() { return { type: type, payload: _createSideEffect(_store, _actionCreators).apply(void 0, arguments), meta: meta }; } function withSideEffect(createSideEffect) { if (typeof createSideEffect !== 'function') throw new Error('Value supplied to "withSideEffect" must be a function'); _createSideEffect = createSideEffect; return actionCreator; } function withPipeline() { _pipeline.push.apply(_pipeline, arguments); return actionCreator; } actionCreator.withSideEffect = withSideEffect; actionCreator.withPipeline = withPipeline; return actionCreator; } function wrapReducer(func) { return function (state, payload) { return (0, _set.default)(lens, func((0, _view.default)(lens, state), payload, state), state); }; } return _ref = {}, _defineProperty(_ref, pathStringSymbol, prefix), _defineProperty(_ref, pathLensSymbol, lens), _defineProperty(_ref, "examine", (0, _view.default)(lens)), _defineProperty(_ref, "mapActionToReducer", mapActionToReducer), _defineProperty(_ref, "wrapReducer", wrapReducer), _defineProperty(_ref, "lens", lens), _ref; } function createReducer() { var initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var initState = typeof initialState === 'function' ? initialState() : initialState; return function reducer(state, _ref2) { var type = _ref2.type, payload = _ref2.payload; var actions = getNamespace(getNamespaceName(type)); if (actions && actions.has(type)) { var result = actions.get(type)(state, payload); return result; } return state === undefined ? initState : state; }; } function setStore(store, actionCreators) { _store = store; _actionCreators = actionCreators; return _store; } function createArrayNamespace(path, nested, mapper, isString) { var namespace = createNamespace(path); var _indexNamespaces = []; function arrayNamespace(index) { if (!_indexNamespaces[index]) { _indexNamespaces[index] = mapper(nested, _toConsumableArray(path).concat([index])); } return _indexNamespaces[index]; } Object.keys(namespace).forEach(function (key) { arrayNamespace[key] = namespace[key]; }); if (isString) { arrayNamespace.examine = function (data) { return Object.keys(data).reduce(function (str, key) { return "".concat(str).concat(data[key]); }, ''); }; } return arrayNamespace; } function mapNamespacesToTarget(target) { var prevKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; if (Array.isArray(target) || typeof target === 'string') { var nested; var isString; if (Array.isArray(target)) { nested = target.find(function (val) { return Array.isArray(val) || (0, _lodash.default)(val); }); } if (typeof target === 'string') isString = true; return createArrayNamespace(prevKey, nested, mapNamespacesToTarget, isString); } if ((0, _lodash.default)(target)) { return Object.keys(target).reduce(function (cloned, key) { var path = _toConsumableArray(prevKey).concat([key]); if ((0, _lodash.default)(target[key])) { return _objectSpread({}, cloned, _defineProperty({}, key, mapNamespacesToTarget(target[key], path))); } if (Array.isArray(target[key])) { return _objectSpread({}, cloned, _defineProperty({}, key, mapNamespacesToTarget(target[key], path))); } return _objectSpread({}, cloned, _defineProperty({}, key, createNamespace(path))); }, createNamespace(prevKey)); } return createNamespace(prevKey); } function mapNamespaces(target) { if (!Array.isArray(target) && !(0, _lodash.default)(target) && typeof target !== 'string') { throw new TypeError("mapNamespaces only maps namespaces to arrays and objects. Instead you provided ".concat(target, ", which is of type ").concat(_typeof(target))); } return mapNamespacesToTarget(target); } return { createNamespace: createNamespace, createReducer: createReducer, setStore: setStore, mapNamespaces: mapNamespaces }; } var _createPathspace = createPathspace(), createNamespace = _createPathspace.createNamespace, createReducer = _createPathspace.createReducer, setStore = _createPathspace.setStore, mapNamespaces = _createPathspace.mapNamespaces; exports.mapNamespaces = mapNamespaces; exports.setStore = setStore; exports.createReducer = createReducer; exports.createNamespace = createNamespace;