UNPKG

@empirica/core

Version:
458 lines (455 loc) 11.7 kB
import { error, trace, warn } from "./chunk-TIKLWCJI.js"; // src/shared/attributes.ts import { BehaviorSubject } from "rxjs"; var Attributes = class { constructor(attributesObs, donesObs, setAttributes) { this.setAttributes = setAttributes; this.attrs = /* @__PURE__ */ new Map(); this.updates = /* @__PURE__ */ new Map(); attributesObs.subscribe({ next: ({ attribute, removed }) => { this.update(attribute, removed); } }); donesObs.subscribe({ next: (scopeIDs) => { this.next(scopeIDs); } }); } attribute(scopeID, key) { let scopeMap = this.attrs.get(scopeID); if (!scopeMap) { scopeMap = /* @__PURE__ */ new Map(); this.attrs.set(scopeID, scopeMap); } let attr = scopeMap.get(key); if (!attr) { attr = new Attribute(this.setAttributes, scopeID, key); scopeMap.set(key, attr); } return attr; } attributes(scopeID) { let scopeMap = this.attrs.get(scopeID); if (!scopeMap) { scopeMap = /* @__PURE__ */ new Map(); this.attrs.set(scopeID, scopeMap); } return Array.from(scopeMap.values()); } attributePeek(scopeID, key) { let scopeUpdateMap = this.updates.get(scopeID); if (scopeUpdateMap) { const updated = scopeUpdateMap.get(key); if (updated) { if (typeof updated === "boolean") { return; } else { if (!updated.val) { return; } else { const attr2 = new Attribute(this.setAttributes, scopeID, key); attr2._update(updated); return attr2; } } } } let scopeMap = this.attrs.get(scopeID); if (!scopeMap) { return; } let attr = scopeMap.get(key); if (!attr) { return; } if (attr.value === void 0) { return; } return attr; } nextAttributeValue(scopeID, key) { const attr = this.attributePeek(scopeID, key); if (!attr) { return; } return attr.value; } update(attr, removed) { let nodeID = attr.nodeID; if (!nodeID) { if (!attr.node?.id) { error(`new attribute without node ID`); return; } nodeID = attr.node.id; } let scopeMap = this.updates.get(nodeID); if (!scopeMap) { scopeMap = /* @__PURE__ */ new Map(); this.updates.set(nodeID, scopeMap); } if (removed) { scopeMap.set(attr.key, true); } else { let key = attr.key; if (attr.index !== void 0 && attr.index !== null) { key = `${key}[${attr.index}]`; } scopeMap.set(key, attr); } } scopeWasUpdated(scopeID) { if (!scopeID) { return false; } return this.updates.has(scopeID); } next(scopeIDs) { for (const [scopeID, attrs] of this.updates) { if (!scopeIDs.includes(scopeID)) { continue; } let scopeMap = this.attrs.get(scopeID); if (!scopeMap) { scopeMap = /* @__PURE__ */ new Map(); this.attrs.set(scopeID, scopeMap); } for (const [key, attrOrDel] of attrs) { if (typeof attrOrDel === "boolean") { let attr = scopeMap.get(key); if (attr) { attr._update(void 0); } } else { let attr = scopeMap.get(attrOrDel.key); if (!attr) { attr = new Attribute(this.setAttributes, scopeID, attrOrDel.key); scopeMap.set(attrOrDel.key, attr); } attr._update(attrOrDel); } } } for (const scopeID of scopeIDs) { this.updates.delete(scopeID); } } }; var Attribute = class { constructor(setAttributes, scopeID, key) { this.setAttributes = setAttributes; this.scopeID = scopeID; this.key = key; this.val = new BehaviorSubject(void 0); } get id() { return this.attr?.id; } get createdAt() { return this.attr ? new Date(this.attr.createdAt) : null; } get obs() { return this.val; } get value() { return this.val.getValue(); } get nodeID() { return this.scopeID; } // items returns the attribute changes for the current attribute, if it is a // vector. Otherwise it returns null; get items() { if (!this.attrs) { return null; } return this.attrs; } set(value, ao) { const attrProps = this._prepSet(value, ao); if (!attrProps) { return; } this.setAttributes([attrProps]); trace(`SET ${this.key} = ${value} (${this.scopeID})`); } _prepSet(value, ao, item) { if (ao?.append !== void 0 && ao.index !== void 0) { error(`cannot set both append and index`); throw new Error(`cannot set both append and index`); } const serVal = JSON.stringify(value); if (!item && (ao?.index !== void 0 || ao?.append)) { let index = ao.index || 0; if (ao?.append) { index = this.attrs?.length || 0; } if (!this.attrs) { this.attrs = []; } if (!this.attrs[index]) { this.attrs[index] = new Attribute( this.setAttributes, this.scopeID, this.key ); } else { const existing = this.attrs[index]; if (existing && existing.serVal === serVal) { return; } } this.attrs[index]._prepSet(value, ao, true); const v = this._recalcVectorVal(); this.val.next(v); } else { if (this.serVal === serVal) { return; } this.val.next(value); } this.serVal = serVal; const attrProps = { key: this.key, nodeID: this.scopeID, val: serVal }; if (ao) { attrProps.private = ao.private; attrProps.protected = ao.protected; attrProps.immutable = ao.immutable; attrProps.ephemeral = ao.ephemeral; attrProps.append = ao.append; attrProps.index = ao.index; } return attrProps; } _recalcVectorVal() { return this.attrs.map( (a) => !a || a.val == void 0 ? null : a.value || null ); } // internal only _update(attr, item) { if (attr && this.attr && this.attr.id === attr.id) { return; } if (attr && attr.vector && !item) { if (attr.index === void 0) { error(`vector attribute missing index`); return; } if (this.attrs == void 0) { this.attrs = []; } while (this.attrs.length < attr.index + 1) { const newAttr2 = new Attribute( this.setAttributes, this.scopeID, this.key ); this.attrs.push(newAttr2); } const newAttr = new Attribute(this.setAttributes, this.scopeID, this.key); newAttr._update(attr, true); this.attrs[attr.index] = newAttr; const value2 = this._recalcVectorVal(); this.val.next(value2); return; } this.attr = attr; this.serVal = attr?.val === void 0 || attr?.val === null ? "" : attr.val; let value = void 0; if (this.attr?.val) { value = JSON.parse(this.attr.val); } this.val.next(value); } }; // src/shared/scopes.ts import { BehaviorSubject as BehaviorSubject2 } from "rxjs"; var Scopes = class { constructor(scopesObs, donesObs, ctx, kinds, attributes) { this.ctx = ctx; this.kinds = kinds; this.attributes = attributes; this.scopes = /* @__PURE__ */ new Map(); // newScopes is used to track scopes that have appeared for the first time. this.newScopes = /* @__PURE__ */ new Map(); this.scopesByKind = /* @__PURE__ */ new Map(); this.kindUpdated = /* @__PURE__ */ new Set(); scopesObs.subscribe({ next: ({ scope, removed }) => { this.update(scope, removed); } }); donesObs.subscribe({ next: (scopeIDs) => { this.next(scopeIDs); } }); } scope(id) { return this.scopes.get(id)?.getValue(); } scopeObs(id) { return this.scopes.get(id); } byKind(kind) { let map = this.scopesByKind.get(kind); if (!map) { map = /* @__PURE__ */ new Map(); this.scopesByKind.set(kind, map); } return map; } kindWasUpdated(kind) { return this.kindUpdated.has(kind); } next(scopeIDs) { this.kindUpdated.clear(); for (const [_, scopeSubject] of this.scopes) { const scope = scopeSubject.getValue(); if ((scope._updated || this.attributes.scopeWasUpdated(scope.id)) && scopeIDs.includes(scope.id)) { scope._updated = false; scopeSubject.next(scope); } } } update(scope, removed) { const existing = this.scopes.get(scope.id)?.getValue(); if (removed) { if (!existing) { warn("scopes: missing scope on removal", scope.id, scope.kind); return; } existing._deleted = true; existing._updated = true; this.scopes.delete(scope.id); if (!scope.kind) { warn("scopes: scope missing kind on scope on removal"); return; } const kind2 = scope.kind; this.scopesByKind.get(kind2).delete(scope.id); this.kindUpdated.add(kind2); return; } if (existing) { existing._deleted = false; return; } if (!scope.kind) { warn("scopes: scope missing kind on scope"); return; } const kind = scope.kind; const scopeClass = this.kinds[kind]; if (!scopeClass) { warn(`scopes: unknown scope kind: ${scope.kind}`); return; } const obj = this.create(scopeClass, scope); const subj = new BehaviorSubject2(obj); this.scopes.set(scope.id, subj); this.newScopes.set(scope.id, true); let skm = this.scopesByKind.get(kind); if (!skm) { skm = /* @__PURE__ */ new Map(); this.scopesByKind.set(kind, skm); } skm.set(scope.id, obj); obj._updated = true; this.kindUpdated.add(kind); } create(scopeClass, scope) { return new scopeClass(this.ctx, scope, this.attributes); } }; var Scope = class { constructor(ctx, scope, attributes) { this.ctx = ctx; this.scope = scope; this.attributes = attributes; /** * @internal */ this._deleted = false; /** * @internal */ this._updated = false; } get id() { return this.scope.id; } /** * @internal */ get kind() { return this.scope.kind; } get(key) { return this.attributes.attribute(this.scope.id, key).value; } getAttribute(key) { return this.attributes.attribute(this.scope.id, key); } obs(key) { return this.attributes.attribute(this.scope.id, key).obs; } set(keyOrAttributes, value, ao) { if (typeof keyOrAttributes === "string") { if (value === void 0) { value = null; } return this.attributes.attribute(this.scope.id, keyOrAttributes).set(value, ao); } const nextProps = []; for (const attr of keyOrAttributes) { const at = this.attributes.attribute(this.scope.id, attr.key)._prepSet(attr.value, attr.ao); if (!at) { continue; } nextProps.push(at); } if (nextProps.length === 0) { return; } this.attributes.setAttributes(nextProps); } append(key, value, ao) { if (!ao) { ao = {}; } ao.append = true; return this.attributes.attribute(this.scope.id, key).set(value, ao); } inspect() { const attrs = this.attributes.attributes(this.scope.id); const out = {}; for (const attr of attrs) { out[attr.key] = attr.value; } return out; } /** * @internal */ hasUpdated() { return this._updated || this.attributes.scopeWasUpdated(this.id); } }; export { Attributes, Attribute, Scopes, Scope }; //# sourceMappingURL=chunk-RXGVZSIF.js.map