proxy-facades 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/.name +1 -0
- package/.idea/modules.xml +8 -0
- package/.idea/proxy-facades.iml +8 -0
- package/.idea/vcs.xml +6 -0
- package/DEVELOPMENT.md +15 -0
- package/LICENSE +21 -0
- package/RecordedReadOnProxiedObjectExt.d.ts +22 -0
- package/RecordedReadOnProxiedObjectExt.d.ts.map +1 -0
- package/RecordedReadOnProxiedObjectExt.js +41 -0
- package/RecordedReadOnProxiedObjectExt.js.map +1 -0
- package/RecordedReadOnProxiedObjectExt.ts +41 -0
- package/Util.d.ts +85 -0
- package/Util.d.ts.map +1 -0
- package/Util.js +239 -0
- package/Util.js.map +1 -0
- package/Util.ts +254 -0
- package/class-trackers/Array.d.ts +93 -0
- package/class-trackers/Array.d.ts.map +1 -0
- package/class-trackers/Array.js +193 -0
- package/class-trackers/Array.js.map +1 -0
- package/class-trackers/Array.ts +245 -0
- package/class-trackers/Iterator.d.ts +38 -0
- package/class-trackers/Iterator.d.ts.map +1 -0
- package/class-trackers/Iterator.js +69 -0
- package/class-trackers/Iterator.js.map +1 -0
- package/class-trackers/Iterator.ts +73 -0
- package/class-trackers/Map.d.ts +128 -0
- package/class-trackers/Map.d.ts.map +1 -0
- package/class-trackers/Map.js +310 -0
- package/class-trackers/Map.js.map +1 -0
- package/class-trackers/Map.ts +403 -0
- package/class-trackers/Set.d.ts +85 -0
- package/class-trackers/Set.d.ts.map +1 -0
- package/class-trackers/Set.js +197 -0
- package/class-trackers/Set.js.map +1 -0
- package/class-trackers/Set.ts +245 -0
- package/class-trackers/index.d.ts +7 -0
- package/class-trackers/index.d.ts.map +1 -0
- package/class-trackers/index.js +36 -0
- package/class-trackers/index.js.map +1 -0
- package/class-trackers/index.ts +38 -0
- package/class-trackers/readme.md +2 -0
- package/common.d.ts +235 -0
- package/common.d.ts.map +1 -0
- package/common.js +378 -0
- package/common.js.map +1 -0
- package/common.ts +501 -0
- package/dev_generateEsRuntimeBehaviourCheckerCode.d.ts +10 -0
- package/dev_generateEsRuntimeBehaviourCheckerCode.d.ts.map +1 -0
- package/dev_generateEsRuntimeBehaviourCheckerCode.js +76 -0
- package/dev_generateEsRuntimeBehaviourCheckerCode.js.map +1 -0
- package/dev_generateEsRuntimeBehaviourCheckerCode.ts +85 -0
- package/dist/mjs/RecordedReadOnProxiedObjectExt.d.ts +22 -0
- package/dist/mjs/RecordedReadOnProxiedObjectExt.d.ts.map +1 -0
- package/dist/mjs/RecordedReadOnProxiedObjectExt.js +37 -0
- package/dist/mjs/RecordedReadOnProxiedObjectExt.js.map +1 -0
- package/dist/mjs/Util.d.ts +85 -0
- package/dist/mjs/Util.d.ts.map +1 -0
- package/dist/mjs/Util.js +223 -0
- package/dist/mjs/Util.js.map +1 -0
- package/dist/mjs/class-trackers/Array.d.ts +93 -0
- package/dist/mjs/class-trackers/Array.d.ts.map +1 -0
- package/dist/mjs/class-trackers/Array.js +186 -0
- package/dist/mjs/class-trackers/Array.js.map +1 -0
- package/dist/mjs/class-trackers/Iterator.d.ts +38 -0
- package/dist/mjs/class-trackers/Iterator.d.ts.map +1 -0
- package/dist/mjs/class-trackers/Iterator.js +65 -0
- package/dist/mjs/class-trackers/Iterator.js.map +1 -0
- package/dist/mjs/class-trackers/Map.d.ts +128 -0
- package/dist/mjs/class-trackers/Map.d.ts.map +1 -0
- package/dist/mjs/class-trackers/Map.js +299 -0
- package/dist/mjs/class-trackers/Map.js.map +1 -0
- package/dist/mjs/class-trackers/Set.d.ts +85 -0
- package/dist/mjs/class-trackers/Set.d.ts.map +1 -0
- package/dist/mjs/class-trackers/Set.js +189 -0
- package/dist/mjs/class-trackers/Set.js.map +1 -0
- package/dist/mjs/class-trackers/index.d.ts +7 -0
- package/dist/mjs/class-trackers/index.d.ts.map +1 -0
- package/dist/mjs/class-trackers/index.js +32 -0
- package/dist/mjs/class-trackers/index.js.map +1 -0
- package/dist/mjs/common.d.ts +235 -0
- package/dist/mjs/common.d.ts.map +1 -0
- package/dist/mjs/common.js +361 -0
- package/dist/mjs/common.js.map +1 -0
- package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.d.ts +10 -0
- package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.d.ts.map +1 -0
- package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.js +76 -0
- package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.js.map +1 -0
- package/dist/mjs/index.d.ts +8 -0
- package/dist/mjs/index.d.ts.map +1 -0
- package/dist/mjs/index.js +8 -0
- package/dist/mjs/index.js.map +1 -0
- package/dist/mjs/objectChangeTracking.d.ts +43 -0
- package/dist/mjs/objectChangeTracking.d.ts.map +1 -0
- package/dist/mjs/objectChangeTracking.js +209 -0
- package/dist/mjs/objectChangeTracking.js.map +1 -0
- package/dist/mjs/origChangeTracking.d.ts +14 -0
- package/dist/mjs/origChangeTracking.d.ts.map +1 -0
- package/dist/mjs/origChangeTracking.js +58 -0
- package/dist/mjs/origChangeTracking.js.map +1 -0
- package/dist/mjs/proxyFacade.d.ts +45 -0
- package/dist/mjs/proxyFacade.d.ts.map +1 -0
- package/dist/mjs/proxyFacade.js +179 -0
- package/dist/mjs/proxyFacade.js.map +1 -0
- package/dist/mjs/watchedProxyFacade.d.ts +84 -0
- package/dist/mjs/watchedProxyFacade.d.ts.map +1 -0
- package/dist/mjs/watchedProxyFacade.js +300 -0
- package/dist/mjs/watchedProxyFacade.js.map +1 -0
- package/index.d.ts +8 -0
- package/index.d.ts.map +1 -0
- package/index.js +36 -0
- package/index.js.map +1 -0
- package/index.ts +7 -0
- package/index_esm.mjs +44 -0
- package/objectChangeTracking.d.ts +43 -0
- package/objectChangeTracking.d.ts.map +1 -0
- package/objectChangeTracking.js +214 -0
- package/objectChangeTracking.js.map +1 -0
- package/objectChangeTracking.ts +251 -0
- package/origChangeTracking.d.ts +14 -0
- package/origChangeTracking.d.ts.map +1 -0
- package/origChangeTracking.js +63 -0
- package/origChangeTracking.js.map +1 -0
- package/origChangeTracking.ts +72 -0
- package/package.json +52 -0
- package/proxyFacade.d.ts +45 -0
- package/proxyFacade.d.ts.map +1 -0
- package/proxyFacade.js +187 -0
- package/proxyFacade.js.map +1 -0
- package/proxyFacade.ts +222 -0
- package/readme.md +111 -0
- package/watchedProxyFacade.d.ts +84 -0
- package/watchedProxyFacade.d.ts.map +1 -0
- package/watchedProxyFacade.js +312 -0
- package/watchedProxyFacade.js.map +1 -0
- package/watchedProxyFacade.ts +369 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import {FacadeProxyHandler, ProxyFacade} from "./proxyFacade";
|
|
2
|
+
import {throwError} from "./Util";
|
|
3
|
+
import {
|
|
4
|
+
AfterChangeOwnKeysListener,
|
|
5
|
+
AfterReadListener,
|
|
6
|
+
ChangeListener,
|
|
7
|
+
checkEsRuntimeBehaviour, EventHook,
|
|
8
|
+
getPropertyDescriptor,
|
|
9
|
+
IWatchedProxyHandler_common, objectMembershipInGraphs,
|
|
10
|
+
ObjKey,
|
|
11
|
+
RecordedRead,
|
|
12
|
+
RecordedReadOnProxiedObject,
|
|
13
|
+
runChangeOperation, UnspecificObjectChange,
|
|
14
|
+
} from "./common";
|
|
15
|
+
import {getChangeHooksForObject, changeHooksForObject} from "./objectChangeTracking";
|
|
16
|
+
import _ from "underscore"
|
|
17
|
+
import {getTrackingConfigFor} from "./class-trackers/index";
|
|
18
|
+
import {RecordedReadOnProxiedObjectExt} from "./RecordedReadOnProxiedObjectExt";
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Access a single value (=variable or return value from a function)
|
|
23
|
+
* This read is can only be constructed manually (not through a WatchedProxyFacade / WatchedProxyHandler
|
|
24
|
+
*/
|
|
25
|
+
export class RecordedValueRead extends RecordedRead{
|
|
26
|
+
value: unknown;
|
|
27
|
+
|
|
28
|
+
constructor(value: unknown) {
|
|
29
|
+
super();
|
|
30
|
+
this.value = value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get isChanged(): boolean {
|
|
34
|
+
throw new Error("Cannot check if simple value (not on object) has changed.");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
onAfterChange(listener: () => void, trackOriginal = false) {
|
|
38
|
+
throw new Error("Cannot listen for changes on simple value (not on object)");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
offAfterChange(listener: () => void) {
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
equals(other: RecordedRead) {
|
|
45
|
+
if(! (other instanceof RecordedValueRead)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return this.value === other.value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class RecordedPropertyRead extends RecordedReadOnProxiedObjectExt {
|
|
54
|
+
key!: ObjKey;
|
|
55
|
+
value!: unknown;
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
constructor(key: ObjKey, value: unknown) {
|
|
59
|
+
super();
|
|
60
|
+
this.key = key;
|
|
61
|
+
this.value = value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get isChanged() {
|
|
65
|
+
//@ts-ignore
|
|
66
|
+
return this.obj[this.key] !== this.value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getAffectingChangeHooks(target: this["obj"]) {
|
|
70
|
+
const result = [
|
|
71
|
+
getChangeHooksForObject(target).changeSpecificProperty.get(this.key)
|
|
72
|
+
]
|
|
73
|
+
if(Array.isArray(this.obj)) {
|
|
74
|
+
result.push(getChangeHooksForObject(target).unspecificChange);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
equals(other: RecordedRead) {
|
|
80
|
+
if(! (other instanceof RecordedPropertyRead)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return this.proxyHandler === other.proxyHandler && this.obj === other.obj && this.key === other.key && this.value === other.value;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class RecordedOwnKeysRead extends RecordedReadOnProxiedObjectExt{
|
|
89
|
+
value!: ArrayLike<string | symbol>;
|
|
90
|
+
|
|
91
|
+
constructor(value: RecordedOwnKeysRead["value"]) {
|
|
92
|
+
super();
|
|
93
|
+
this.value = value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get isChanged() {
|
|
97
|
+
return !_.isEqual(Reflect.ownKeys(this.obj), this.value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getAffectingChangeHooks(target: this["obj"]) {
|
|
101
|
+
const result = [
|
|
102
|
+
getChangeHooksForObject(target).changeOwnKeys
|
|
103
|
+
]
|
|
104
|
+
if(Array.isArray(this.obj)) {
|
|
105
|
+
result.push(getChangeHooksForObject(target).unspecificChange);
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
equals(other: RecordedRead) {
|
|
111
|
+
if(! (other instanceof RecordedOwnKeysRead)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return this.proxyHandler === other.proxyHandler && this.obj === other.obj && _.isEqual(this.value, other.value);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Fired when a method was called that is not implemented in the supervisor. May be from a future js version
|
|
121
|
+
*/
|
|
122
|
+
export class RecordedUnspecificRead extends RecordedReadOnProxiedObjectExt{
|
|
123
|
+
get isChanged() {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getAffectingChangeHooks(target: this["obj"]) {
|
|
128
|
+
return [
|
|
129
|
+
getChangeHooksForObject(target).anyChange
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
equals(other: RecordedRead) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Use cases:
|
|
141
|
+
* - record read + watch recorded for modifications. For re-render trigger
|
|
142
|
+
* - record read and make several snapshots (when load is called) and compare exactly those reads
|
|
143
|
+
*/
|
|
144
|
+
export class WatchedProxyFacade extends ProxyFacade<WatchedProxyHandler> {
|
|
145
|
+
// ** Configuration**
|
|
146
|
+
|
|
147
|
+
trackReadsOnPrototype = false;
|
|
148
|
+
|
|
149
|
+
// *** State: ****
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Called after a read has been made to any object inside this facade
|
|
153
|
+
* @protected
|
|
154
|
+
*/
|
|
155
|
+
_afterReadListeners = new Set<AfterReadListener>()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
onAfterRead(listener: AfterReadListener) {
|
|
159
|
+
this._afterReadListeners.add(listener);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
offAfterRead(listener: AfterReadListener) {
|
|
163
|
+
this._afterReadListeners.delete(listener);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
constructor() {
|
|
167
|
+
super();
|
|
168
|
+
checkEsRuntimeBehaviour();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Watches for writes on a specified property
|
|
173
|
+
* @param obj
|
|
174
|
+
* @param key Not restricted here (for the tests), but it must not be number !
|
|
175
|
+
* @param listener
|
|
176
|
+
*/
|
|
177
|
+
onAfterWriteOnProperty<O extends object, K extends keyof O>(obj: O, key: K, listener: ChangeListener) {
|
|
178
|
+
getChangeHooksForObject(obj).changeSpecificProperty.get(key as ObjKey).afterListeners.add(listener);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Watches for writes on a specified property
|
|
183
|
+
* @param obj
|
|
184
|
+
* @param key Not restricted here (for the tests), but it must not be number !
|
|
185
|
+
* @param listener
|
|
186
|
+
*/
|
|
187
|
+
offAfterWriteOnProperty<O extends object, K extends keyof O>(obj: O, key: K, listener: ChangeListener) {
|
|
188
|
+
changeHooksForObject.get(obj)?.changeSpecificProperty.get(key as ObjKey).afterListeners.delete(listener);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
protected crateHandler(target: object, facade: any): WatchedProxyHandler {
|
|
192
|
+
return new WatchedProxyHandler(target, facade);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export class WatchedProxyHandler extends FacadeProxyHandler<WatchedProxyFacade> implements IWatchedProxyHandler_common{
|
|
197
|
+
|
|
198
|
+
constructor(target: object, facade: WatchedProxyFacade) {
|
|
199
|
+
super(target, facade);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
get trackingConfig() {
|
|
203
|
+
return getTrackingConfigFor(this.target); // TODO: cache (performance)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fireAfterRead(read: RecordedReadOnProxiedObject) {
|
|
207
|
+
read.proxyHandler = this;
|
|
208
|
+
read.obj = this.target;
|
|
209
|
+
|
|
210
|
+
this.facade._afterReadListeners.forEach(l => l(read)); // Inform listeners
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getFacade() {
|
|
214
|
+
return this.facade;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get (fake_target:object, key:string | symbol, receiver:any) {
|
|
218
|
+
const target = this.target;
|
|
219
|
+
const proxy = this.proxy;
|
|
220
|
+
const thisHandler = this;
|
|
221
|
+
const receiverMustBeNonProxied = this.trackingConfig?.receiverMustBeNonProxied === true;
|
|
222
|
+
|
|
223
|
+
if(key === "_watchedProxyHandler") { // TODO: use symbol for that (performance)
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
if(key === "_target") { // TODO: use symbol for that (performance)
|
|
227
|
+
return this.target;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Check for and use supervisor class:
|
|
231
|
+
if(this.trackingConfig !== undefined) {
|
|
232
|
+
for(const TrackerClass of this.trackingConfig.getTrackerClasses()) {
|
|
233
|
+
let propOnSupervisor = Object.getOwnPropertyDescriptor(TrackerClass.prototype, key);
|
|
234
|
+
if(propOnSupervisor !== undefined) { // Supervisor class is responsible for the property (or method) ?
|
|
235
|
+
//@ts-ignore
|
|
236
|
+
if(propOnSupervisor.get) { // Prop is a getter?
|
|
237
|
+
return this.facade.getProxyFor(propOnSupervisor.get.apply(this.proxy));
|
|
238
|
+
}
|
|
239
|
+
if(propOnSupervisor.set) { // Prop is a setter ?
|
|
240
|
+
throw new Error("setters not yet implemented")
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
typeof propOnSupervisor.value === "function" || throwError(`Accessing supervisor's plain property: ${String(key)}`); // validity check
|
|
244
|
+
const supervisorMethod = propOnSupervisor.value;
|
|
245
|
+
return supervisorMethod;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// When arriving here, the field is not **directly** in one of the tracker classes
|
|
250
|
+
//@ts-ignore
|
|
251
|
+
origMethod = this.target[key];
|
|
252
|
+
if(this.trackingConfig.knownHighLevelMethods.has(key)) {
|
|
253
|
+
return trapHighLevelReaderWriterMethod
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if(typeof origMethod === "function" && !(key as any in Object.prototype)) { // Read+write method that was not handled directly by supervisor class?
|
|
257
|
+
if(this.trackingConfig.readOnlyMethods.has(key)) {
|
|
258
|
+
return trapForGenericReaderMethod
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
return trapForGenericReaderWriterMethod // Assume the worst, that it is a writer method
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return super.get(fake_target, key, receiver);
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
var origMethod: ((this:unknown, ...args:unknown[]) => unknown) | undefined = undefined;
|
|
270
|
+
/**
|
|
271
|
+
* Fires a RecordedUnspecificRead
|
|
272
|
+
*/
|
|
273
|
+
function trapForGenericReaderMethod(this:object, ...args: unknown[]) {
|
|
274
|
+
const callResult = origMethod!.apply(receiverMustBeNonProxied?target:this, args); // call original method:
|
|
275
|
+
if(thisHandler.trackingConfig?.trackTreads !== false) { // not explicitly disabled ?
|
|
276
|
+
thisHandler.fireAfterRead(new RecordedUnspecificRead());
|
|
277
|
+
}
|
|
278
|
+
return thisHandler.trackingConfig?.proxyUnhandledMethodResults?thisHandler.facade.getProxyFor(callResult):callResult;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Fires a RecordedUnspecificRead and calls the unspecificChange listeners
|
|
282
|
+
* @param args
|
|
283
|
+
*/
|
|
284
|
+
function trapForGenericReaderWriterMethod(this:object, ...args: unknown[]) {
|
|
285
|
+
return runChangeOperation(proxy, new UnspecificObjectChange(proxy),[getChangeHooksForObject(proxy).unspecificChange],() => {
|
|
286
|
+
const callResult = origMethod!.apply(receiverMustBeNonProxied?target:this, args); // call original method:
|
|
287
|
+
if(thisHandler.trackingConfig?.trackTreads !== false) { // not explicitly disabled ?
|
|
288
|
+
thisHandler.fireAfterRead(new RecordedUnspecificRead());
|
|
289
|
+
}
|
|
290
|
+
return thisHandler.trackingConfig?.proxyUnhandledMethodResults?thisHandler.facade.getProxyFor(callResult):callResult;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Wraps it in runAndCallListenersOnce_after
|
|
295
|
+
* @param args
|
|
296
|
+
*/
|
|
297
|
+
function trapHighLevelReaderWriterMethod(this:object, ...args: unknown[]) {
|
|
298
|
+
return runChangeOperation(proxy, undefined,[],() => {
|
|
299
|
+
return origMethod!.apply(this, args); // call original method
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
rawRead(key: ObjKey) {
|
|
305
|
+
const result = super.rawRead(key);
|
|
306
|
+
if(!this.facade.trackReadsOnPrototype) {
|
|
307
|
+
if(Object.getOwnPropertyDescriptor(this.target, key) === undefined && getPropertyDescriptor(this.target,key ) !== undefined) { // Property is on prototype only ?
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if(this.trackingConfig?.trackTreads !== false) { // not explicitly disabled ?
|
|
312
|
+
this.fireAfterRead(new RecordedPropertyRead(key, result)); // Inform listeners
|
|
313
|
+
}
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
protected rawChange(key: string | symbol, newUnproxiedValue: any) {
|
|
318
|
+
const changeHooksForThisObject = getChangeHooksForObject(this.proxy);
|
|
319
|
+
const hooksToServe: EventHook[] = [];
|
|
320
|
+
|
|
321
|
+
if (this.isForArray()) {
|
|
322
|
+
hooksToServe.push(changeHooksForThisObject.unspecificChange);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
hooksToServe.push(changeHooksForThisObject.changeSpecificProperty.get(key));
|
|
326
|
+
hooksToServe.push(changeHooksForThisObject.changeAnyProperty);
|
|
327
|
+
|
|
328
|
+
const isNewProperty = getPropertyDescriptor(this.target, key) === undefined;
|
|
329
|
+
if (isNewProperty) {
|
|
330
|
+
hooksToServe.push(changeHooksForThisObject.changeOwnKeys);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
runChangeOperation(this.proxy, new UnspecificObjectChange(this.proxy),hooksToServe,() => {
|
|
334
|
+
super.rawChange(key, newUnproxiedValue);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
deleteProperty(target: object, key: string | symbol): boolean {
|
|
339
|
+
const doesExists = Object.getOwnPropertyDescriptor(this.target, key) !== undefined;
|
|
340
|
+
if (!doesExists) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return runChangeOperation(this.proxy, new UnspecificObjectChange(this.proxy),[getChangeHooksForObject(this.proxy).changeOwnKeys],() => {
|
|
345
|
+
this.set(target, key, undefined, this.proxy); // Set to undefined first, so property change listeners will get informed
|
|
346
|
+
return super.deleteProperty(target, key);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
ownKeys(target: object): ArrayLike<string | symbol> {
|
|
351
|
+
const result = Reflect.ownKeys(this.target);
|
|
352
|
+
if(this.trackingConfig?.trackTreads !== false) { // not explicitly disabled ?
|
|
353
|
+
this.fireAfterRead(new RecordedOwnKeysRead(result))
|
|
354
|
+
}
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
isForArray() {
|
|
359
|
+
return Array.isArray(this.target)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
isForSet() {
|
|
363
|
+
return this.target instanceof Set;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
isForMap() {
|
|
367
|
+
return this.target instanceof Map;
|
|
368
|
+
}
|
|
369
|
+
}
|