UNPKG

@tko/computed

Version:

TKO Computed Observables

97 lines (96 loc) 2.61 kB
// @tko/computed 🥊 4.0.0-beta1.3 ESM import { observable, observableArray, unwrap } from "@tko/observable"; import { computed } from "./computed"; const PROXY_SYM = Symbol("Knockout Proxied Object"); const MIRROR_SYM = Symbol("Knockout Proxied Observables"); function makeComputed(proxy2, fn) { return computed({ owner: proxy2, read: fn, write: fn, pure: "pure" in fn ? fn.pure : true, deferEvaluation: "deferEvaluation" in fn ? fn.deferEvaluation : true }).extend({ deferred: true }); } function setOrCreate(mirror, prop, value, proxy2) { if (!mirror[prop]) { const ctr = Array.isArray(value) ? observableArray : typeof value === "function" ? makeComputed.bind(null, proxy2) : observable; mirror[prop] = ctr(value); } else { mirror[prop](value); } } function assignOrUpdate(mirror, object, proxy2) { for (const key of Object.keys(object)) { setOrCreate(mirror, key, object[key], proxy2); } return object; } export function proxy(object) { const mirror = { [PROXY_SYM]: object }; mirror[MIRROR_SYM] = mirror; const proxy2 = new Proxy(function() { }, { has(target, prop) { return prop in mirror; }, get(target, prop) { return unwrap(mirror[prop]); }, set(target, prop, value, receiver) { setOrCreate(mirror, prop, value, proxy2); object[prop] = value; return true; }, deleteProperty(property) { delete mirror[property]; return delete object[property]; }, apply(target, thisArg, [props]) { if (props) { assignOrUpdate(mirror, props, proxy2); return Object.assign(object, props); } return object; }, getPrototypeOf() { return Object.getPrototypeOf(object); }, setPrototypeOf(target, proto) { return Object.setPrototypeOf(object, proto); }, defineProperty(target, prop, desc) { return Object.defineProperty(object, prop, desc); }, preventExtensions() { return Object.preventExtensions(object); }, isExtensible() { return Object.isExtensible(object); }, ownKeys() { return [ ...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object) ]; } }); assignOrUpdate(mirror, object, proxy2); return proxy2; } export function getObservable(proxied, prop) { return proxied[MIRROR_SYM][prop]; } export function peek(proxied, prop) { return getObservable(proxied, prop).peek(); } export function isProxied(proxied) { return PROXY_SYM in proxied; } Object.assign(proxy, { getObservable, peek, isProxied });