@dhmk/zustand-lens
Version:
Lens support for zustand
221 lines (220 loc) • 9.29 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.atomic = exports.withLenses = exports.lens = exports.createLens = exports.meta = void 0;
var utils_1 = require("@dhmk/utils");
var vanilla_1 = require("zustand/vanilla");
exports.meta = Symbol("lens meta");
var storeContext = Symbol("store context");
// pathless overload to normalize setter's behavior
// function createLens(set, get)
function createLens(set, get, path) {
var normPath = path === undefined ? undefined : typeof path === "string" ? [path] : path;
var _set = function (partial, replace) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
return set.apply(void 0, __spreadArray([function (parentValue) {
var _a, _b, _c, _d;
var ourOldValue = normPath
? (0, utils_1.getIn)(parentValue, normPath)
: parentValue;
var ourTmpValue = typeof partial === "function" ? partial(ourOldValue) : partial;
var isPlain = (0, utils_1.isPlainObject)(ourOldValue);
// immer detection
var ourOldValue2 = normPath ? (0, utils_1.getIn)(get(), normPath) : get();
var isDraft = isPlain && ourOldValue !== ourOldValue2;
if (isDraft) {
var draft = ourOldValue;
if (ourTmpValue)
Object.assign(draft, ourTmpValue);
// not a `draft[meta]` because of immer@10 bug (https://github.com/immerjs/immer/issues/1087)
var pp = /*draft*/ (_b = (_a = ourOldValue2[exports.meta]) === null || _a === void 0 ? void 0 : _a.postprocess) === null || _b === void 0 ? void 0 : _b.call.apply(_b, __spreadArray([_a, draft,
ourOldValue2], args, false));
if (pp)
Object.assign(draft, pp);
return;
}
var ourTmpValue2 = replace || !isPlain
? ourTmpValue
: __assign(__assign({}, ourOldValue), ourTmpValue);
var ourNextValue = isPlain
? __assign(__assign({}, ourTmpValue2), (_d = (_c = ourTmpValue2[exports.meta]) === null || _c === void 0 ? void 0 : _c.postprocess) === null || _d === void 0 ? void 0 : _d.call.apply(_d, __spreadArray([_c, ourTmpValue2,
ourOldValue], args, false))) : ourTmpValue2;
var isSame = isPlain
? (0, utils_1.shallowEqual)(ourOldValue, ourNextValue)
: Object.is(ourOldValue, ourNextValue);
return isSame
? parentValue
: normPath
? (0, utils_1.setIn)(parentValue, normPath, ourNextValue)
: ourNextValue;
},
normPath ? false : replace], args, false));
};
var _get = function () { return (normPath ? (0, utils_1.getIn)(get(), normPath) : get()); };
return [_set, _get];
}
exports.createLens = createLens;
var LENS_TAG = "@dhmk/LENS_TAG";
var isLens = function (x) { return !!x && x[LENS_TAG]; };
var LensTypeInfo = /** @class */ (function () {
function LensTypeInfo() {
}
return LensTypeInfo;
}());
function lens(fn) {
var self = function (set, get, api, ctx /* partial context */) {
var _a = createLens(set, get, ctx.relativePath), _set = _a[0], _get = _a[1];
ctx.set = _set;
ctx.get = _get;
return fn(_set, _get, api, ctx);
};
self[LENS_TAG] = true;
return self;
}
exports.lens = lens;
var findLensAndCreate = function (x, parentCtx) {
var _a, _b;
var res = x;
if ((0, utils_1.isPlainObject)(x)) {
res = {};
var keys = Array().concat(Object.getOwnPropertyNames(x), (_b = (_a = Object.getOwnPropertySymbols) === null || _a === void 0 ? void 0 : _a.call(Object, x)) !== null && _b !== void 0 ? _b : [] // ie 11
);
keys.forEach(function (k) {
var _a;
var v = x[k];
// Symbol props are only for storing metadata
if (typeof k === "symbol") {
res[k] = v;
return;
}
var nextSet = parentCtx.set;
var nextGet = parentCtx.get;
var nextRelativePath = parentCtx.relativePath.concat(k);
if (isLens(v)) {
// partial context
// `lens` will update it with `set` and `get`
var lensCtx_1 = {
set: undefined, // will be set by `lens` function
get: undefined, // see `set`
api: parentCtx.api,
rootPath: parentCtx.rootPath.concat(k),
relativePath: parentCtx.relativePath.concat(k),
atomic: parentCtx.atomic === atomicStub
? atomicStubWithWarning
: parentCtx.atomic,
};
var setterFn_1 = function (x) { return x(); };
var set = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return parentCtx.atomic(function () {
return setterFn_1(function () { return parentCtx.set.apply(parentCtx, args); }, lensCtx_1);
});
};
v = v(set, parentCtx.get, parentCtx.api, lensCtx_1);
if ((_a = v[exports.meta]) === null || _a === void 0 ? void 0 : _a.setter)
setterFn_1 = v[exports.meta].setter;
nextSet = lensCtx_1.set;
nextGet = lensCtx_1.get;
nextRelativePath = [];
}
res[k] = findLensAndCreate(v, {
set: nextSet,
get: nextGet,
api: parentCtx.api,
rootPath: parentCtx.rootPath.concat(k),
relativePath: nextRelativePath,
atomic: parentCtx.atomic,
});
});
}
return res;
};
var withLensesImpl = function (config) { return function (set, get, api) {
var _a, _b, _c;
var atomic = (_b = (_a = api[storeContext]) === null || _a === void 0 ? void 0 : _a.atomic) !== null && _b !== void 0 ? _b : atomicStub;
var setterFn = function (x) { return x(); };
var setFn = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return atomic(function () { return setterFn(function () { return set.apply(void 0, args); }, ctx); });
};
var _set = createLens(setFn, get, undefined)[0]; // use pathless overload
var ctx = {
set: _set,
get: get,
api: api,
rootPath: [],
relativePath: [],
atomic: atomic,
};
// @ts-ignore
var obj = typeof config === "function" ? config(_set, get, api) : config;
var res = findLensAndCreate(obj, ctx);
if ((_c = res[exports.meta]) === null || _c === void 0 ? void 0 : _c.setter)
setterFn = res[exports.meta].setter;
return res;
}; };
exports.withLenses = withLensesImpl;
// atomic
var atomicStub = function (fn) { return fn(); };
var atomicStubWithWarning = function (fn) {
console.warn("You must include `atomic` middleware.");
return atomicStub(fn);
};
var atomicImpl = function (config) { return function (set, get, api) {
var _a;
var tempStore = (0, vanilla_1.createStore)(get);
var counter = 0;
var atomic = function (fn) {
if (++counter === 1) {
tempStore.setState(get());
}
try {
fn();
}
finally {
if (--counter === 0) {
set(tempStore.getState());
}
}
};
var _set = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
atomic(function () { return tempStore.setState.apply(tempStore, args); });
};
var _get = function () { return (counter ? tempStore.getState() : get()); };
return config(_set, _get, __assign(__assign({}, api), (_a = { setState: _set, getState: _get }, _a[storeContext] = {
atomic: atomic,
}, _a)));
}; };
exports.atomic = atomicImpl;