From 67d8d071a2667ec0c6f071fad7649c90da9e0fbb Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Sat, 25 Apr 2026 17:44:09 -0400 Subject: [PATCH] Replace implementation with shallow proxy --- module/data/actor/base.mjs | 5 ++--- module/data/item/base.mjs | 4 ++-- module/documents/actor.mjs | 4 ++-- module/helpers/utils.mjs | 37 ++++++++++++++++--------------------- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 13ff0a38..9efbe7d7 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,6 +1,6 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; import DHItem from '../../documents/item.mjs'; -import { getScrollTextData } from '../../helpers/utils.mjs'; +import { createShallowProxy, getScrollTextData } from '../../helpers/utils.mjs'; const fields = foundry.data.fields; @@ -180,8 +180,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { * @returns {object} */ getRollData() { - const data = { ...this }; - return data; + return createShallowProxy(this); } /** diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 8dedf485..aebf33bf 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -10,7 +10,7 @@ import { addLinkedItemsDiff, getScrollTextData, - shallowCopyWithGetters, + createShallowProxy, updateLinkedItemApps } from '../../helpers/utils.mjs'; import { ActionsField } from '../fields/actionField.mjs'; @@ -165,7 +165,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { */ getRollData(options = {}) { const data = this.actor?.getRollData() ?? {}; - data.item = shallowCopyWithGetters(this); + data.item = createShallowProxy(this); return data; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 47b4bfdc..eb57a186 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,7 +1,7 @@ import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; import { LevelOptionType } from '../data/levelTier.mjs'; import DHFeature from '../data/item/feature.mjs'; -import { createScrollText, damageKeyToNumber, getDamageKey, shallowCopyWithGetters } from '../helpers/utils.mjs'; +import { createScrollText, damageKeyToNumber, getDamageKey, createShallowProxy } from '../helpers/utils.mjs'; import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs'; import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; import { abilities } from '../config/actorConfig.mjs'; @@ -595,7 +595,7 @@ export default class DhpActor extends Actor { /**@inheritdoc */ getRollData() { - const rollData = shallowCopyWithGetters(super.getRollData()); + const rollData = createShallowProxy(super.getRollData()); rollData.id = this.id; rollData.name = this.name; rollData.system = this.system.getRollData(); diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index b76d180c..738a5f3d 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -810,28 +810,23 @@ export function sortBy(arr, fn) { return arr.sort(cmp); } -function getAllPropertyNames(obj, names = new Set()) { - if (!obj) return names; - - for (const name of Object.getOwnPropertyNames(obj)) { - names.add(name); - } - - return getAllPropertyNames(Object.getPrototypeOf(obj), names); -} - /** - * Returns a shallow copy including getters of the given object. - * Generally used for expanding roll data without side effects + * Creates a proxy that allows retrieval of top data but diverts updates to a different object. + * Generally used for roll data */ -export function shallowCopyWithGetters(obj) { - const props = getAllPropertyNames(obj); - const result = {}; - for (const key of props) { - const value = obj[key]; - if (key !== '__proto__' && typeof value !== 'function') { - result[key] = obj[key]; +export function createShallowProxy(obj) { + if (obj._isShallowProxy) return obj; + + const overrides = {}; + return new Proxy(obj, { + get(target, prop, receiver) { + if (prop === '_isShallowProxy') return true; + if (prop in overrides) return overrides[prop]; + return Reflect.get(target, prop, receiver); + }, + set(_target, prop, newValue) { + overrides[prop] = newValue; + return true; } - } - return result; + }); }