UNPKG

@qtpy/state-management-observable

Version:

1. [Основная идея и архитектура](#основная-идея-и-архитектура) 1.1. [Прозрачная реактивность](#прозрачная-реактивность) 1.2. [Поддержка типизированных строковых ключей](#поддержка-типизированных-строковых-ключей) 1.3. [Подписки с «гранул

478 lines (477 loc) 15.7 kB
var se = Object.defineProperty; var ce = (E, o, u) => o in E ? se(E, o, { enumerable: !0, configurable: !0, writable: !0, value: u }) : E[o] = u; var $ = (E, o, u) => ce(E, typeof o != "symbol" ? o + "" : o, u); import { getStringPath as oe, validatePath as M, getRandomId as W, withMetaSupport as L, iterateObjectTree as I, calculateSnapshotHash as V, wrapNode as G, setMetaData as z, normalizeCacheKey as J, ssrStore as ae, isArrayMethod as ie, splitPath as O, getMetaData as ue, shallowEqual as de, isPathValid as le, getByPath as X } from "./utils.mjs"; class fe { constructor(o = [], u) { $(this, "undoStack", /* @__PURE__ */ new Map()); $(this, "redoStack", /* @__PURE__ */ new Map()); $(this, "perPathMaxLength"); this.perPathMaxLength = /* @__PURE__ */ new Map(); for (const [d, f] of o) { const h = u(d); this.perPathMaxLength.set(h, f); } } getMaxLength(o) { return this.perPathMaxLength.get(o) ?? 0; } push(o, u) { if (!this.perPathMaxLength.get(o)) return; const d = this.undoStack.get(o) ?? []; d.push(u); const f = this.getMaxLength(o); d.length > f && d.shift(), this.undoStack.set(o, d), this.redoStack.set(o, []); } getUndo(o, u) { const d = this.undoStack.get(o) ?? []; if (!(u < 0 || u >= d.length)) return d[d.length - 1 - u]; } getRedo(o, u) { const d = this.redoStack.get(o) ?? []; if (!(u < 0 || u >= d.length)) return d[d.length - 1 - u]; } getHistory(o) { const u = this.undoStack.get(o) ?? [], d = this.redoStack.get(o) ?? []; return { undo: [...u], redo: [...d] }; } spliceStack(o, u, d) { if (d) { const [f, h] = d; if (f < 0 || f >= o.length || h <= 0) return; const y = o.splice(f, h); return u.push(...y), y[y.length - 1]; } } undo(o, u) { const d = this.undoStack.get(o) ?? [], f = this.redoStack.get(o) ?? []; if (d.length <= 1 && !u) return; if (u) { const y = this.spliceStack(d, f, u); return this.undoStack.set(o, d), this.redoStack.set(o, f), y ?? (d.length > 0 ? d[d.length - 1] : void 0); } const h = d.pop(); return f.push(h), this.undoStack.set(o, d), this.redoStack.set(o, f), d[d.length - 1]; } redo(o, u) { const d = this.undoStack.get(o) ?? [], f = this.redoStack.get(o) ?? []; if (f.length === 0 && !u) return; if (u) { const y = this.spliceStack(f, d, u); return this.undoStack.set(o, d), this.redoStack.set(o, f), y; } const h = f.pop(); return d.push(h), this.undoStack.set(o, d), this.redoStack.set(o, f), h; } getCurrent(o) { const u = this.undoStack.get(o) ?? []; return u[u.length - 1]; } clear(o, u = "all", d) { const f = this.undoStack.get(o) ?? [], h = this.redoStack.get(o) ?? []; if (d) { const [y, w] = d; if (y < 0 || y >= (u === "redo" ? h : f).length || w <= 0) return !1; if (u === "redo") return h.splice(y, w), this.redoStack.set(o, h), !0; if (u === "undo") return f.splice(y, w), this.undoStack.set(o, f), !0; if (u === "all") { const p = f.length > 0 && y >= 0 && y < f.length && w > 0, k = h.length > 0 && y >= 0 && y < h.length && w > 0; return p && f.splice(y, w), k && h.splice(y, w), this.undoStack.set(o, f), this.redoStack.set(o, h), p || k; } } switch (u) { case "redo": return this.redoStack.delete(o); case "undo": return this.undoStack.delete(o); default: const y = this.undoStack.delete(o), w = this.redoStack.delete(o); return y || w; } } pruneUnused(o) { for (const u of [...this.undoStack.keys()]) o.has(u) || this.clear(u); } getEntries() { return Array.from(this.undoStack.entries()).map(([o, u]) => { const d = this.redoStack.get(o) ?? []; return { path: o, current: u[u.length - 1], undoLength: u.length, redoLength: d.length, undo: u, redo: d, maxLength: this.getMaxLength(o) }; }); } } function ye(E, o = [], u = {}) { let d = { ...E }, f = null; const h = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new WeakMap(), w = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Set(), k = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), K = /* @__PURE__ */ new Set(), x = /* @__PURE__ */ new Map(), C = () => { if (h.size === 0) return null; const e = Array.from(h.keys()).pop(); return h.get(e); }, q = () => h.size !== 0, _ = (e) => O(e).reduce((t, n) => { if (t != null) return t[n]; }, d), N = (e, r) => { const t = O(e), n = t.pop(), c = t.reduce((s, i) => { if (s == null) throw new Error(`Невозможно установить по пути "${e}" — промежуточное значение undefined`); return s[i]; }, d); c[n] = r; }; let B = null; function Q(e, r = "") { if (typeof e != "object" || e === null) return e; for (const { node: n, path: c, parent: s, key: i } of I(e)) L(n, () => { const l = V(n); if (!l) return; const g = G(n, s, i, y); z(y, g, { _prevSignature: l }, w, c); }); return new Proxy(e, { get(n, c, s) { const i = typeof c == "string" ? c : String(c), l = r ? `${r}.${i}` : i; f == null || f.trackedPaths.add(l); const g = Reflect.get(n, c, s); return Array.isArray(n) && typeof g == "function" && ie(i) ? (...m) => { B = { name: i }; const b = C(); let A; return a.batch(() => { A = g.apply(s, m); }, "proxy"), b && b.modeBatching === "proxy" && r && K.add(r), B = null, A; } : g === n ? s : g !== null && typeof g == "object" ? Q(g, l) : g; }, set(n, c, s, i) { const l = C(), g = typeof c == "string" ? c : String(c), m = r ? `${r}.${g}` : g, b = Reflect.get(n, c, i); return Object.is(b, s) || (l && l.modeBatching === "proxy" ? l == null || l.pending.set(m, s) : (a.update(m, s), !B && r && a.invalidate(r))), !0; }, deleteProperty(n, c) { const s = typeof c == "string" ? c : String(c), i = r ? `${r}.${s}` : s, l = Reflect.deleteProperty(n, c); return l && a.update(i, void 0), l; }, ownKeys(n) { if (f) { const c = r ? `${r}.` : ""; for (const s of Reflect.ownKeys(n)) f.trackedPaths.add(`${c}${String(s)}`); } return Reflect.ownKeys(n); } }); } function T(e, r, t, n, c = !0) { let s = !1; const i = L(r, () => { const l = ue(t, e, w, n), g = l == null ? void 0 : l._prevSignature, m = V(r); return g === m ? (s = !0, !0) : (m && c && z(t, r, { _prevSignature: m }, w, n), !0); }); return { newVal: r, oldVal: e, bool: s || !i && de(e, r), isSupportedMetaData: i, skipUpdate: s }; } const a = {}; let H = Q(d); Object.defineProperty(a, "$", { get: () => H, enumerable: !0, configurable: !0 }); const S = (e) => oe(a == null ? void 0 : a.$, e), P = new fe((u == null ? void 0 : u.customLimitsHistory) ?? [], S), U = /* @__PURE__ */ new Set(); function Y(e, r) { var n; const t = /* @__PURE__ */ new Set(); return e.forEach((c, s) => { t.add(s); }), (n = u == null ? void 0 : u.customLimitsHistory) == null || n.forEach(([c]) => { const s = a.resolvePath(c); t.add(s); }), r.forEach((c) => { const s = c.__meta; s != null && s.trackedPaths && s.trackedPaths.forEach((i) => t.add(i)); }), t; } function Z(e, r, t, n) { const c = e ? `${e}.` : ""; for (const s of n) { if (!s.startsWith(c) || U.has(s)) continue; const i = s.slice(c.length), l = X(t, i), g = X(r, i); T(l, g, y, s, !1).bool || (a.update(s, g, { skipHistory: !1, keepQuiet: !0, isRecurse: !0, oldValue: l, isAddMetaData: !0 }), U.add(s)); } q() || U.clear(); } function F(e, r, t, n, c) { L(r, () => { const s = /* @__PURE__ */ new Set(); c.forEach((i) => { le(d, i) ? s.add(i) : n.delete(i); }), Z(e, r, t, s); }); } function R(e, r, t, n = !1) { if (p.forEach((s) => { const i = s.__meta; if (q() ? i.cacheKeys && i.cacheKeys.has(e) : !i.cacheKeys || i.cacheKeys.has(e)) { f = i; try { s(H, i.unsubscribe); } finally { f = null; } } }), !U.has(e)) { const s = k.get(e); s && (s.forEach((i) => { const l = i.__meta; i(r, l.unsubscribe); }), U.add(e)); } if (n) return; const c = Y(k, p); F(e, r, t, k, c); } a.clearHistoryPath = (e, r = "all", t) => { const n = S(e); P.clear(n, r, t); }, a.clearAllHistory = () => { const e = new Set(k.keys()); P.pruneUnused(e); }; const D = (e, r, t = !1, n = !1, c = !1, s) => { const i = s ?? _(e), l = T(i, r, y, e); c && R(e, r, i, c), !t && !l.bool && P.push(e, r), !c && (l.bool || (N(e, r), !n && R(e, r, i, c))); }; a.update = (e, r, t) => { M(e); const n = C(), c = S(e); let s = a.resolveValue(e, r, t == null ? void 0 : t.isAddMetaData); if (n && !(t != null && t.keepQuiet)) n.pending.set(c, s); else return D(c, s, t == null ? void 0 : t.skipHistory, t == null ? void 0 : t.keepQuiet, t == null ? void 0 : t.isRecurse, t == null ? void 0 : t.oldValue), s; }, a.update.quiet = (e, r) => a.update(e, r, { keepQuiet: !0 }), a.debounced = (e, r) => { const t = W(); let n = null; const c = (...s) => { n && clearTimeout(n), n = setTimeout(() => { e(...s), x.delete(t); }, r), x.set(t, n); }; return c.cancel = () => { n && (clearTimeout(n), x.delete(t)); }, c; }; function ee(e) { const r = []; for (const [t, n] of e) { const c = _(t), s = T(c, n, y, t), i = C(); s.bool || ((i == null ? void 0 : i.modeBatching) === "user" && P.push(t, c), N(t, n), R(t, n, c), r.push(t)); } r.length && p.forEach((t) => { const n = t.__meta; n.cacheKeys || t(a.getRawStore(), n.unsubscribe); }); } function te(e) { const r = Array.from(h.keys()); for (let t = r.length - 1; t >= 0; t--) { const n = h.get(r[t]); if (n.pending.has(e)) return n.pending.get(e); } return _(e); } a.resolveValue = (e, r, t = !1) => { const n = S(e), c = te(n), s = typeof r == "function" ? r(c) : r; return t && L(s, () => { for (const { node: i, parent: l, key: g } of I(s)) { const m = V(i); if (!m) break; const b = G(i, l, g, y); z(y, b, { _prevSignature: m }, w, n); } }), s; }, a.cancelAsyncUpdates = (e) => { if (e) { const r = S(e), t = v.get(r); t && (t.abort(), v.delete(r)); } else v.forEach((r, t) => { r.abort(), v.delete(t); }); }, a.isAborted = (e) => { const r = S(e), t = v.get(r); return t ? t.signal.aborted : !1; }, a.asyncUpdate = async (e, r, t = {}) => { const { abortPrevious: n = !1, keepQuiet: c = !1 } = t; M(e); const s = S(e); n && a.cancelAsyncUpdates(s); let i; if (n) { const l = new AbortController(); v.set(s, l); try { const g = _(s); return i = await r(g, l.signal), a.update(s, i, { keepQuiet: c }), i; } catch (g) { throw g.name !== "AbortError" && console.error(g), g; } finally { v.delete(s); } } else try { const l = _(s); return i = await r(l), a.update(s, i, { keepQuiet: c }), i; } catch (l) { throw console.error(l), l; } }, a.asyncUpdate.quiet = async (e, r, t = {}) => a.asyncUpdate(e, r, { abortPrevious: t.abortPrevious ?? !1, keepQuiet: !0 }); function re(e = "user") { const r = W(); return h.set(r, { modeBatching: e, pending: /* @__PURE__ */ new Map() }), r; } function ne(e) { const r = h.get(e); if (r) if (h.delete(e), h.size === 0) { ee(r.pending), U.clear(); for (const t of K) a.invalidate(t); K.clear(); } else { const t = Array.from(h.keys()).pop(), n = h.get(t); r.pending.forEach((c, s) => n.pending.set(s, c)); } } a.batch = async (e, r = "user") => { const t = re(r); try { const n = e(); n instanceof Promise && await n; } finally { ne(t); } return Promise.resolve(); }, a.getUndo = (e, r) => { M(e); const t = S(e); return P.getUndo(t, r); }, a.getRedo = (e, r) => { M(e); const t = S(e); return P.getRedo(t, r); }, a.getHistory = (e) => { M(e); const r = S(e); return P.getHistory(r); }, a.undo = (e, r) => { M(e); const t = S(e), n = P.undo(t, r); return n !== void 0 ? (D(t, n, !0), a.update(t, n, { skipHistory: !0, keepQuiet: !0 }), !0) : (console.warn(`No undo history for path: ${t}`), !1); }, a.redo = (e, r) => { M(e); const t = S(e), n = P.redo(t, r); return n !== void 0 ? (D(t, n, !0), a.update(t, n, { skipHistory: !0, keepQuiet: !0 }), !0) : (console.warn(`No redo history for path: ${t}`), !1); }, a.subscribe = (e, r) => { const t = r ? new Set(r.map((s) => J(s, a))) : void 0, n = (s, i) => { c.active && e(s, i); }, c = { active: !0, trackedPaths: /* @__PURE__ */ new Set(), cacheKeys: t, unsubscribe: () => { c.active = !1, p.delete(n); } }; return n.__meta = c, p.add(n), c.unsubscribe; }, a.subscribeToPath = (e, r, t = {}) => { M(e); const { immediate: n = !1, cacheKeys: c } = t, s = S(e), i = c ? c.map((b) => J(b, a)) : [], l = [s, ...i], g = (b, A) => r(b, A), m = { active: !0, trackedPaths: new Set(l), cacheKeys: i.length > 0 ? new Set(i) : void 0, unsubscribe: () => { l.forEach((b) => { var A; (A = k.get(b)) == null || A.delete(g); }); } }; return g.__meta = m, l.forEach((b) => { k.has(b) || k.set(b, /* @__PURE__ */ new Set()), k.get(b).add(g); }), n && g(_(s), m.unsubscribe), m.unsubscribe; }, a.invalidateAll = () => { p.forEach((e) => { const r = e.__meta; f = r; try { e(H, r.unsubscribe); } finally { f = null; } }), k.forEach((e, r) => { const t = _(r); e.forEach((n) => { const c = n.__meta; n(t, c.unsubscribe); }); }); }, a.invalidate = (e) => { const r = S(e); R(r); }, a.cancelAsyncUpdates = (e) => { if (e) { const r = S(e), t = v.get(r); t && (t.abort(), v.delete(r)); } else v.forEach((r, t) => { r.abort(), v.delete(t); }); }, a.clearStore = () => { p.clear(), k.clear(), v.clear(), x.forEach((e) => clearTimeout(e)), x.clear(), a.clearAllHistory(); }, a.get = (e) => (M(e), _(S(e))), a.resolvePath = S, a.getRawStore = () => d, a.setRawStore = async (e, r) => { a.cancelAsyncUpdates(), a.clearAllHistory(), x.forEach((t) => clearTimeout(t)), x.clear(), d = { ...e }, H = Q(d), r != null && r.keepQuiet || a.invalidateAll(); }, a.getMemoryStats = () => ({ subscribersCount: p.size, pathSubscribersCount: k.size, historyEntries: P.getEntries(), activePathsCount: k.size, debounceTimersCount: x.size, abortersCount: v.size }); let j = a.update; return o.reverse().forEach((e) => { j = e(a, j); }), a.update = j, u.ssrStoreId ? ae(a, u.ssrStoreId) : a; } export { ye as createObservableStore };