UNPKG

@dhmk/zustand-lens

Version:

Lens support for zustand

221 lines (220 loc) 9.29 kB
"use strict"; 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;