UNPKG

vanilla-party

Version:

An easy to use library for simple multi-user JavaScript apps.

106 lines (94 loc) 3.06 kB
import { JSONObject, JSONValue } from "./validate" import * as log from "./log" /** * patches _old to deep equal _new * needed so objects can be updated without breaking references to them * * @param oldObject object to be updated * @param newObject object with values to use for update * @param path path to the object to be updated */ export function patchInPlace( oldObject: JSONObject, newObject: JSONObject, path = "" ): void { if (typeof oldObject !== "object") { log.error("_old is not an object") return } if (typeof newObject !== "object") { log.error("_new is not an object") return } const oldKeys = Object.keys(oldObject).reverse() const newKeys = Object.keys(newObject) // remove oldObject keys that are not in newObject for (const key of oldKeys) { if (!Object.prototype.hasOwnProperty.call(newObject, key)) { // log.debug(`remove ${_keyPath}.${key}`); if (Array.isArray(oldObject)) { oldObject.splice(parseInt(key), 1) } else { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete oldObject[key] } } } // add newObject keys that are not in oldObject for (const key of newKeys) { if (!Object.prototype.hasOwnProperty.call(oldObject, key)) { // log.debug(`add ${_keyPath}.${key}`); oldObject[key] = newObject[key] } } // patch shared object and array keys for (const key of newKeys) { if (Object.prototype.hasOwnProperty.call(oldObject, key)) { const oldType = getMergeType(oldObject[key]) const newType = getMergeType(newObject[key]) // bail if type is unsupported if (newType === "unsupported") { log.error( `${path}.${key} is unsupported type: ${typeof newObject[key]}` ) continue } // merge objects if (oldType === "object" && newType === "object") { // casts are safe; objects in JSONObjects are always JSON Objects patchInPlace( oldObject[key] as JSONObject, newObject[key] as JSONObject, `${path}.${key}` ) continue } // merge arrays if (oldType === "array" && newType === "array") { // casts are safe; arrays in JSONObjects can be treated by // this function as JSONObjects patchInPlace( oldObject[key] as JSONObject, newObject[key] as JSONObject, `${path}.${key}` ) continue } // replace everything else if (oldObject[key] !== newObject[key]) { oldObject[key] = newObject[key] } } } } // module.exports = { patchInPlace }; function getMergeType(value: JSONValue): string { if (value === null) return "null" if (Array.isArray(value)) return "array" if (typeof value === "object") return "object" if (typeof value === "boolean") return "primitive" if (typeof value === "number" && Number.isFinite(value)) return "primitive" if (typeof value === "string") return "primitive" return "unsupported" }