mobx-bonsai
Version:
A fast lightweight alternative to MobX-State-Tree + Y.js two-way binding
1,587 lines • 349 kB
JavaScript
var __defProp = Object.defineProperty;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var _a, _b, _c, _d, _e, _f, _undoAction, _redoAction, _g;
import * as mobx from "mobx";
import { isObservableArray, isObservableMap, isObservableSet, isObservableObject, remove, set, action, createAtom, toJS, observable, intercept, observe, computed, reaction, runInAction, transaction, untracked, keys, get, has, entries, values, _getGlobalState, when, isObservable } from "mobx";
class MobxBonsaiError extends Error {
constructor(msg) {
super(msg);
Object.setPrototypeOf(this, MobxBonsaiError.prototype);
}
}
function mitt(n) {
return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
var i = n.get(t);
i ? i.push(e) : n.set(t, [e]);
}, off: function(t, e) {
var i = n.get(t);
i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []));
}, emit: function(t, e) {
var i = n.get(t);
i && i.slice().map(function(n2) {
n2(e);
}), (i = n.get("*")) && i.slice().map(function(n2) {
n2(t, e);
});
} };
}
function failure(msg) {
return new MobxBonsaiError(msg);
}
let urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
let nanoid = (size = 21) => {
let id = "";
let i = size | 0;
while (i--) {
id += urlAlphabet[Math.random() * 64 | 0];
}
return id;
};
let localId = 0;
const localBaseId = nanoid();
const defaultNodeKeyGenerator = () => {
const id = localId.toString(36) + "-" + localBaseId;
localId++;
return id;
};
let globalConfig = {
keyGenerator: defaultNodeKeyGenerator,
checkCircularReferences: false
};
function getGlobalConfig() {
return globalConfig;
}
function disposeOnce(fn) {
let disposed = false;
return (...args) => {
if (disposed) {
return;
}
disposed = true;
fn(...args);
};
}
function getDefaultExportFromCjs(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
var deepFreeze$1;
var hasRequiredDeepFreeze;
function requireDeepFreeze() {
if (hasRequiredDeepFreeze) return deepFreeze$1;
hasRequiredDeepFreeze = 1;
deepFreeze$1 = function deepFreeze2(o) {
Object.freeze(o);
Object.getOwnPropertyNames(o).forEach(function(prop) {
if (o.hasOwnProperty(prop) && o[prop] !== null && (typeof o[prop] === "object" || typeof o[prop] === "function") && !Object.isFrozen(o[prop])) {
deepFreeze2(o[prop]);
}
});
return o;
};
return deepFreeze$1;
}
var deepFreezeExports = requireDeepFreeze();
const deepFreeze = /* @__PURE__ */ getDefaultExportFromCjs(deepFreezeExports);
function isPrimitive(v) {
const t = typeof v;
return t === "string" || t === "number" || t === "boolean" || v === null || v === void 0;
}
function isObject(value) {
return value !== null && typeof value === "object";
}
function assertIsObject(value, argName) {
if (!isObject(value)) {
throw failure(`${argName} must be an object`);
}
}
function isPlainObject(v) {
return isObject(v) && v.constructor === Object;
}
function isArray(v) {
return Array.isArray(v) || isObservableArray(v);
}
function isMap(val) {
return val instanceof Map || isObservableMap(val);
}
function isSet(val) {
return val instanceof Set || isObservableSet(val);
}
function isObservablePlainStructure(target) {
return isObservableObject(target) || isObservableArray(target);
}
function assertIsObservablePlainStructure(target, argName) {
const valid = isObservablePlainStructure(target);
if (!valid) {
throw failure(`${argName} must be an observable object or array`);
}
}
function assertIsFunction(value, argName) {
if (typeof value !== "function") {
throw failure(`${argName} must be a function`);
}
}
const inDevMode = process.env.NODE_ENV !== "production";
function setIfDifferent(target, key, value) {
if (target[key] !== value || !(key in target)) {
set(target, key, value);
}
}
function reconcileData(oldValue, newValue, reconciliationRoot) {
var _a2, _b2;
if (oldValue === newValue) {
return oldValue;
}
if (isPrimitive(newValue) || isPrimitive(oldValue)) {
return newValue;
}
const oldIsArray = isArray(oldValue);
const newIsArray = isArray(newValue);
if (oldIsArray !== newIsArray) {
return newValue;
}
if (newIsArray) {
const oldArray = oldValue;
const newArray = newValue;
if (oldArray.length > newArray.length) {
oldArray.splice(newArray.length, oldArray.length - newArray.length);
}
for (let i = 0; i < oldArray.length; i++) {
const oldV = oldArray[i];
const newV = reconcileData(oldV, newArray[i]);
setIfDifferent(oldArray, i, newV);
}
for (let i = oldArray.length; i < newArray.length; i++) {
oldArray.push(reconcileData(void 0, newArray[i]));
}
return oldArray;
} else if (isMap(newValue)) {
throw failure("a value must not contain maps");
} else if (isSet(newValue)) {
throw failure("a value must not contain sets");
} else {
const oldObject = oldValue;
const newObject = newValue;
const newNodeTypeAndKey = getNodeTypeAndKey(newObject);
const oldNodeTypeAndKey = getNodeTypeAndKey(oldObject);
if (newNodeTypeAndKey.type !== oldNodeTypeAndKey.type || newNodeTypeAndKey.key !== oldNodeTypeAndKey.key) {
return newValue;
}
if (((_a2 = newNodeTypeAndKey.type) == null ? void 0 : _a2.isFrozen) || ((_b2 = oldNodeTypeAndKey.type) == null ? void 0 : _b2.isFrozen)) {
return newValue;
}
const oldObjectKeys = Object.keys(oldObject);
const oldObjectKeysLen = oldObjectKeys.length;
for (let i = 0; i < oldObjectKeysLen; i++) {
const k = oldObjectKeys[i];
if (!(k in newObject)) {
remove(oldObject, k);
}
}
const newObjectKeys = Object.keys(newObject);
const newObjectKeysLen = newObjectKeys.length;
for (let i = 0; i < newObjectKeysLen; i++) {
const k = newObjectKeys[i];
const v = newObject[k];
const oldV = oldObject[k];
const newV = reconcileData(oldV, v);
setIfDifferent(oldObject, k, newV);
}
return oldObject;
}
}
function getParentPath(node2) {
const nodeData = getNodeData(node2);
const ret = nodeData.parent ? { parent: nodeData.parent.object, path: nodeData.parent.path } : void 0;
reportNodeParentObserved(node2);
return ret;
}
const snapshots = /* @__PURE__ */ new WeakMap();
const snapshotAtoms = /* @__PURE__ */ new WeakMap();
const invalidateSnapshotTreeToRoot = action((node2) => {
var _a2, _b2;
assertIsNode(node2, "node");
let current = node2;
while (current) {
const hadSnapshot = snapshots.delete(current);
if (!hadSnapshot) {
break;
}
(_a2 = snapshotAtoms.get(current)) == null ? void 0 : _a2.reportChanged();
current = (_b2 = getParentPath(current)) == null ? void 0 : _b2.parent;
}
});
const createSnapshot = action((node2) => {
assertIsNode(node2, "node");
if (isFrozenNode(node2)) {
return node2;
}
if (isObservableArray(node2)) {
return node2.map((v) => getSnapshotOrPrimitive(v, true));
}
if (isObservableObject(node2)) {
const obj = {};
Object.entries(node2).forEach(([key, v]) => {
obj[key] = getSnapshotOrPrimitive(v, true);
});
return obj;
}
throw failure(`only observable objects, observable arrays and primitives are supported`);
});
function getSnapshotOrPrimitive(value, acceptPrimitives) {
if (acceptPrimitives && isPrimitive(value)) {
return value;
}
const node2 = value;
assertIsNode(node2, "value");
let existingSnapshot = snapshots.get(node2);
if (!existingSnapshot) {
existingSnapshot = createSnapshot(node2);
snapshots.set(node2, existingSnapshot);
}
let atom = snapshotAtoms.get(node2);
if (!atom) {
atom = createAtom("snapshot");
snapshotAtoms.set(node2, atom);
}
atom.reportObserved();
return existingSnapshot;
}
function getSnapshot(node2) {
return getSnapshotOrPrimitive(node2, false);
}
function getParent(node2) {
var _a2;
return (_a2 = getParentPath(node2)) == null ? void 0 : _a2.parent;
}
function buildNodeFullPath(node2, subPath) {
const fullPath = [];
let current = node2;
while (current) {
const parent = getParentPath(current);
if (parent) {
fullPath.push(parent.path);
}
current = parent == null ? void 0 : parent.parent;
}
fullPath.reverse();
if (subPath) {
fullPath.push(subPath);
}
return fullPath;
}
function getNodeData(node2) {
assertIsNode(node2, "node");
return nodes.get(node2);
}
function reportNodeParentObserved(node2) {
const data = getNodeData(node2);
if (!data.parentAtom) {
data.parentAtom = createAtom("parent");
}
data.parentAtom.reportObserved();
}
const nodes = /* @__PURE__ */ new WeakMap();
function setParentNode(node2, parentNode) {
var _a2;
const nodeData = getNodeData(node2);
const oldParent = nodeData.parent;
if (oldParent && !parentNode) {
if (shouldHaveChangeListeners(oldParent.object)) {
decrementAncestorChangeListenerRefCount(node2);
}
} else if (!oldParent && parentNode) {
if (shouldHaveChangeListeners(parentNode.object)) {
incrementAncestorChangeListenerRefCount(node2);
}
} else if (oldParent && parentNode && oldParent.object !== parentNode.object) {
throw failure(
"assertion failed: node moved from one parent to another without being detached first"
);
}
nodeData.parent = parentNode;
(_a2 = nodeData.parentAtom) == null ? void 0 : _a2.reportChanged();
}
function isNode(struct) {
return nodes.has(struct);
}
function isFrozenNode(node2) {
return getNodeData(node2).frozen;
}
function assertIsNode(node2, argName) {
if (!isNode(node2)) {
throw failure(`${argName} must be a mobx-bonsai node`);
}
}
function emitToListeners(listeners, change) {
if (listeners && listeners.length > 0) {
listeners.forEach((listener) => {
listener(change);
});
}
}
function emitChangeToRoot(eventTarget, change) {
let currentTarget = eventTarget;
while (currentTarget) {
const changeListeners = getNodeData(currentTarget).onChangeListeners;
emitToListeners(changeListeners, change);
currentTarget = getParent(currentTarget);
}
}
function emitInterceptedChangeToRoot(eventTarget, change) {
let currentChange = change;
let currentTarget = eventTarget;
while (currentTarget) {
const interceptedChangeListeners = getNodeData(currentTarget).onInterceptedChangeListeners;
if (interceptedChangeListeners && interceptedChangeListeners.length > 0) {
for (const listener of interceptedChangeListeners) {
const result = listener(currentChange);
if (result === void 0) {
throw failure(
"onDeepInterceptedChange listener must return either the change object or null, but returned undefined"
);
}
if (result === null) {
return null;
}
currentChange = result;
}
}
currentTarget = getParent(currentTarget);
}
return currentChange;
}
function registerListener(node2, listener, listenersProperty) {
const nodeData = getNodeData(node2);
let listeners = nodeData[listenersProperty];
const wasEmpty = !listeners || listeners.length === 0;
if (!listeners) {
listeners = [];
nodeData[listenersProperty] = listeners;
}
listeners.push(listener);
if (wasEmpty && listenersProperty === "onChangeListeners") {
incrementAncestorChangeListenerRefCount(node2);
}
return disposeOnce(() => {
const currentListeners = nodeData[listenersProperty];
if (currentListeners) {
const index = currentListeners.indexOf(listener);
if (index !== -1) {
currentListeners.splice(index, 1);
const isEmpty = currentListeners.length === 0;
if (isEmpty) {
nodeData[listenersProperty] = void 0;
if (listenersProperty === "onChangeListeners") {
decrementAncestorChangeListenerRefCount(node2);
}
}
}
}
});
}
function onDeepInterceptedChange(node2, listener) {
return registerListener(node2, listener, "onInterceptedChangeListeners");
}
function onDeepChange(node2, listener) {
return registerListener(node2, listener, "onChangeListeners");
}
function attachObserveHook(node2) {
const nodeData = getNodeData(node2);
if (!nodeData.observeDisposer) {
nodeData.observeDisposer = observe(node2, (change) => {
emitChangeToRoot(node2, change);
});
}
}
function detachObserveHook(node2) {
const nodeData = getNodeData(node2);
if (nodeData.observeDisposer) {
nodeData.observeDisposer();
nodeData.observeDisposer = void 0;
}
}
function incrementAncestorChangeListenerRefCount(node2) {
const nodeData = getNodeData(node2);
if (nodeData.frozen) {
return;
}
nodeData.ancestorChangeListenerRefCount++;
if (nodeData.ancestorChangeListenerRefCount === 1) {
attachObserveHook(node2);
}
if (nodeData.childrenObjects) {
nodeData.childrenObjects.forEach((child) => {
incrementAncestorChangeListenerRefCount(child);
});
}
}
function decrementAncestorChangeListenerRefCount(node2) {
const nodeData = getNodeData(node2);
if (nodeData.frozen) {
return;
}
nodeData.ancestorChangeListenerRefCount--;
if (nodeData.ancestorChangeListenerRefCount === 0) {
detachObserveHook(node2);
}
if (nodeData.childrenObjects) {
nodeData.childrenObjects.forEach((child) => {
decrementAncestorChangeListenerRefCount(child);
});
}
}
function shouldHaveChangeListeners(node2) {
return getNodeData(node2).ancestorChangeListenerRefCount > 0;
}
let detachDuplicatedNodes = 0;
const runDetachingDuplicatedNodes = (fn) => {
detachDuplicatedNodes++;
try {
fn();
} finally {
detachDuplicatedNodes--;
}
};
const node = action(
(struct, options) => {
var _a2;
if (isNode(struct)) {
return struct;
}
const { type, key } = getNodeTypeAndKey(struct);
const keyProp = type && "key" in type ? type.key : void 0;
if (type !== void 0 && key !== void 0) {
const existingNode = "findByKey" in type ? type.findByKey(key) : void 0;
if (existingNode) {
const result = reconcileData(existingNode, struct);
if (result !== existingNode) {
throw failure("reconciliation should not create a new object");
}
return existingNode;
}
}
const frozen = type && "isFrozen" in type ? type.isFrozen : false;
const nodeData = {
parent: void 0,
parentAtom: void 0,
onChangeListeners: void 0,
onInterceptedChangeListeners: void 0,
childrenObjects: void 0,
frozen,
observeDisposer: void 0,
ancestorChangeListenerRefCount: 0
};
let nodeStruct;
const registerNode = () => {
if (!nodeStruct) {
throw failure("nodeStruct is not defined");
}
nodes.set(nodeStruct, nodeData);
tryRegisterNodeByTypeAndKey(nodeStruct);
};
if (frozen) {
const plainStruct = toJS(struct);
if (inDevMode) {
deepFreeze(plainStruct);
}
nodeStruct = plainStruct;
registerNode();
} else {
const observableStruct = (() => {
if (isObservablePlainStructure(struct)) {
return struct;
}
return Array.isArray(struct) ? observable.array(struct, { deep: false }) : observable.object(struct, void 0, { deep: false });
})();
nodeStruct = observableStruct;
registerNode();
const attachAsChildNode = (v, path, setIfConverted) => {
if (isPrimitive(v)) {
return;
}
let n = v;
if (isNode(n)) {
const parent = getNodeData(n).parent;
if (parent && (parent.object !== observableStruct || parent.path !== path)) {
if (detachDuplicatedNodes > 0) {
set(parent.object, parent.path, void 0);
} else {
throw failure(
`The same node cannot appear twice in the same or different trees, trying to assign it to ${JSON.stringify(buildNodeFullPath(observableStruct, path))}, but it already exists at ${JSON.stringify(buildNodeFullPath(parent.object, parent.path))}. If you are moving the node then remove it from the tree first before moving it. If you are copying the node then use 'clone' to make a clone first.`
);
}
}
} else {
n = node(v);
const parent = getNodeData(n).parent;
if (parent && (parent.object !== observableStruct || parent.path !== path)) {
set(parent.object, parent.path, void 0);
}
if (n !== v) {
setIfConverted(n);
}
}
if (!nodeData.childrenObjects) {
nodeData.childrenObjects = observable.set([], { deep: false });
}
nodeData.childrenObjects.add(n);
setParentNode(n, { object: observableStruct, path });
};
const detachAsChildNode = (v) => {
if (!isPrimitive(v) && isNode(v)) {
setParentNode(v, void 0);
if (nodeData.childrenObjects) {
nodeData.childrenObjects.delete(v);
}
}
};
const isArrayNode = isArray(observableStruct);
if (isArrayNode) {
const array = observableStruct;
array.forEach((v, i) => {
attachAsChildNode(v, i.toString(), (n) => {
set(array, i, n);
});
});
} else {
const object = observableStruct;
Object.entries(object).forEach(([key2, v]) => {
attachAsChildNode(v, key2, (n) => {
set(object, key2, n);
});
});
}
if (isArrayNode) {
const array = observableStruct;
intercept(array, (change) => {
const wrappedChange = emitInterceptedChangeToRoot(array, change);
if (wrappedChange === null) {
return null;
}
let changed = false;
switch (change.type) {
case "update": {
const oldValue = array[change.index];
changed = oldValue !== change.newValue;
if (changed) {
detachAsChildNode(oldValue);
attachAsChildNode(change.newValue, "" + change.index, (n) => {
change.newValue = n;
});
}
break;
}
case "splice": {
for (let i = 0; i < change.removedCount; i++) {
const removedValue = array[change.index + i];
detachAsChildNode(removedValue);
}
for (let i = 0; i < change.added.length; i++) {
attachAsChildNode(change.added[i], "" + (change.index + i), (n) => {
change.added[i] = n;
});
}
changed = change.removedCount > 0 || change.added.length > 0;
const oldNextIndex = change.index + change.removedCount;
const newNextIndex = change.index + change.added.length;
if (oldNextIndex !== newNextIndex) {
for (let i = oldNextIndex, j = newNextIndex; i < array.length; i++, j++) {
const value = array[i];
if (isPrimitive(value)) {
continue;
}
if (!isNode(value)) {
throw failure("node expected");
}
setParentNode(
value,
{
object: array,
path: "" + j
}
// parentPath
);
}
}
break;
}
default:
throw failure(`unsupported change type`);
}
if (changed) {
invalidateSnapshotTreeToRoot(observableStruct);
return change;
}
return null;
});
} else {
const object = observableStruct;
intercept(object, (change) => {
const wrappedChange = emitInterceptedChangeToRoot(object, change);
if (wrappedChange === null) {
return null;
}
if (typeof change.name === "symbol") {
throw failure("symbol keys are not supported on a mobx-bonsai node");
}
const propKey = "" + change.name;
if (propKey === nodeTypeKey || keyProp !== void 0 && propKey === keyProp) {
throw failure(`the property ${change.name} cannot be modified`);
}
let changed = false;
switch (change.type) {
case "add": {
changed = true;
attachAsChildNode(change.newValue, propKey, (n) => {
change.newValue = n;
});
break;
}
case "update": {
const oldValue = object[propKey];
changed = oldValue !== change.newValue;
if (changed) {
detachAsChildNode(oldValue);
attachAsChildNode(change.newValue, propKey, (n) => {
change.newValue = n;
});
}
break;
}
case "remove": {
changed = true;
const oldValue = object[propKey];
detachAsChildNode(oldValue);
break;
}
default:
throw failure(`unsupported change type`);
}
if (changed) {
invalidateSnapshotTreeToRoot(observableStruct);
return change;
}
return null;
});
}
}
const skipInit = (_a2 = options == null ? void 0 : options.skipInit) != null ? _a2 : false;
if (!skipInit) {
type == null ? void 0 : type._initNode(nodeStruct);
}
return nodeStruct;
}
);
function volatileProp(defaultValueGen) {
const volatileValueAdmins = /* @__PURE__ */ new WeakMap();
const getOrCreateValueAdmin = (target) => {
let valueAdmin = volatileValueAdmins.get(target);
if (!valueAdmin) {
const initialValue = defaultValueGen();
valueAdmin = {
valueBox: observable.box(initialValue, { deep: false }),
initialValue
};
volatileValueAdmins.set(target, valueAdmin);
}
return valueAdmin;
};
const vProp = [
(target) => {
assertIsObservablePlainStructure(target, "target");
const valueAdmin = getOrCreateValueAdmin(target);
return valueAdmin.valueBox.get();
},
action((target, value) => {
assertIsObservablePlainStructure(target, "target");
const valueAdmin = getOrCreateValueAdmin(target);
valueAdmin.valueBox.set(value);
}),
action((target) => {
assertIsObservablePlainStructure(target, "target");
const valueAdmin = volatileValueAdmins.get(target);
if (valueAdmin) {
valueAdmin.valueBox.set(valueAdmin.initialValue);
}
})
];
return vProp;
}
const nodeTypeKey = "$$type";
const nodeByTypeAndKey = /* @__PURE__ */ new Map();
const finalizationRegistry = new FinalizationRegistry(
({ typeId, key }) => {
const typeMap = nodeByTypeAndKey.get(typeId);
if (!typeMap) {
return;
}
const ref = typeMap.get(key);
if (!ref) {
return;
}
if (ref.deref()) {
return;
}
typeMap.delete(key);
if (typeMap.size === 0) {
nodeByTypeAndKey.delete(typeId);
}
}
);
function tryRegisterNodeByTypeAndKey(node2) {
assertIsNode(node2, "node");
const { type, key } = getNodeTypeAndKey(node2);
if (type === void 0 || key === void 0) {
return false;
}
const { typeId } = type;
let typeMap = nodeByTypeAndKey.get(typeId);
if (!typeMap) {
typeMap = /* @__PURE__ */ new Map();
nodeByTypeAndKey.set(typeId, typeMap);
}
typeMap.set(key, new WeakRef(node2));
finalizationRegistry.register(node2, { typeId, key });
return true;
}
const registeredNodeTypes = /* @__PURE__ */ new Map();
function findNodeTypeById(typeId) {
return registeredNodeTypes.get(typeId);
}
function getNodeTypeId(node2) {
return node2[nodeTypeKey];
}
function getNodeTypeAndKey(node2) {
const typeValue = getNodeTypeId(node2);
if (typeValue === void 0) {
return {
type: void 0,
key: void 0
};
}
const type = findNodeTypeById(typeValue);
if (type === void 0) {
throw failure(`a node with type '${typeValue}' was found, but such type is not registered`);
}
return {
type,
key: "getKey" in type ? type.getKey(node2) : void 0
};
}
function nodeType(type) {
return type !== void 0 ? typedNodeType(type) : untypedNodeType();
}
function addNodeTypeExtensionMethods(nodeTypeObj) {
const addKey = (key, value) => {
nodeTypeObj[key] = value;
nodeTypeObj._extendsKeys.add(key);
};
nodeTypeObj.volatile = (volatiles) => {
for (const volatileKey of Object.keys(volatiles)) {
const defaultValueGen = volatiles[volatileKey];
const [getter, setter, resetter] = volatileProp(defaultValueGen);
const capitalizedVolatileKey = volatileKey.charAt(0).toUpperCase() + volatileKey.slice(1);
addKey(`get${capitalizedVolatileKey}`, getter);
addKey(`set${capitalizedVolatileKey}`, setter);
addKey(`reset${capitalizedVolatileKey}`, resetter);
}
return nodeTypeObj;
};
nodeTypeObj.actions = (actions) => {
for (const key of Object.keys(actions)) {
addKey(
key,
action((n, ...args) => actions[key].apply(n, args))
);
}
return nodeTypeObj;
};
nodeTypeObj.getters = (getters) => {
for (const key of Object.keys(getters)) {
addKey(key, (n, ...args) => getters[key].apply(n, args));
}
return nodeTypeObj;
};
nodeTypeObj.computeds = (computeds) => {
const cachedComputedsByNode = /* @__PURE__ */ new WeakMap();
function getOrCreateNodeCachedComputed(n, key) {
let nodeCachedComputeds = cachedComputedsByNode.get(n);
if (!nodeCachedComputeds) {
nodeCachedComputeds = /* @__PURE__ */ new Map();
cachedComputedsByNode.set(n, nodeCachedComputeds);
}
let cachedComputed = nodeCachedComputeds.get(key);
if (!cachedComputed) {
const value = computeds[key];
if (typeof value === "function") {
cachedComputed = computed(() => value.call(n));
} else if (typeof value === "object" && "get" in value && typeof value.get === "function") {
const options = { ...value, get: void 0 };
cachedComputed = computed(() => value.get.call(n), options);
} else {
throw failure(
`computed property '${key}' must be a function or a configuration object with a 'get' method`
);
}
nodeCachedComputeds.set(key, cachedComputed);
}
return cachedComputed;
}
for (const key of Object.keys(computeds)) {
addKey(key, (n) => getOrCreateNodeCachedComputed(n, key).get());
}
return nodeTypeObj;
};
nodeTypeObj.settersFor = (...properties) => {
for (const prop of properties) {
const capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1);
addKey(
`set${capitalizedProp}`,
action((node2, value) => {
set(node2, prop, value);
})
);
}
return nodeTypeObj;
};
nodeTypeObj.defaults = (defaultGenerators) => {
nodeTypeObj.defaultGenerators = {
...nodeTypeObj.defaultGenerators,
...defaultGenerators
};
return nodeTypeObj;
};
nodeTypeObj.extends = (otherNodeType) => {
if ("typeId" in otherNodeType && otherNodeType.typeId !== void 0) {
throw failure(`cannot extend from a typed node type`);
}
for (const key of otherNodeType._extendsKeys) {
if (!(key in otherNodeType)) {
throw failure(
`assertion error: '${key}' was expected to be in the extended node type, but it was not found`
);
}
if (key in nodeTypeObj) {
throw failure(
`cannot extend from node type since the current key '${key}' would be overwritten`
);
}
addKey(key, otherNodeType[key]);
}
if (otherNodeType.defaultGenerators) {
nodeTypeObj.defaults(otherNodeType.defaultGenerators);
}
return nodeTypeObj;
};
}
function applyDefaultGenerators(data, defaultGenerators) {
if (!defaultGenerators) {
return data;
}
if (typeof data !== "object" || data === null) {
throw failure(`data must be an object`);
}
const copy = { ...data };
for (const [key, gen] of Object.entries(defaultGenerators)) {
if (copy[key] === void 0) {
copy[key] = gen();
}
}
return copy;
}
function typedNodeType(type) {
if (type && registeredNodeTypes.has(type)) {
throw failure(`node type '${type}' is already registered`);
}
const events = mitt();
const snapshot = (data) => {
let sn = applyDefaultGenerators(data, nodeTypeObj.defaultGenerators);
if (data === sn) {
sn = {
...data,
[nodeTypeKey]: type
};
} else {
sn[nodeTypeKey] = type;
}
if (keyedNodeTypeObj.key !== void 0) {
const key = keyedNodeTypeObj.getKey(sn);
if (key === void 0) {
sn[keyedNodeTypeObj.key] = getGlobalConfig().keyGenerator();
}
}
return sn;
};
const nodeTypeObj = (data) => {
return node(snapshot(data));
};
const keyedNodeTypeObj = nodeTypeObj;
nodeTypeObj._extendsKeys = /* @__PURE__ */ new Set();
nodeTypeObj.snapshot = snapshot;
nodeTypeObj.typeId = type;
nodeTypeObj.isFrozen = false;
nodeTypeObj.frozen = () => {
nodeTypeObj.isFrozen = true;
return nodeTypeObj;
};
nodeTypeObj.withKey = (key) => {
if (keyedNodeTypeObj.key !== void 0) {
throw failure(`node type already has a key`);
}
keyedNodeTypeObj.key = key;
keyedNodeTypeObj.getKey = (node2) => {
return keyedNodeTypeObj.key === void 0 ? void 0 : node2[keyedNodeTypeObj.key];
};
keyedNodeTypeObj.findByKey = (key2) => {
const typeMap = nodeByTypeAndKey.get(type);
if (!typeMap) {
return void 0;
}
const ref = typeMap.get(key2);
return ref == null ? void 0 : ref.deref();
};
keyedNodeTypeObj.defaults({
[key]: () => getGlobalConfig().keyGenerator()
});
return keyedNodeTypeObj;
};
nodeTypeObj.nodeIsOfType = (node2) => {
return isNode(node2) && node2[nodeTypeKey] === type;
};
nodeTypeObj.unregister = disposeOnce(() => {
registeredNodeTypes.delete(type);
});
nodeTypeObj[Symbol.dispose] = () => {
nodeTypeObj.unregister();
};
nodeTypeObj._addOnInit = (callback) => {
const actionCallback = action(callback);
events.on("init", actionCallback);
return disposeOnce(() => {
events.off("init", actionCallback);
});
};
nodeTypeObj.onInit = (callback) => {
nodeTypeObj._addOnInit(callback);
return nodeTypeObj;
};
nodeTypeObj._initNode = (node2) => {
events.emit("init", node2);
};
addNodeTypeExtensionMethods(nodeTypeObj);
registeredNodeTypes.set(type, nodeTypeObj);
return nodeTypeObj;
}
function onInit(nodeType2, callback) {
return nodeType2._addOnInit(callback);
}
function untypedNodeType() {
const snapshot = (data) => applyDefaultGenerators(data, nodeTypeObj.defaultGenerators);
const nodeTypeObj = (data) => node(snapshot(data));
nodeTypeObj._extendsKeys = /* @__PURE__ */ new Set();
nodeTypeObj.snapshot = snapshot;
addNodeTypeExtensionMethods(nodeTypeObj);
return nodeTypeObj;
}
function computedProp(fn, options) {
const computedFns = /* @__PURE__ */ new WeakMap();
const getFn = (obj) => {
if (!isObservablePlainStructure(obj)) {
return fn(obj);
}
let computedFn = computedFns.get(obj);
if (!computedFn) {
computedFn = computed(() => fn(obj), options);
computedFns.set(obj, computedFn);
}
return computedFn.get();
};
getFn.getComputedFor = (obj) => computedFns.get(obj);
return getFn;
}
function getChildrenNodesWithTargetSet(node2, targetSet) {
getShallowChildren(node2).forEach((child) => {
targetSet.add(child);
const deepChildren = getComputedDeepChildren(child);
deepChildren.forEach((deepChild) => {
targetSet.add(deepChild);
});
});
}
const getShallowChildren = (node2) => {
const nodeData = getNodeData(node2);
if (!nodeData.childrenObjects) {
nodeData.childrenObjects = observable.set([], { deep: false });
}
return nodeData.childrenObjects;
};
const getComputedDeepChildren = computedProp((node2) => {
const children = /* @__PURE__ */ new Set();
getChildrenNodesWithTargetSet(node2, children);
return children;
});
function getChildrenNodes(node2, options) {
var _a2;
assertIsNode(node2, "node");
const deep = (_a2 = options == null ? void 0 : options.deep) != null ? _a2 : false;
if (!deep) {
return getShallowChildren(node2);
}
return getComputedDeepChildren(node2);
}
function findChildren(root, predicate, options) {
const children = getChildrenNodes(root, options);
const set2 = /* @__PURE__ */ new Set();
const iter = children.values();
let cur = iter.next();
while (!cur.done) {
if (predicate(cur.value)) {
set2.add(cur.value);
}
cur = iter.next();
}
return set2;
}
function findParentPath(child, predicate, maxDepth = 0) {
assertIsNode(child, "child");
const path = [];
let current = child;
let depth = 0;
let parentPath;
while (parentPath = getParentPath(current)) {
path.unshift(parentPath.path);
current = parentPath.parent;
if (predicate(current)) {
return {
parent: current,
path
};
}
depth++;
if (maxDepth > 0 && depth === maxDepth) {
break;
}
}
return void 0;
}
function findParent(child, predicate, maxDepth = 0) {
const foundParentPath = findParentPath(child, predicate, maxDepth);
return foundParentPath ? foundParentPath.parent : void 0;
}
function getParentToChildPath(fromParent, toChild) {
assertIsNode(fromParent, "fromParent");
assertIsNode(toChild, "toChild");
if (fromParent === toChild) {
return [];
}
const path = [];
let current = toChild;
let parentPath;
while (parentPath = getParentPath(current)) {
path.unshift(parentPath.path);
current = parentPath.parent;
if (current === fromParent) {
return path;
}
}
return void 0;
}
function getRootPath(node2) {
assertIsNode(node2, "node");
let root = node2;
const path = [];
const pathObjects = [node2];
let parentPath;
while (parentPath = getParentPath(root)) {
root = parentPath.parent;
path.unshift(parentPath.path);
pathObjects.unshift(parentPath.parent);
}
const rootPath = { root, path, pathObjects };
return rootPath;
}
function getRoot(node2) {
return getRootPath(node2).root;
}
function isChildOfParent(child, parent) {
assertIsNode(child, "child");
assertIsNode(parent, "parent");
let currentParent = getParent(child);
while (currentParent) {
if (currentParent === parent) {
return true;
}
currentParent = getParent(currentParent);
}
return false;
}
function isParentOfChild(parent, child) {
return isChildOfParent(child, parent);
}
function isRoot(node2) {
return !getParent(node2);
}
function onChildAttachedTo({
target,
childNodeType,
onChildAttached,
deep,
fireForCurrentChildren
}) {
assertIsFunction(target, "target");
assertIsFunction(onChildAttached, "onChildAttached");
deep != null ? deep : deep = false;
fireForCurrentChildren != null ? fireForCurrentChildren : fireForCurrentChildren = true;
const convertToChildNodeTypeSet = () => {
if (!childNodeType) {
return void 0;
}
return new Set(Array.isArray(childNodeType) ? childNodeType : [childNodeType]);
};
const childNodeTypeSet = convertToChildNodeTypeSet();
const detachDisposers = /* @__PURE__ */ new WeakMap();
const runDetachDisposer = (n) => {
const detachDisposer = detachDisposers.get(n);
if (detachDisposer) {
detachDisposers.delete(n);
detachDisposer();
}
};
const addDetachDisposer = (n, disposer) => {
if (disposer) {
detachDisposers.set(n, action(disposer));
}
};
const getChildrenObjectOpts = { deep };
const getCurrentChildren = () => {
const t = target();
assertIsNode(t, "target()");
const children = getChildrenNodes(t, getChildrenObjectOpts);
const set2 = /* @__PURE__ */ new Set();
const iter = children.values();
let cur = iter.next();
while (!cur.done) {
set2.add(cur.value);
cur = iter.next();
}
return set2;
};
const currentChildren = fireForCurrentChildren ? /* @__PURE__ */ new Set() : getCurrentChildren();
const disposeReaction = reaction(
() => getCurrentChildren(),
(newChildren) => {
const disposersToRun = [];
const currentChildrenIter = currentChildren.values();
let currentChildrenCur = currentChildrenIter.next();
while (!currentChildrenCur.done) {
const n = currentChildrenCur.value;
if (!newChildren.has(n)) {
currentChildren.delete(n);
disposersToRun.push(n);
}
currentChildrenCur = currentChildrenIter.next();
}
if (disposersToRun.length > 0) {
for (let i = disposersToRun.length - 1; i >= 0; i--) {
runDetachDisposer(disposersToRun[i]);
}
}
const newChildrenIter = newChildren.values();
let newChildrenCur = newChildrenIter.next();
while (!newChildrenCur.done) {
const n = newChildrenCur.value;
if (!currentChildren.has(n)) {
currentChildren.add(n);
runInAction(() => {
const { type } = getNodeTypeAndKey(n);
if (!childNodeTypeSet || childNodeTypeSet.has(type)) {
const detachAction = onChildAttached(n);
addDetachDisposer(n, detachAction);
}
});
}
newChildrenCur = newChildrenIter.next();
}
},
{
fireImmediately: true
}
);
return disposeOnce((runDetachDisposers) => {
disposeReaction();
if (runDetachDisposers) {
const currentChildrenIter = currentChildren.values();
let currentChildrenCur = currentChildrenIter.next();
while (!currentChildrenCur.done) {
const n = currentChildrenCur.value;
runDetachDisposer(n);
currentChildrenCur = currentChildrenIter.next();
}
}
currentChildren.clear();
});
}
const unresolved = { resolved: false };
function resolvePath(pathRootNode, path) {
assertIsNode(pathRootNode, "pathRootNode");
let current = pathRootNode;
const len = path.length;
for (let i = 0; i < len; i++) {
if (current === null || typeof current !== "object") {
return unresolved;
}
const p = path[i];
if (isArray(current) && +p >= current.length) {
return unresolved;
}
if (!(p in current)) {
return unresolved;
}
current = current[p];
}
return { resolved: true, value: current };
}
var WalkTreeMode = /* @__PURE__ */ ((WalkTreeMode2) => {
WalkTreeMode2["ParentFirst"] = "parentFirst";
WalkTreeMode2["ChildrenFirst"] = "childrenFirst";
return WalkTreeMode2;
})(WalkTreeMode || {});
function walkTree(root, visit, mode) {
assertIsNode(root, "root");
if (mode === "parentFirst") {
return walkTreeParentFirst(root, visit);
} else {
return walkTreeChildrenFirst(root, visit);
}
}
function walkTreeParentFirst(root, visit) {
const stack = [root];
while (stack.length > 0) {
const node2 = stack.pop();
const ret = visit(node2);
if (ret !== void 0) {
return ret;
}
const children = getChildrenNodes(node2);
stack.length += children.size;
let i = stack.length - 1;
const childrenIter = children.values();
let ch = childrenIter.next();
while (!ch.done) {
stack[i--] = ch.value;
ch = childrenIter.next();
}
}
return void 0;
}
function walkTreeChildrenFirst(root, visit) {
const childrenIter = getChildrenNodes(root).values();
let ch = childrenIter.next();
while (!ch.done) {
const ret2 = walkTreeChildrenFirst(ch.value, visit);
if (ret2 !== void 0) {
return ret2;
}
ch = childrenIter.next();
}
const ret = visit(root);
if (ret !== void 0) {
return ret;
}
return void 0;
}
const applySnapshot = action((node2, snapshot) => {
assertIsNode(node2, "node");
assertIsObject(snapshot, "snapshot");
const reconcile = () => {
const ret = reconcileData(node2, snapshot);
if (ret !== node2) {
throw failure("assertion failed: reconciled object has to be the same");
}
};
if (isArray(snapshot)) {
if (!isArray(node2)) {
throw failure("if the snapshot is an array the target must be an array too");
}
reconcile();
return;
}
if (isPlainObject(snapshot)) {
if (isFrozenNode(node2)) {
if (node2 === snapshot) {
return;
} else {
throw failure("applySnapshot does not work on frozen nodes");
}
}
if (!isObservableObject(node2)) {
throw failure("if the snapshot is an object the target must be an object too");
}
const typeKey = getNodeTypeAndKey(node2);
const newTypeKey = getNodeTypeAndKey(snapshot);
if (typeKey.type !== newTypeKey.type) {
throw failure(
`applySnapshot does not allow changes to the '${nodeTypeKey}' property of the node the snapshot is being applied to`
);
}
if (typeKey.key !== newTypeKey.key) {
const keyProp = typeKey.type && "key" in typeKey.type ? typeKey.type.key : void 0;
throw failure(
`applySnapshot does not allow changes to the '${keyProp}' property of the node the snapshot is being applied to`
);
}
reconcile();
return;
}
if (isMap(snapshot)) {
throw failure("a snapshot must not contain maps");
}
if (isSet(snapshot)) {
throw failure("a snapshot must not contain sets");
}
throw failure(`unsupported snapshot - ${snapshot}`);
});
function onSnapshot(nodeOrFn, listener) {
const nodeFn = typeof nodeOrFn === "function" ? nodeOrFn : () => nodeOrFn;
const node2 = nodeFn();
assertIsNode(node2, "node");
let currentSnapshot = getSnapshot(node2);
const disposeReaction = reaction(
() => getSnapshot(nodeFn()),
(newSnapshot) => {
const prevSn = currentSnapshot;
currentSnapshot = newSnapshot;
listener(newSnapshot, prevSn);
}
);
return disposeOnce(disposeReaction);
}
function substituteNodeKeys(value, newNodeKeyGenerator = getGlobalConfig().keyGenerator) {
if (isPrimitive(value)) {
return value;
}
if (Array.isArray(value)) {
return value.map((v) => substituteNodeKeys(v, newNodeKeyGenerator));
}
if (isPlainObject(value)) {
const typeAndKey = getNodeTypeAndKey(value);
const keyProp = typeAndKey.type && "key" in typeAndKey.type ? typeAndKey.type.key : void 0;
const newValue = {};
for (const key in value) {
if (key === keyProp) {
newValue[key] = newNodeKeyGenerator(value[key]);
} else {
newValue[key] = substituteNodeKeys(value[key], newNodeKeyGenerator);
}
}
return newValue;
}
throw failure("unsupported value type");
}
function clone(nodeToClone) {
const snapshotWithChangedKeys = substituteNodeKeys(getSnapshot(nodeToClone));
return node(snapshotWithChangedKeys);
}
function getOrCreate(map, key, create) {
let value = map.get(key);
if (value === void 0) {
value = create();
map.set(key, value);
}
return value;
}
function resolveContextValue(contextValue) {
if (contextValue.type === "value") {
return contextValue.value;
} else {
return contextValue.value.get();
}
}
const createContextValueAtom = () => createAtom("contextValue");
class ContextClass {
constructor(defaultValue) {
__publicField(this, "defaultContextValue", observable.box(void 0, { deep: false }));
__publicField(this, "overrideContextValue", observable.box(void 0, {
deep: false
}));
__publicField(this, "nodeContextValue", /* @__PURE__ */ new WeakMap());
__publicField(this, "nodeAtom", /* @__PURE__ */ new WeakMap());
__publicField(this, "setDefault", action((value) => {
this.defaultContextValue.set({
type: "value",
value
});
}));
__publicField(this, "setDefaultComputed", action((valueFn) => {
this.defaultContextValue.set({
type: "computed",
value: computed(valueFn)
});
}));
__publicField(this, "set", action((node2, value) => {
assertIsNode(node2, "node");
this.nodeContextValue.set(node2, {
type: "value",
value
});
this.reportNodeAtomChanged(node2);
}));
__publicField(this, "setComputed", action((node2, valueFn) => {
this._setComputed(node2, computed(valueFn));
}));
__publicField(this, "unset", action((node2) => {
assertIsNode(node2, "node");
this.nodeContextValue.delete(node2);
this.reportNodeAtomChanged(node2);
}));
__publicField(this, "apply", action((fn, value) => {
const old = this.overrideContextValue.get();
this.overrideContextValue.set({
type: "value",
value
});
try {
const ret = fn();
if (isNode(ret)) {
this.set(ret, value);
}
return ret;
} finally {
this.overrideContextValue.set(old);
}
}));
__publicField(this, "applyComputed", action((fn, valueFn) => {
const computedValueFn = computed(valueFn);
const old = this.overrideContextValue.get();
this.overrideContextValue.set({
type: "computed",
value: computedValueFn
});
try {
const ret = fn();
if (isNode(ret)) {
this._setComputed(ret, computedValueFn);
}
return ret;
} finally {
this.overrideContextValue.set(old);
}
}));
this.setDefault(defaultValue);
}
reportNodeAtomObserved(node2) {
getOrCreate(this.nodeAtom, node2, createContextValueAtom).reportObserved();
}
reportNodeAtomChanged(node2) {
var _a2;
(_a2 = this.nodeAtom.get(node2)) == null ? void 0 : _a2.reportChanged();
}
internalGet(node2) {
this.reportNodeAtomObserved(node2);
const obsForNode = this.nodeContextValue.get(node2);
if (obsForNode) {
return resolveContextValue(obsForNode);
}
const parent = getParent(node2);
if (!parent) {
const overrideValue = this.overrideContextValue.get();
if (overrideValue) {
return resolveContextValue(overrideValue);
}
return this.getDefault();
}
return this.internalGet(parent);
}
get(node2) {
assertIsNode(node2, "node");
return this.internalGet(node2);
}
internalGetProviderNode(node2) {
this.reportNodeAtomObserved(node2);
const obsForNode = this.nodeContextValue.get(node2);
if (obsForNode) {
return node2;
}
const parent = getParent(node2);
if (!parent) {
return void 0;
}
return this.internalGetProviderNode(parent);
}
getProviderNode(node2) {
assertIsNode(node2, "node");
return this.internalGetProviderNode(node2);
}
getDefault() {
return resolveContextValue(this.defaultContextValue.get());
}
_setComputed(node2, computedValueFn) {
assertIsNode(node2, "node");
this.nodeContextValue.set(node2, { type: "computed", value: computedValueFn });
this.reportNodeAtomChanged(node2);
}
}
function createContext(defaultValue) {
return new ContextClass(defaultValue);
}
function asReduxStore(target) {
assertIsNode(target, "target");
const store = {
getState() {
return getSnapshot(target);
},
subscribe(listener) {
return onSnapshot(target, listener);
}
};
return store;
}
function connectReduxDevTools(remotedevPackage, remotedevConnection, target) {
assertIsNode(target, "target");
let handlingMonitorAction = 0;
remotedevConnection.subscribe((message) => {
if (message.type === "DISPATCH") {
handleMonitorActions(remotedevConnection, target, message);
}
});
const initialState = getSnapshot(target);
remotedevConnection.init(initialState);
let lastLoggedSnapshot = initialState;
onSnapshot(target, (sn) => {
if (handlingMonitorAction) {
return;
}
if (sn === lastLoggedSnapshot) {
return;
}
lastLoggedSnapshot = sn;
const copy = {
type: "onSnapshot"
};
remotedevConnection.send(copy, sn);
});
function handleMonitorActions(remotedev2, target2, message) {
try {
handlingMonitorAction++;
switch (message.payload.type) {
case "RESET": {
applySnapshot(target2, initialState);
return remotedev2.init(initialState);
}
case "COMMIT":
return remotedev2.init(getSnapshot(target2));
case "ROLLBACK": {
const state = remotedevPackage.extractState(message);
applySnapshot(target2, state);
return remotedev2.init(state);
}
case "JUMP_TO_STATE":
case "JUMP_TO_ACTION": {
applySnapshot(target2, remotedevPackage.extractState(message