UNPKG

tilia

Version:

🍃 State management library, domain-driven.

935 lines (932 loc) 22.8 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.js var index_exports = {}; __export(index_exports, { _clear: () => _clear, _ctx: () => _ctx, _done: () => _done, _meta: () => _meta, _observe: () => _observe, _ready: () => _ready, batch: () => batch, carve: () => carve, changing: () => changing, computed: () => computed, derived: () => derived, lift: () => lift, make: () => make, observe: () => observe, readonly: () => readonly$1, signal: () => signal, source: () => source, store: () => store, tilia: () => tilia, watch: () => watch }); module.exports = __toCommonJS(index_exports); // src/Tilia.mjs var raise = (function(message) { throw new Error(message); }); var reraise = (function(e) { console.error("Reraising exception after flush"); throw e; }); var callCb = (function(cb, k, v) { cb(k, v); }); function cleanTrace(stack) { if (typeof stack !== "string") return stack; const cleaned = ["Exception thrown in computed or observe"]; let collapsing = false; for (const line of stack.split("\n")) { if (/src\/Tilia\.mjs:\d+:\d+/.test(line)) { if (!collapsing) { cleaned.push(" [... tilia internals]"); collapsing = true; } } else { cleaned.push(line); collapsing = false; } } return cleaned.join("\n"); } var symbol = (function(s) { return Symbol.for("tilia:" + s); }); var indexKey = symbol("indexKey"); var metaKey = symbol("metaKey"); var dynamicKey = symbol("dynamicKey"); var ctxKey = symbol("ctx"); var proxiable = (function(v) { if (typeof v === "object" && v !== null) { const proto = Object.getPrototypeOf(v); return proto === Object.prototype || proto === Array.prototype || proto === null; } return false; }); var dynamic = (function(v) { return typeof v === "object" && v !== null && v[dynamicKey] ? v : void 0; }); function readonly(o, k) { let d = Object.getOwnPropertyDescriptor(o, k); if (d == null) { return false; } else { return d.writable === false; } } var setError = (function(root, e) { if (typeof e === "object" && e !== null) { if (e.stack) { console.error(cleanTrace(e.stack)); } else { console.error(e); } root.error = e; } }); function observeKey(observed, key) { let w = observed.get(key); if (w !== null && w !== void 0) { return w; } w === null; let w$1 = { state: "Pristine", key, observed, observers: /* @__PURE__ */ new Set() }; observed.set(key, w$1); return w$1; } function flush(root) { if (root.expired.size > 0) { while (root.expired.size > 0) { let expired = root.expired; root.expired = /* @__PURE__ */ new Set(); expired.forEach((observer) => observer.notify()); } ; } let gc = root.gc; if (gc.active.size >= gc.threshold) { gc.quarantine.forEach((w) => { if (w.state === "Pristine" && w.observers.size === 0) { w.state = "Cleared"; w.observed.delete(w.key); return; } }); gc.quarantine = gc.active; gc.active = /* @__PURE__ */ new Set(); } if (root.error === void 0) { return; } let e = root.error; root.error = void 0; reraise(e); } function _clear(observer) { let root = observer.root; observer.observing.forEach((watchers) => { if (watchers.state === "Pristine" && watchers.observers.delete(observer) && watchers.observers.size === 0) { root.gc.active.add(watchers); return; } }); let o = root.observer; if (o == null || o !== observer) { return; } else { root.observer = void 0; if (!root.lock) { return flush(root); } else { return; } } } function _ready(observer, notifyIfChanged) { observer.observing.find((w, idx) => { let match = w.state; switch (match) { case "Pristine": w.observers.add(observer); return false; case "Changed": case "Cleared": break; } if (notifyIfChanged) { _clear(observer); observer.notify(); return true; } let w$1 = observeKey(w.observed, w.key); w$1.observers.add(observer); observer.observing[idx] = w$1; return false; }); let root = observer.root; let o = root.observer; if (o == null || o !== observer) { return; } else { root.observer = void 0; if (!root.lock) { return flush(root); } else { return; } } } function notify(root, observed, key) { let watchers = observed.get(key); if (watchers == null) { return; } observed.delete(key); watchers.state = "Changed"; let expired = root.expired; watchers.observers.forEach((observer) => { _clear(observer); expired.add(observer); }); let match = root.observer; if (match !== null && match !== void 0) { return; } match === null; if (!root.lock) { return flush(root); } } function set(node, isArray, _fromComputed, target, _key, _value) { while (true) { let value = _value; let key = _key; let fromComputed = _fromComputed; let hadKey = Reflect.has(target, key); let prev = Reflect.get(target, key); let proxiable$1 = proxiable(value); let same; if (proxiable$1) { let m = Reflect.get(value, metaKey); same = m == null ? prev === value : m.target === prev; } else { same = prev === value; } if (same) { return true; } if (!Reflect.set(target, key, value)) { return false; } let key$1 = isArray && key === "length" ? indexKey : key; if (proxiable$1) { node.proxied.delete(key$1); } if (!fromComputed) { let clear = node.computes.get(key$1); if (clear == null) { clear === null; } else { node.computes.delete(key$1); clear(); } } let match = dynamic(value); if (match == null) { match === null; } else { let w = node.observed.get(key$1); if (w == null) { return true; } if (!(w.state === "Pristine" && w.observers.size > 0)) { return true; } Reflect.set(target, key$1, prev); let compile$1 = (callback) => compile(node, isArray, target, key$1, callback); let setter = (v2) => { set(node, isArray, true, target, key$1, v2); }; let get = (_value2) => { while (true) { let value2 = _value2; let dynamic$1 = dynamic(value2); if (dynamic$1 == null) { return value2; } let v2; switch (dynamic$1.TAG) { case "Computed": v2 = compile$1(dynamic$1._0); break; case "Source": let source2 = dynamic$1._0; let v$1 = source2.value; let val = { contents: v$1 }; let set2 = (v3) => { val.contents = v3; setter(v3); }; v2 = compile$1((set2(v$1), () => { let callback = source2.source; callback(val.contents, set2); return val.contents; })); break; case "Store": let store2 = dynamic$1._0; v2 = compile$1(() => store2.store(setter)); break; case "Compiled": let rebuild = dynamic$1._0.rebuild; v2 = rebuild(); break; } if (!proxiable(v2)) { return v2; } _value2 = v2; continue; } ; }; let v = get(value); _value = v; _key = key$1; _fromComputed = true; continue; } if (!fromComputed) { let cbs = node.changes; if (cbs == null) { cbs === null; } else { cbs.forEach((cb) => callCb(cb, key, value)); } } notify(node.root, node.observed, key$1); if (!hadKey) { notify(node.root, node.observed, indexKey); } return true; } ; } function compile(node, isArray, target, key, callback) { let lastValue = { v: void 0 }; let observer = { o: void 0 }; let compute = { rebuild: void 0 }; let compiled = { TAG: "Compiled", _0: compute }; Reflect.set(compiled, dynamicKey, true); let notify2 = () => { let v = Reflect.get(target, key); if (v !== compiled) { lastValue.v = v; } let w = node.observed.get(key); if (w !== null && w !== void 0) { if (w.observers.size > 0) { set(node, isArray, true, target, key, rebuild()); } else { w.state = "Changed"; node.observed.delete(key); node.proxied.delete(key); Reflect.set(target, key, compiled); } return; } w === null; node.proxied.delete(key); Reflect.set(target, key, compiled); }; let rebuild = () => { let curr = Reflect.get(target, key); if (curr === compiled) { Reflect.set(target, key, lastValue.v); } else { lastValue.v = curr; } let o_root = node.root; let o_observing = []; let o = { root: o_root, notify: notify2, observing: o_observing }; observer.o = o; let previous = node.root.observer; node.root.observer = o; let v; try { v = callback(); } catch (_e) { setError(node.root, _e); _clear(o); if (previous == null) { previous === null; } else { _clear(previous); } v = lastValue.v; } node.root.observer = previous; if (o_observing.length === 0) { _clear(o); node.computes.delete(key); } else { _ready(o, false); } return v; }; compute.rebuild = rebuild; let clear = () => { let o = observer.o; if (o == null) { return; } _clear(o); o.observing.length = 0; }; node.computes.set(key, clear); return rebuild(); } function proxify(root, _target) { while (true) { let target = _target; let m = Reflect.get(target, metaKey); if (m == null) { m === null; } else { if (m.root === root) { return m; } _target = m.target; continue; } let node = { root, observed: /* @__PURE__ */ new Map(), proxied: /* @__PURE__ */ new Map(), computes: /* @__PURE__ */ new Map(), changes: void 0 }; let meta = (node.target = target, node); let isArray = Array.isArray(target); let proxy = new Proxy(target, { set: (extra, extra$1, extra$2) => set(node, isArray, false, extra, extra$1, extra$2), deleteProperty: (extra, extra$1) => { let res = Reflect.deleteProperty(extra, extra$1); node.proxied.delete(extra$1); let clear = node.computes.get(extra$1); if (clear == null) { clear === null; } else { node.computes.delete(extra$1); clear(); } let cbs = node.changes; if (cbs == null) { cbs === null; } else { cbs.forEach((cb) => callCb(cb, extra$1, void 0)); } notify(node.root, node.observed, extra$1); return res; }, get: (extra, extra$1) => { if (extra$1 === metaKey) { return meta; } if (extra$1 === dynamicKey) { return void 0; } let value = Reflect.get(extra, extra$1); let own = Object.hasOwn(extra, extra$1); if (!(value === void 0 || own)) { return value; } let o = node.root.observer; if (o == null) { o === null; } else if (isArray && extra$1 === "length") { let w = observeKey(node.observed, indexKey); o.observing.push(w); } else { let w$1 = observeKey(node.observed, extra$1); o.observing.push(w$1); } if (!(proxiable(value) && !readonly(extra, extra$1))) { return value; } let m2 = node.proxied.get(extra$1); if (m2 !== null && m2 !== void 0) { return m2.proxy; } m2 === null; let compile$1 = (callback) => compile(node, isArray, extra, extra$1, callback); let setter = (v2) => { set(node, isArray, true, extra, extra$1, v2); }; let get = (_value) => { while (true) { let value2 = _value; let dynamic$1 = dynamic(value2); if (dynamic$1 == null) { return value2; } let v2; switch (dynamic$1.TAG) { case "Computed": v2 = compile$1(dynamic$1._0); break; case "Source": let source2 = dynamic$1._0; let v$1 = source2.value; let val = { contents: v$1 }; let set2 = (v3) => { val.contents = v3; setter(v3); }; v2 = compile$1((set2(v$1), () => { let callback = source2.source; callback(val.contents, set2); return val.contents; })); break; case "Store": let store2 = dynamic$1._0; v2 = compile$1(() => store2.store(setter)); break; case "Compiled": let rebuild = dynamic$1._0.rebuild; v2 = rebuild(); break; } if (!proxiable(v2)) { return v2; } _value = v2; continue; } ; }; let v = get(value); Reflect.set(extra, extra$1, v); if (!proxiable(v)) { return v; } let m$1 = proxify(node.root, v); node.proxied.set(extra$1, m$1); return m$1.proxy; }, ownKeys: (extra) => { let root2 = node.root; let observed = node.observed; let keys = Reflect.ownKeys(extra); let o = root2.observer; if (o == null) { o === null; } else { let w = observeKey(observed, indexKey); o.observing.push(w); } return keys; } }); meta.proxy = proxy; return meta; } ; } function makeTilia(root) { return (value) => { if (!proxiable(value)) { raise("tilia: value is not an object or array"); } return proxify(root, value).proxy; }; } function makeDerived(p) { return (fn) => { let v = { TAG: "Computed", _0: () => fn(p.contents) }; Reflect.set(v, dynamicKey, true); return v; }; } function makeReactive(derived2) { return { derived: derived2 }; } function makeCarve(root) { return (fn) => { let p = { contents: {} }; let ctx2 = makeReactive(makeDerived(p)); let value = fn(ctx2); if (!proxiable(value)) { raise("tilia: value is not an object or array"); } let value$1 = proxify(root, value).proxy; p.contents = value$1; return value$1; }; } function makeObserve(root) { return (callback) => { let notify2 = () => { let observer_observing = []; let observer = { root, notify: notify2, observing: observer_observing }; root.observer = observer; let o = observer; try { callback(); return _ready(o, true); } catch (_e) { setError(root, _e); return _clear(o); } }; notify2(); }; } function makeWatch(root, observe_) { return (callback, effect) => { let notify2 = () => { let o2 = observe_(notify2); let v = callback(); o2.root.observer = void 0; if (root.lock) { effect(v); } else { root.lock = true; effect(v); root.lock = false; } _ready(o2, false); }; let o = observe_(notify2); callback(); _ready(o, false); }; } function makeBatch(root) { return (callback) => { if (root.lock) { return callback(); } else { root.lock = true; callback(); root.lock = false; return flush(root); } }; } var orphanError = "Cannot modify or access the value of an orphan computation. See https://tiliajs.com/errors#orphan"; function warningHandler() { return { set: (param, _key, _value) => raise(orphanError), deleteProperty: (param, _key) => raise(orphanError), get: (target, key) => { if (key === dynamicKey || key === metaKey || key === "TAG" || key === "_0") { return Reflect.get(target, key); } else { return raise(orphanError); } }, ownKeys: (target) => Reflect.ownKeys(target) }; } function computed(fn) { let v = { TAG: "Computed", _0: fn }; Reflect.set(v, dynamicKey, true); return new Proxy(v, warningHandler()); } function makeSource(tilia2) { return (value, source2) => { let d = dynamic(source2); let s; s = d == null ? { source: source2, value } : tilia2({ value, source: d }); let v = { TAG: "Source", _0: s }; Reflect.set(v, dynamicKey, true); return v; }; } function makeStore(tilia2) { return (callback) => { let d = dynamic(callback); let s; s = d == null ? { store: callback } : tilia2({ store: d }); let v = { TAG: "Store", _0: s }; Reflect.set(v, dynamicKey, true); return v; }; } function makeDerived$1(tilia2) { return (fn) => tilia2({ value: computed(() => fn()) }); } function _done(o) { o.root.observer = void 0; } function connector(tilia2, carve2, observe2, watch2, batch2, signal2, derived2, source2, store2, _observe2) { return { tilia: tilia2, carve: carve2, observe: observe2, watch: watch2, batch: batch2, // extra signal: signal2, derived: derived2, source: source2, store: store2, // internal _observe: _observe2 }; } function make(gcOpt) { let gc = gcOpt !== void 0 ? gcOpt : 50; let gc$1 = { active: /* @__PURE__ */ new Set(), quarantine: /* @__PURE__ */ new Set(), threshold: gc }; let root = { observer: void 0, expired: /* @__PURE__ */ new Set(), lock: false, error: void 0, id: Math.random(), gc: gc$1 }; let tilia2 = makeTilia(root); let _observe2 = (extra) => { let observer_observing = []; let observer = { root, notify: extra, observing: observer_observing }; root.observer = observer; return observer; }; return connector(tilia2, makeCarve(root), makeObserve(root), makeWatch(root, _observe2), makeBatch(root), (value) => { let s = tilia2({ value }); let set2 = (v) => { s.value = v; }; return [ s, set2 ]; }, makeDerived$1(tilia2), makeSource(tilia2), makeStore(tilia2), _observe2); } var ctx = Reflect.get(globalThis, ctxKey); var _ctx; var exit = 0; if (ctx == null) { exit = 1; } else { _ctx = ctx; } if (exit === 1) { let ctx$1 = make(void 0); Reflect.set(globalThis, ctxKey, ctx$1); _ctx = ctx$1; } function readonly$1(data) { let obj = {}; Object.defineProperty(obj, "data", { writable: false, enumerable: true, configurable: false, value: data }); return obj; } function lift(s) { return computed(() => s.value); } function changing(accessor, guard) { let empty_upsert = []; let empty_remove = []; let empty = { upsert: empty_upsert, remove: empty_remove }; let m = Reflect.get(accessor(), metaKey); let meta; meta = m == null ? raise("changing: argument is not a tilia proxy") : m; let root = meta.root; let pending = /* @__PURE__ */ new Map(); let counter = proxify(root, { changed: 0 }).proxy; let currentMeta = { contents: meta }; let register = (m2, cb2) => { let cbs = m2.changes; let cbs$1; let exit2 = 0; if (cbs == null) { exit2 = 1; } else { cbs$1 = cbs; } if (exit2 === 1) { let cbs$2 = /* @__PURE__ */ new Set(); m2.changes = cbs$2; cbs$1 = cbs$2; } cbs$1.add(cb2); return cbs$1; }; let drain = () => { let upsert = []; let remove = []; pending.forEach((v, k) => { if (v == null) { remove.push(k); } else { upsert.push(v); } pending.delete(k); }); return { upsert, remove }; }; let cb = (key, value) => { pending.set(key, value); counter.changed = counter.changed + 1 | 0; }; let currentCbs = { contents: register(meta, cb) }; let reregister = () => { let m2 = Reflect.get(accessor(), metaKey); if (m2 == null || m2 === currentMeta.contents) { return; } else { currentCbs.contents.delete(cb); currentCbs.contents = register(m2, cb); currentMeta.contents = m2; return; } }; let capture = guard !== void 0 ? () => { reregister(); if (guard()) { Reflect.get(counter, "changed"); if (pending.size > 0) { return drain(); } else { return empty; } } else { return empty; } } : () => { reregister(); Reflect.get(counter, "changed"); if (pending.size > 0) { return drain(); } else { return empty; } }; let mute = (fn) => { reregister(); currentCbs.contents.delete(cb); if (root.lock) { fn(); } else { root.lock = true; fn(); root.lock = false; flush(root); } currentCbs.contents.add(cb); }; return { changes: capture, mute }; } var tilia = _ctx.tilia; var carve = _ctx.carve; var observe = _ctx.observe; var watch = _ctx.watch; var batch = _ctx.batch; var signal = _ctx.signal; var derived = _ctx.derived; var source = _ctx.source; var store = _ctx.store; var _observe = _ctx._observe; function _meta(p) { return Reflect.get(p, metaKey); } //# sourceMappingURL=index.cjs.map