UNPKG

@qtpy/state-management-observable

Version:

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

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