mahler
Version:
A automated task composer and HTN based planner for building autonomous system agents
98 lines • 3.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.observe = observe;
const path_1 = require("../path");
const patch_1 = require("./patch");
function isObject(value) {
return value !== null && typeof value === 'object';
}
function appendToPath(key, path) {
return key === '_' && path.length === 0 ? path : path.concat(String(key));
}
function buildProxy(r, u, next, path = []) {
return new Proxy(u, {
set(target, prop, value) {
const childPath = appendToPath(prop, path);
const existsBefore = prop in target;
let valueProxy = value;
if (isObject(value)) {
// If we are re-assigning a key with a new object we need to
// observe that object too. We pass an empty array to changes as we don't want
// to reverse those changes
valueProxy = observeObject(r, value, next, childPath);
}
const res = Reflect.set(target, prop, valueProxy);
// Do not notify on array length changes
if (res) {
if (Array.isArray(target) && prop === 'length') {
return res;
}
if (existsBefore) {
// Notify the observer
next({
op: 'update',
path: path_1.Path.from(childPath),
target: value,
});
}
else {
next({
op: 'create',
path: path_1.Path.from(childPath),
target: value,
});
}
}
return res;
},
deleteProperty(target, prop) {
const res = Reflect.deleteProperty(target, prop);
if (res) {
const childPath = appendToPath(prop, path);
next({ op: 'delete', path: path_1.Path.from(childPath) });
}
return res;
},
});
}
function observeArray(r, u, next, path = []) {
u = u.map((v, i) => {
if (isObject(v)) {
const newPath = path.concat(String(i));
return observeObject(r, v, next, newPath);
}
return v;
});
return buildProxy(r, u, next, path);
}
function observeObject(r, u, next, path = []) {
if (Array.isArray(u)) {
return observeArray(r, u, next, path);
}
// Recursively observe existing properties of the object
u = Object.fromEntries(Object.getOwnPropertyNames(u).map((key) => {
const v = u[key];
if (isObject(v)) {
return [key, observeObject(r, v, next, appendToPath(key, path))];
}
return [key, v];
}));
return buildProxy(r, u, next, path);
}
/**
* Communicates the changes performed by a function on an object
* reference to an observer.
*
* @param fn The function to execute
* @param observer The observer to notify of changes
* @returns an intrumented function
*/
function observe(fn, observer) {
return function (ref) {
return fn(observeObject(ref, ref, (change) => {
(0, patch_1.applyPatch)(ref, change);
observer.next(change);
}));
};
}
//# sourceMappingURL=observe.js.map