zippa
Version:
A Generic Zipper Library
979 lines (806 loc) • 25.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.replace = exports.edit = exports.appendChild = exports.insertChild = exports.insertRight = exports.insertLeft = exports.prev = exports.next = exports.root = exports.up = exports.canGoUp = exports.canGoRight = exports.canGoLeft = exports.isRightmost = exports.isLeftmost = exports.isNotTop = exports.isTop = exports.isEnd = exports.getChildren = exports.isLeaf = exports.value = exports.whilst = undefined;
exports.zipperFrom = zipperFrom;
exports.isBranch = isBranch;
exports.leftmost = leftmost;
exports.left = left;
exports.right = right;
exports.rightmost = rightmost;
exports.canGoDown = canGoDown;
exports.down = down;
exports.remove = remove;
exports.makeZipper = makeZipper;
var _ = require('ramda/src/__');
var _2 = _interopRequireDefault(_);
var _assoc = require('ramda/src/assoc');
var _assoc2 = _interopRequireDefault(_assoc);
var _of = require('ramda/src/of');
var _of2 = _interopRequireDefault(_of);
var _always = require('ramda/src/always');
var _always2 = _interopRequireDefault(_always);
var _call = require('ramda/src/call');
var _call2 = _interopRequireDefault(_call);
var _cond = require('ramda/src/cond');
var _cond2 = _interopRequireDefault(_cond);
var _converge = require('ramda/src/converge');
var _converge2 = _interopRequireDefault(_converge);
var _complement = require('ramda/src/complement');
var _complement2 = _interopRequireDefault(_complement);
var _curry = require('ramda/src/curry');
var _curry2 = _interopRequireDefault(_curry);
var _either = require('ramda/src/either');
var _either2 = _interopRequireDefault(_either);
var _head = require('ramda/src/head');
var _head2 = _interopRequireDefault(_head);
var _equals = require('ramda/src/equals');
var _equals2 = _interopRequireDefault(_equals);
var _identity = require('ramda/src/identity');
var _identity2 = _interopRequireDefault(_identity);
var _init = require('ramda/src/init');
var _init2 = _interopRequireDefault(_init);
var _ifElse = require('ramda/src/ifElse');
var _ifElse2 = _interopRequireDefault(_ifElse);
var _last = require('ramda/src/last');
var _last2 = _interopRequireDefault(_last);
var _or = require('ramda/src/or');
var _or2 = _interopRequireDefault(_or);
var _prop = require('ramda/src/prop');
var _prop2 = _interopRequireDefault(_prop);
var _juxt = require('ramda/src/juxt');
var _juxt2 = _interopRequireDefault(_juxt);
var _tail = require('ramda/src/tail');
var _tail2 = _interopRequireDefault(_tail);
var _pipe = require('ramda/src/pipe');
var _pipe2 = _interopRequireDefault(_pipe);
var _merge = require('ramda/src/merge');
var _merge2 = _interopRequireDefault(_merge);
var _T = require('ramda/src/T');
var _T2 = _interopRequireDefault(_T);
var _when = require('ramda/src/when');
var _when2 = _interopRequireDefault(_when);
var _unless = require('ramda/src/unless');
var _unless2 = _interopRequireDefault(_unless);
var _until = require('ramda/src/until');
var _until2 = _interopRequireDefault(_until);
var _unnest = require('ramda/src/unnest');
var _unnest2 = _interopRequireDefault(_unnest);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var TOP = null;
var END = 'END';
function isEmpty(arr) {
return !arr.length;
}
var whilst = exports.whilst = (0, _curry2.default)(function (predicate, fn, value) {
var curr = value;
while (predicate(curr)) {
curr = fn(curr);
}
return curr;
});
var TOPPATH = {
left: [],
right: [],
parentItems: TOP,
parentPath: TOP,
changed: false
};
/**
* The Zipper class.
*
* Keeps track of the current item, path, and metadata (implementation functions).
*
* Don't use this constructor directly. Create your own Zipper factory with `makeZipper`,
* and use it to create instances of Zipper.
*
* @class Zipper
* @namespace Zipper
*/
function Zipper(item, path, meta) {
this.item = item;
this.path = path;
this.meta = meta;
}
var getItem = (0, _prop2.default)('item');
/**
* Gets the value of the current location.
* @param {Zipper} zipper
* @returns {T|null}
*/
var value = exports.value = getItem;
var getPath = (0, _prop2.default)('path');
var getMeta = (0, _prop2.default)('meta');
var sideEffect = (0, _curry2.default)(function (fn, x) {
fn(x);
return x;
});
var _raiser = function _raiser(msg) {
return function () {
throw new Error(msg);
};
};
var raise = (0, _pipe2.default)(_raiser, sideEffect);
function zipperFrom(oldLoc, newItem, path, meta) {
return new Zipper(newItem, path || getPath(oldLoc), meta || getMeta(oldLoc));
}
/**
* Returns a boolean indicating if the current location is not a leaf.
* @param {Zipper} zipper
* @returns {boolean}
*/
function isBranch(zipper) {
return getMeta(zipper).isBranch(getItem(zipper));
}
/**
* Returns a boolean indicating if the current location is a leaf.
* @param {Zipper} zipper
* @returns {boolean}
*/
var isLeaf = exports.isLeaf = (0, _complement2.default)(isBranch);
var _getChildrenFn = (0, _pipe2.default)(getMeta, (0, _prop2.default)('getChildren'));
var getChildren = exports.getChildren = (0, _pipe2.default)((0, _when2.default)(isLeaf, raise('Tried getting children of a leaf')), (0, _converge2.default)(_call2.default, [_getChildrenFn, getItem]));
function makeItem(z, item, children) {
return getMeta(z).makeItem(item, children);
}
/**
* Returns a boolean indicating if the zipper has been
* exhausted by calls to `next`.
*
* @param {Zipper} zipper
* @returns {boolean}
*/
var isEnd = exports.isEnd = (0, _pipe2.default)(getPath, (0, _equals2.default)(END));
var _parentItemsFromPath = (0, _prop2.default)('parentItems');
var _parent = (0, _pipe2.default)(_parentItemsFromPath, _last2.default);
var _parentPath = (0, _prop2.default)('parentPath');
var getParentItems = (0, _pipe2.default)(getPath, (0, _when2.default)((0, _equals2.default)(END), raise('Can\'t get parent items from end path.')), _parentItemsFromPath);
var getParent = (0, _pipe2.default)(getPath, _parent);
var getParentPath = (0, _pipe2.default)(getPath, _parentPath);
/**
* Returns a boolean indicating if the zipper is at the top.
* @param {Zipper} zipper
* @returns {boolean}
*/
var isTop = exports.isTop = (0, _pipe2.default)(getParentItems, (0, _equals2.default)(TOP));
/**
* Returns a boolean indicating if the zipper is not at the top.
* @param {Zipper} zipper
* @returns {boolean}
*/
var isNotTop = exports.isNotTop = (0, _complement2.default)(isTop);
var _leftsFromPath = (0, _pipe2.default)((0, _prop2.default)('left'), (0, _or2.default)(_2.default, []));
var _rightsFromPath = (0, _pipe2.default)((0, _prop2.default)('right'), (0, _or2.default)(_2.default, []));
var lefts = (0, _pipe2.default)(getPath, _leftsFromPath);
var rights = (0, _pipe2.default)(getPath, _rightsFromPath);
var hasChanged = (0, _pipe2.default)(getPath, (0, _prop2.default)('changed'), Boolean);
var isUnchanged = (0, _complement2.default)(hasChanged);
var isNotEmpty = (0, _complement2.default)(isEmpty);
/**
* Returns a boolean indicating if the item at the current location
* is the leftmost sibling.
* @param {Zipper} zipper
* @returns {boolean}
*/
var isLeftmost = exports.isLeftmost = (0, _pipe2.default)(lefts, isEmpty);
/**
* Returns a boolean indicating if the item at the current location
* is the rightmost sibling.
* @param {Zipper} zipper
* @returns {boolean}
*/
var isRightmost = exports.isRightmost = (0, _pipe2.default)(rights, isEmpty);
/**
* Returns a boolean indicating if the item at the current location
* is the leftmost sibling.
*
* Alias for {@link isLeftmost}
* @param {Zipper} zipper
* @returns {boolean}
*/
var canGoLeft = exports.canGoLeft = (0, _complement2.default)(isLeftmost);
/**
* Returns a boolean indicating if the item at the current location
* is the rightmost sibling.
*
* Alias for {@link isRightmost}
* @param {Zipper} zipper
* @returns {boolean}
*/
var canGoRight = exports.canGoRight = (0, _complement2.default)(isRightmost);
/**
* Moves location to the leftmost sibling.
* If the current location is already the leftmost,
* returns itself.
*
* @param {Zipper} zipper
* @returns {Zipper}
*/
function leftmost(zipper) {
if (isTop(zipper) || isLeftmost(zipper)) return zipper;
var path = getPath(zipper);
var _lefts = _leftsFromPath(path);
var _rights = _rightsFromPath(path);
var item = getItem(zipper);
var leftMost = (0, _head2.default)(_lefts);
var newLeft = [];
var newRight = (0, _tail2.default)(_lefts).concat([item], _rights);
return zipperFrom(zipper, leftMost, (0, _merge2.default)(path, {
left: newLeft,
right: newRight
}));
}
/**
* Moves location to the left sibling.
* If the current location is already the leftmost,
* returns null.
*
* @param {Zipper} zipper
* @returns {Zipper|null}
*/
function left(zipper) {
if (isEnd(zipper)) return zipper;
if (isLeftmost(zipper)) return null;
var item = getItem(zipper);
var path = getPath(zipper);
var _lefts = _leftsFromPath(path);
var _rights = _rightsFromPath(path);
var leftSibling = (0, _last2.default)(_lefts);
var newLeft = (0, _init2.default)(_lefts);
var newRight = [item].concat(_rights);
return zipperFrom(zipper, leftSibling, (0, _merge2.default)(path, {
left: newLeft,
right: newRight
}));
}
/**
* Moves location to the right sibling.
* If the current location is already the rightmost,
* returns null.
*
* @param {Zipper} zipper
* @returns {Zipper|null}
*/
function right(zipper) {
if (isEnd(zipper)) return zipper;
if (isRightmost(zipper)) return null;
var item = getItem(zipper);
var path = getPath(zipper);
var _lefts = _leftsFromPath(path);
var _rights = _rightsFromPath(path);
var rightSibling = (0, _head2.default)(_rights);
var newLeft = _lefts.concat([item]);
var newRight = (0, _tail2.default)(_rights);
return zipperFrom(zipper, rightSibling, (0, _merge2.default)(path, {
left: newLeft,
right: newRight
}));
}
/**
* Moves location to the rightmost sibling.
* If the current location is already the rightmost,
* returns itself.
*
* @param {Zipper} zipper
* @returns {Zipper}
*/
function rightmost(zipper) {
if (isRightmost(zipper)) return zipper;
var path = getPath(zipper);
var _rights = _rightsFromPath(path);
var _lefts = _leftsFromPath(path);
var item = getItem(zipper);
var rightMost = (0, _last2.default)(_rights);
var newLeft = _lefts.concat([item], (0, _init2.default)(_rights));
var newRight = [];
return zipperFrom(zipper, rightMost, (0, _merge2.default)(path, {
left: newLeft,
right: newRight
}));
}
/**
* Alias for `isBranch`
*
* @param {Zipper} zipper
* @returns {boolean}
*/
function canGoDown(ipper) {
return isBranch(ipper) && isNotEmpty(getChildren(ipper));
}
/**
* Moves location to the leftmost child.
* If the current item is a leaf, returns null.
*
* @param {Zipper} zipper
* @returns {Zipper|null}
*/
function down(zipper) {
if (!isBranch(zipper)) return null;
var item = getItem(zipper);
var path = getPath(zipper);
var children = getChildren(zipper);
var newLeft = [];
var newRight = (0, _tail2.default)(children);
var newLoc = zipperFrom(zipper, (0, _head2.default)(children), (0, _merge2.default)(path, {
left: newLeft,
right: newRight,
parentItems: (_parentItemsFromPath(path) || []).concat([item]),
parentPath: path
}));
return newLoc;
}
function _insertLeft(insertItem, zipper) {
if (isTop(zipper)) {
throw new Error('Tried inserting left of top');
}
var item = getItem(zipper);
var path = getPath(zipper);
var _lefts = _leftsFromPath(path);
return zipperFrom(zipper, item, (0, _merge2.default)(path, {
left: _lefts.concat([insertItem]),
changed: true
}));
}
function _insertRight(insertItem, zipper) {
if (isTop(zipper)) {
throw new Error('Tried inserting left of top');
}
var item = getItem(zipper);
var path = getPath(zipper);
var _rights = _rightsFromPath(path);
return zipperFrom(zipper, item, (0, _merge2.default)(path, {
right: [insertItem].concat(_rights),
changed: true
}));
}
function _replace(_replaceWith, zipper) {
if (getItem(zipper) === _replaceWith) return zipper;
return zipperFrom(zipper, _replaceWith, (0, _assoc2.default)('changed', true, getPath(zipper)));
}
function _edit(fn, zipper) {
return _replace(fn(getItem(zipper)), zipper);
}
/**
* Returns a boolean indicating if the zipper is not at the top.
*
* Alias for {@link isNotTop}
*
* @param {Zipper} zipper
* @returns {boolean}
*/
var canGoUp = exports.canGoUp = isNotTop;
var _unchangedUp = (0, _converge2.default)(zipperFrom, [_identity2.default, getParent, getParentPath]);
var itemsOnCurrentLevel = (0, _pipe2.default)((0, _juxt2.default)([lefts, (0, _pipe2.default)(getItem, _of2.default), rights]), _unnest2.default);
var makeParentItem = (0, _converge2.default)(makeItem, [_identity2.default, getParent, itemsOnCurrentLevel]);
/**
* Moves location to the parent, constructing a new parent
* if the children have changed.
*
* If already at the top, returns null.
*
* @param {Zipper} zipper
* @returns {Zipper|null}
*/
var up = exports.up = (0, _cond2.default)([[(0, _or2.default)(isTop, isEnd), (0, _always2.default)(null)], [isUnchanged, _unchangedUp], [_T2.default, (0, _converge2.default)(zipperFrom, [_identity2.default, makeParentItem, (0, _pipe2.default)(getParentPath, (0, _assoc2.default)('changed', true))])]]);
/**
* Moves location to the root, constructing
* any changes made.
*
* @param {Zipper} zipper
* @returns {Zipper}
*/
var root = exports.root = (0, _unless2.default)(isEnd, whilst(isNotTop, up));
var toEnd = function toEnd(z) {
return zipperFrom(z, getItem(z), END);
};
var nextUp = (0, _pipe2.default)((0, _until2.default)((0, _either2.default)(isTop, canGoRight), up), (0, _ifElse2.default)(isTop, toEnd, right));
/**
* Moves location to the next element in depth-first order.
*
* @param {Zipper} zipper
* @returns {Zipper}
*/
var next = exports.next = (0, _cond2.default)([[isEnd, _identity2.default], [canGoDown, down], [canGoRight, right], [_T2.default, nextUp]]);
var _goToRightmostChild = (0, _pipe2.default)(down, rightmost);
/**
* Moves location to the previous element in depth-first order.
*
* @param {Zipper} zipper
* @returns {Zipper}
*/
var prev = exports.prev = (0, _ifElse2.default)(canGoLeft, (0, _pipe2.default)(left, whilst(isBranch, _goToRightmostChild)), up);
/**
* Removes item at the current location.
* Returns location that would be previous in depth first search.
*
* @param {Zipper} zipper
* @returns {Zipper}
*/
function remove(zipper) {
if (isTop(zipper)) {
throw new Error('Can\'t remove top.');
}
if (isEnd(zipper)) throw new Error('Can\'t remove end');
var path = getPath(zipper);
var _lefts = _leftsFromPath(path);
if (_lefts.length) {
var leftSibling = zipperFrom(zipper, (0, _last2.default)(_lefts), (0, _merge2.default)(path, {
left: (0, _init2.default)(_lefts),
changed: true
}));
return whilst(isBranch, _goToRightmostChild, leftSibling);
} else {
var _rights = _rightsFromPath(path);
var parentPath = _parentPath(path);
var parent = _parent(path);
return zipperFrom(zipper, makeItem(zipper, parent, _rights), isTop(zipper) ? parentPath : (0, _assoc2.default)('changed', true, parentPath));
}
}
function _insertChild(item, z) {
var newChildren = [item].concat(getChildren(z));
return _replace(makeItem(z, item, newChildren), z);
}
function _appendChild(item, z) {
var newChildren = getChildren(z).concat([item]);
return _replace(makeItem(z, item, newChildren), z);
}
function makeNullaryMethod(fn) {
return function nullaryZipperMethod() {
return fn(this);
};
}
function makeUnaryMethod(fn) {
return function unaryZipperMethod(x) {
return fn(x, this);
};
}
Object.assign(Zipper.prototype, {
/**
* Gets the value of the current location.
*
* @alias Zipper.prototype.value
* @instance
* @memberof Zipper
* @returns {T|null}
*/
value: makeNullaryMethod(value),
/**
* Moves location to the root, constructing
* any changes made.
*
* @alias Zipper.prototype.root
* @instance
* @memberof Zipper
* @returns {Zipper}
*/
root: makeNullaryMethod(root),
/**
* Moves location to the parent.
* If at the top, returns null.
*
* @alias Zipper.prototype.up
* @instance
* @memberof Zipper
* @returns {Zipper|null}
*/
up: makeNullaryMethod(up),
/**
* Moves location to the leftmost child.
* If the current item is a leaf, returns null.
*
* @alias Zipper.prototype.down
* @instance
* @memberof Zipper
* @returns {Zipper|null}
*/
down: makeNullaryMethod(down),
/**
* Moves location to the left sibling.
* If the current location is already the leftmost,
* returns null.
*
* @alias Zipper.prototype.left
* @instance
* @memberof Zipper
* @returns {Zipper|null}
*/
left: makeNullaryMethod(left),
/**
* Moves location to the right sibling.
* If the current location is already the rightmost,
* returns null.
*
* @alias Zipper.prototype.right
* @instance
* @memberof Zipper
* @returns {Zipper|null}
*/
right: makeNullaryMethod(right),
/**
* Moves location to the leftmost sibling.
* If the current location is already the leftmost,
* returns itself.
*
* @alias Zipper.prototype.leftmost
* @instance
* @memberof Zipper
* @returns {Zipper}
*/
leftmost: makeNullaryMethod(leftmost),
/**
* Moves location to the rightmost sibling.
* If the current location is already the rightmost,
* returns itself.
*
* @alias Zipper.prototype.rightmost
* @instance
* @memberof Zipper
* @returns {Zipper}
*/
rightmost: makeNullaryMethod(rightmost),
/**
* Moves location to the next element in depth-first order.
*
* @alias Zipper.prototype.next
* @instance
* @memberof Zipper
* @returns {Zipper}
*/
next: makeNullaryMethod(next),
/**
* Moves location to the previous element in depth-first order.
*
* @alias Zipper.prototype.prev
* @instance
* @memberof Zipper
* @returns {Zipper}
*/
prev: makeNullaryMethod(prev),
/**
* Returns a boolean indicating if the zipper has been
* exhausted by calls to `next`.
*
* @alias Zipper.prototype.isEnd
* @instance
* @memberof Zipper
* @returns {boolean}
*/
isEnd: makeNullaryMethod(isEnd),
/**
* Returns a boolean indicating if the zipper is at the top.
*
* @alias Zipper.prototype.isTop
* @instance
* @memberof Zipper
* @returns {boolean}
*/
isTop: makeNullaryMethod(isTop),
/**
* Returns a boolean indicating if the current location is not a leaf.
*
* @alias Zipper.prototype.isBranch
* @instance
* @memberof Zipper
* @returns {boolean}
*/
isBranch: makeNullaryMethod(isBranch),
/**
* Returns a boolean indicating if the current location is a leaf.
*
* @alias Zipper.prototype.isLeaf
* @instance
* @memberof Zipper
* @returns {boolean}
*/
isLeaf: makeNullaryMethod(isLeaf),
/**
* Returns a boolean indicating if the item at the current location
* is the leftmost sibling.
*
* @alias Zipper.prototype.isLeftmost
* @instance
* @memberof Zipper
* @returns {boolean}
*/
isLeftmost: makeNullaryMethod(isLeftmost),
/**
* Returns a boolean indicating if the item at the current location
* is the rightmost sibling.
*
* @alias Zipper.prototype.isRightmost
* @instance
* @memberof Zipper
* @returns {boolean}
*/
isRightmost: makeNullaryMethod(isRightmost),
/**
* Alias for `isTop`.
*
* @alias Zipper.prototype.canGoUp
* @instance
* @memberof Zipper
* @returns {boolean}
*/
canGoUp: makeNullaryMethod(canGoUp),
/**
* Alias for `isLeftmost`
*
* @alias Zipper.prototype.canGoLeft
* @instance
* @memberof Zipper
* @returns {boolean}
*/
canGoLeft: makeNullaryMethod(canGoLeft),
/**
* Alias for `isRightmost`
*
* @alias Zipper.prototype.canGoRight
* @instance
* @memberof Zipper
* @returns {boolean}
*/
canGoRight: makeNullaryMethod(canGoRight),
/**
* Alias for `isBranch`
*
* @alias Zipper.prototype.canGoDown
* @instance
* @memberof Zipper
* @returns {boolean}
*/
canGoDown: makeNullaryMethod(canGoDown),
/**
* Replaces the current item with value returned
* by calling `fn` with the current item.
*
* @alias Zipper.prototype.edit
* @instance
* @memberof Zipper
* @param {Function} fn - Function that takes the old item
* and returns a new item.
* @returns {Zipper}
*/
edit: makeUnaryMethod(_edit),
/**
* Replaces the current item with the given value.
*
* @alias Zipper.prototype.replace
* @instance
* @memberof Zipper
* @param {T} replaceWith - item to replace the current one with.
* @returns {Zipper}
*/
replace: makeUnaryMethod(_replace),
/**
* Inserts a new item as the left sibling.
*
* @alias Zipper.prototype.insertLeft
* @instance
* @memberof Zipper
* @param {T} item
* @returns {Zipper}
*/
insertLeft: makeUnaryMethod(_insertLeft),
/**
* Inserts a new item as the right sibling.
*
* @alias Zipper.prototype.insertRight
* @instance
* @memberof Zipper
* @param {T} item
* @returns {Zipper}
*/
insertRight: makeUnaryMethod(_insertRight),
/**
* Inserts a new item as the leftmost child.
*
* @alias Zipper.prototype.insertChild
* @instance
* @memberof Zipper
* @param {T} item
* @returns {Zipper}
*/
insertChild: makeUnaryMethod(_insertChild),
/**
* Inserts a new item as the rightmost child.
*
* @alias Zipper.prototype.appendChild
* @instance
* @memberof Zipper
* @param {T} item
* @returns {Zipper}
*/
appendChild: makeUnaryMethod(_appendChild),
/**
* Removes item at the current location.
* Returns location that would be previous in depth first search.
*
* @alias Zipper.prototype.remove
* @instance
* @memberof Zipper
* @returns {Zipper}
*/
remove: makeNullaryMethod(remove)
});
/**
* Makes a Zipper factory that uses the implementation provided
* in the parameters.
*
* @param {Function} _isBranch - Function with signature`(item: T) => boolean`
* that indicates if the item can have children.
* @param {Function} _getChildren - Function with signature`(item: T) => Array<T>`
* that returns an array of children for a branch.
* @param {Function} _makeItem - Function with signature`(item: T, children: Array<T>) => T`
* that returns a new item, given an old item and it's new children.
* @return {Function} zipper factory with signature `(item: T) => Zipper`. The factory
* can also be accessed from the factory's `from` property.
*/
function makeZipper(_isBranch, _getChildren, _makeItem) {
function makeConcreteZipper(item) {
return new Zipper(item, TOPPATH, {
isBranch: _isBranch,
getChildren: _getChildren,
makeItem: _makeItem
});
}
makeConcreteZipper.from = makeConcreteZipper;
return makeConcreteZipper;
}
// Export functions with arity > 1 curried
/**
* Inserts a new item as the left sibling.
*
* @function
* @param {T} item
* @param {Zipper} zipper
* @returns {Zipper}
*/
var insertLeft = exports.insertLeft = (0, _curry2.default)(_insertLeft);
/**
* Inserts a new item as the right sibling.
*
* @function
* @param {T} item
* @param {Zipper} zipper
* @returns {Zipper}
*/
var insertRight = exports.insertRight = (0, _curry2.default)(_insertRight);
/**
* Inserts a new item as the leftmost child.
*
* @function
* @param {T} item
* @param {Zipper} zipper
* @returns {Zipper}
*/
var insertChild = exports.insertChild = (0, _curry2.default)(_insertChild);
/**
* Inserts a new item as the rightmost child.
*
* @function
* @param {T} item
* @returns {Zipper}
*/
var appendChild = exports.appendChild = (0, _curry2.default)(_appendChild);
/**
* Replaces the current item with value returned
* by calling `fn` with the current item.
*
* @function
* @param {Function} fn - Function that takes the old item
* and returns a new item.
* @param {Zipper} zipper
* @returns {Zipper}
*/
var edit = exports.edit = (0, _curry2.default)(_edit);
/**
* Replaces the current item with the given value.
*
* @function
* @param {T} replaceWith - item to replace the current one with.
* @param {Zipper} zipper
* @returns {Zipper}
*/
var replace = exports.replace = (0, _curry2.default)(_replace);
exports.default = makeZipper;