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.
Files changed (136) hide show
  1. package/.idea/.name +1 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/proxy-facades.iml +8 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/DEVELOPMENT.md +15 -0
  6. package/LICENSE +21 -0
  7. package/RecordedReadOnProxiedObjectExt.d.ts +22 -0
  8. package/RecordedReadOnProxiedObjectExt.d.ts.map +1 -0
  9. package/RecordedReadOnProxiedObjectExt.js +41 -0
  10. package/RecordedReadOnProxiedObjectExt.js.map +1 -0
  11. package/RecordedReadOnProxiedObjectExt.ts +41 -0
  12. package/Util.d.ts +85 -0
  13. package/Util.d.ts.map +1 -0
  14. package/Util.js +239 -0
  15. package/Util.js.map +1 -0
  16. package/Util.ts +254 -0
  17. package/class-trackers/Array.d.ts +93 -0
  18. package/class-trackers/Array.d.ts.map +1 -0
  19. package/class-trackers/Array.js +193 -0
  20. package/class-trackers/Array.js.map +1 -0
  21. package/class-trackers/Array.ts +245 -0
  22. package/class-trackers/Iterator.d.ts +38 -0
  23. package/class-trackers/Iterator.d.ts.map +1 -0
  24. package/class-trackers/Iterator.js +69 -0
  25. package/class-trackers/Iterator.js.map +1 -0
  26. package/class-trackers/Iterator.ts +73 -0
  27. package/class-trackers/Map.d.ts +128 -0
  28. package/class-trackers/Map.d.ts.map +1 -0
  29. package/class-trackers/Map.js +310 -0
  30. package/class-trackers/Map.js.map +1 -0
  31. package/class-trackers/Map.ts +403 -0
  32. package/class-trackers/Set.d.ts +85 -0
  33. package/class-trackers/Set.d.ts.map +1 -0
  34. package/class-trackers/Set.js +197 -0
  35. package/class-trackers/Set.js.map +1 -0
  36. package/class-trackers/Set.ts +245 -0
  37. package/class-trackers/index.d.ts +7 -0
  38. package/class-trackers/index.d.ts.map +1 -0
  39. package/class-trackers/index.js +36 -0
  40. package/class-trackers/index.js.map +1 -0
  41. package/class-trackers/index.ts +38 -0
  42. package/class-trackers/readme.md +2 -0
  43. package/common.d.ts +235 -0
  44. package/common.d.ts.map +1 -0
  45. package/common.js +378 -0
  46. package/common.js.map +1 -0
  47. package/common.ts +501 -0
  48. package/dev_generateEsRuntimeBehaviourCheckerCode.d.ts +10 -0
  49. package/dev_generateEsRuntimeBehaviourCheckerCode.d.ts.map +1 -0
  50. package/dev_generateEsRuntimeBehaviourCheckerCode.js +76 -0
  51. package/dev_generateEsRuntimeBehaviourCheckerCode.js.map +1 -0
  52. package/dev_generateEsRuntimeBehaviourCheckerCode.ts +85 -0
  53. package/dist/mjs/RecordedReadOnProxiedObjectExt.d.ts +22 -0
  54. package/dist/mjs/RecordedReadOnProxiedObjectExt.d.ts.map +1 -0
  55. package/dist/mjs/RecordedReadOnProxiedObjectExt.js +37 -0
  56. package/dist/mjs/RecordedReadOnProxiedObjectExt.js.map +1 -0
  57. package/dist/mjs/Util.d.ts +85 -0
  58. package/dist/mjs/Util.d.ts.map +1 -0
  59. package/dist/mjs/Util.js +223 -0
  60. package/dist/mjs/Util.js.map +1 -0
  61. package/dist/mjs/class-trackers/Array.d.ts +93 -0
  62. package/dist/mjs/class-trackers/Array.d.ts.map +1 -0
  63. package/dist/mjs/class-trackers/Array.js +186 -0
  64. package/dist/mjs/class-trackers/Array.js.map +1 -0
  65. package/dist/mjs/class-trackers/Iterator.d.ts +38 -0
  66. package/dist/mjs/class-trackers/Iterator.d.ts.map +1 -0
  67. package/dist/mjs/class-trackers/Iterator.js +65 -0
  68. package/dist/mjs/class-trackers/Iterator.js.map +1 -0
  69. package/dist/mjs/class-trackers/Map.d.ts +128 -0
  70. package/dist/mjs/class-trackers/Map.d.ts.map +1 -0
  71. package/dist/mjs/class-trackers/Map.js +299 -0
  72. package/dist/mjs/class-trackers/Map.js.map +1 -0
  73. package/dist/mjs/class-trackers/Set.d.ts +85 -0
  74. package/dist/mjs/class-trackers/Set.d.ts.map +1 -0
  75. package/dist/mjs/class-trackers/Set.js +189 -0
  76. package/dist/mjs/class-trackers/Set.js.map +1 -0
  77. package/dist/mjs/class-trackers/index.d.ts +7 -0
  78. package/dist/mjs/class-trackers/index.d.ts.map +1 -0
  79. package/dist/mjs/class-trackers/index.js +32 -0
  80. package/dist/mjs/class-trackers/index.js.map +1 -0
  81. package/dist/mjs/common.d.ts +235 -0
  82. package/dist/mjs/common.d.ts.map +1 -0
  83. package/dist/mjs/common.js +361 -0
  84. package/dist/mjs/common.js.map +1 -0
  85. package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.d.ts +10 -0
  86. package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.d.ts.map +1 -0
  87. package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.js +76 -0
  88. package/dist/mjs/dev_generateEsRuntimeBehaviourCheckerCode.js.map +1 -0
  89. package/dist/mjs/index.d.ts +8 -0
  90. package/dist/mjs/index.d.ts.map +1 -0
  91. package/dist/mjs/index.js +8 -0
  92. package/dist/mjs/index.js.map +1 -0
  93. package/dist/mjs/objectChangeTracking.d.ts +43 -0
  94. package/dist/mjs/objectChangeTracking.d.ts.map +1 -0
  95. package/dist/mjs/objectChangeTracking.js +209 -0
  96. package/dist/mjs/objectChangeTracking.js.map +1 -0
  97. package/dist/mjs/origChangeTracking.d.ts +14 -0
  98. package/dist/mjs/origChangeTracking.d.ts.map +1 -0
  99. package/dist/mjs/origChangeTracking.js +58 -0
  100. package/dist/mjs/origChangeTracking.js.map +1 -0
  101. package/dist/mjs/proxyFacade.d.ts +45 -0
  102. package/dist/mjs/proxyFacade.d.ts.map +1 -0
  103. package/dist/mjs/proxyFacade.js +179 -0
  104. package/dist/mjs/proxyFacade.js.map +1 -0
  105. package/dist/mjs/watchedProxyFacade.d.ts +84 -0
  106. package/dist/mjs/watchedProxyFacade.d.ts.map +1 -0
  107. package/dist/mjs/watchedProxyFacade.js +300 -0
  108. package/dist/mjs/watchedProxyFacade.js.map +1 -0
  109. package/index.d.ts +8 -0
  110. package/index.d.ts.map +1 -0
  111. package/index.js +36 -0
  112. package/index.js.map +1 -0
  113. package/index.ts +7 -0
  114. package/index_esm.mjs +44 -0
  115. package/objectChangeTracking.d.ts +43 -0
  116. package/objectChangeTracking.d.ts.map +1 -0
  117. package/objectChangeTracking.js +214 -0
  118. package/objectChangeTracking.js.map +1 -0
  119. package/objectChangeTracking.ts +251 -0
  120. package/origChangeTracking.d.ts +14 -0
  121. package/origChangeTracking.d.ts.map +1 -0
  122. package/origChangeTracking.js +63 -0
  123. package/origChangeTracking.js.map +1 -0
  124. package/origChangeTracking.ts +72 -0
  125. package/package.json +52 -0
  126. package/proxyFacade.d.ts +45 -0
  127. package/proxyFacade.d.ts.map +1 -0
  128. package/proxyFacade.js +187 -0
  129. package/proxyFacade.js.map +1 -0
  130. package/proxyFacade.ts +222 -0
  131. package/readme.md +111 -0
  132. package/watchedProxyFacade.d.ts +84 -0
  133. package/watchedProxyFacade.d.ts.map +1 -0
  134. package/watchedProxyFacade.js +312 -0
  135. package/watchedProxyFacade.js.map +1 -0
  136. package/watchedProxyFacade.ts +369 -0
package/common.ts ADDED
@@ -0,0 +1,501 @@
1
+ import {WatchedProxyHandler} from "./watchedProxyFacade";
2
+ import {arraysAreEqualsByPredicateFn, newDefaultMap, read, throwError, WeakMapSet} from "./Util";
3
+ import {getGlobalOrig, ProxyFacade} from "./proxyFacade";
4
+ import {getChangeHooksForObject} from "./objectChangeTracking";
5
+
6
+ export type ObjKey = string | symbol;
7
+
8
+ export abstract class RecordedRead {
9
+ abstract equals(other: RecordedRead): boolean;
10
+
11
+ abstract get isChanged(): boolean;
12
+
13
+ /**
14
+ *
15
+ * @param listener
16
+ * @param trackOriginal true to install a tracker on the non-proxied- (by this facade) original object
17
+ */
18
+ abstract onAfterChange(listener: () => void, trackOriginal?: boolean): void;
19
+
20
+ abstract offAfterChange(listener: () => void): void;
21
+ }
22
+
23
+ export abstract class RecordedReadOnProxiedObject extends RecordedRead {
24
+ proxyHandler!: WatchedProxyHandler
25
+ /**
26
+ * A bit redundant with proxyhandler. But for performance reasons, we leave it
27
+ */
28
+ obj!: object;
29
+ }
30
+
31
+ export type AfterReadListener = (read: RecordedRead) => void;
32
+
33
+ export type AfterChangeOwnKeysListener = () => void;
34
+ export type Clazz = {
35
+ new(...args: any[]): unknown
36
+ }
37
+
38
+ export type GetIteratorValueProxiedFn<T> = (value: T) => T;
39
+ export type IteratorReturningProxiedValue<T> = Iterator<T> & {_getValueProxied: GetIteratorValueProxiedFn<T>}
40
+
41
+ /**
42
+ * A change operation that may later be serializable. Beeing able to store it in the transaction protocol of membrace-db. Or to syncronize live objects between server->client
43
+ */
44
+ export abstract class ChangeOperation {
45
+
46
+ /**
47
+ * Saved inputs as arguments for the do function
48
+ */
49
+ inputs?: Parameters<this["_do"]>
50
+
51
+ abstract _do(...inputs: unknown[]): {result: unknown, undoInfo: unknown}
52
+
53
+ _unDo(undoInfo: ReturnType<this["_do"]>["undoInfo"]): void {
54
+ throw new Error("Not yet implemented")
55
+ }
56
+
57
+ constructor() {
58
+ // Check if registered:
59
+ changeOperationsClasses.has(this.constructor.name) || throwError("Change operation was not registered. Please register the class first, with registerChangeOperationClass(...)");
60
+ }
61
+
62
+ withInputs(...inputs: Parameters<this["_do"]>): this {
63
+ this.inputs = inputs;
64
+ return this;
65
+ }
66
+
67
+ do(): ReturnType<this["_do"]>["undoInfo"] {
68
+ if(this.inputs === undefined) throw new Error("inputs not set");
69
+
70
+ return this._do(...this.inputs).result;
71
+ }
72
+ }
73
+
74
+ const changeOperationsClasses = new Map<string, typeof ChangeOperation>();
75
+ export function registerChangeOperationClass(clazz: typeof ChangeOperation) {
76
+ const name = clazz.name as string;
77
+ name || throwError("Change operation class does not have a name. Is it an anonymous class?")
78
+ !(changeOperationsClasses.has(name) && changeOperationsClasses.get(name) !== clazz) || throwError("Another change operation class is already registered under the name: " + name);
79
+ changeOperationsClasses.set(name, clazz);
80
+ }
81
+
82
+
83
+
84
+ export type ChangeListener = (change: ChangeOperation) => void;
85
+
86
+ /**
87
+ * Registry for one possible potential target event type. I.e. a property of a certain object, or a more abstract one like: "some key of a certain object has changed".
88
+ */
89
+ export class EventHook {
90
+ /**
91
+ * Called before the change
92
+ * @param change
93
+ */
94
+ beforeListeners = new Set<ChangeListener>();
95
+
96
+ /**
97
+ * Called after the change
98
+ * @param change
99
+ */
100
+ afterListeners= new Set<ChangeListener>();
101
+
102
+ /**
103
+ * To be able to easily control the before and after for exactly the same change. It's an idea / no good use case found yet.
104
+ * @param change
105
+ * @param doChange
106
+ */
107
+ //interceptors = new Set<(change: RecordedChange, doChange: () => void) => void>();
108
+
109
+ fireBefore(change: ChangeOperation) {
110
+ this.beforeListeners.forEach(l => l(change));
111
+ }
112
+
113
+ fireAfter(change: ChangeOperation) {
114
+ this.afterListeners.forEach(l => l(change));
115
+ }
116
+ }
117
+
118
+
119
+ /**
120
+ * For use in proxy and direct
121
+ */
122
+ export interface DualUseTracker<T> {
123
+
124
+ /**
125
+ * Will return the handler when called through the handler
126
+ */
127
+ get _watchedProxyHandler(): IWatchedProxyHandler_common | undefined;
128
+
129
+ /**
130
+ * The original (unproxied) object
131
+ */
132
+ get _target(): T
133
+ }
134
+
135
+ //@ts-ignore
136
+ export function dualUseTracker_callOrigMethodOnTarget<O extends object, M extends keyof O>(tracker: DualUseTracker<O>, methodName: M, args: unknown[]): ReturnType<O[M]> {
137
+ const target = tracker._target;
138
+ const method = tracker._watchedProxyHandler !== undefined?target[methodName]:Object.getPrototypeOf(Object.getPrototypeOf(tracker))[methodName];
139
+ return method.apply(target, args);
140
+ }
141
+
142
+ /**
143
+ * Like Object.getOwnPropertyDescriptor. But for all parent classes
144
+ * @param o
145
+ * @param p
146
+ */
147
+ export function getPropertyDescriptor(o: object, p: PropertyKey): PropertyDescriptor | undefined {
148
+ let result = Object.getOwnPropertyDescriptor(o, p);
149
+ if(result !== undefined) {
150
+ return result;
151
+ }
152
+ let proto = Object.getPrototypeOf(o);
153
+ if(proto !== null) {
154
+ return getPropertyDescriptor(proto, p);
155
+ }
156
+ }
157
+
158
+ export type GetterFlags = {
159
+ origHadGetter?: boolean
160
+ }
161
+ export type SetterFlags = {
162
+ origHadSetter?: boolean
163
+ }
164
+
165
+ const runAndCallListenersOnce_after_listeners = new Map<object, Set<() => void>>();
166
+
167
+ /**
168
+ * Used by runChangeOperation
169
+ */
170
+ class ChangeCall {
171
+ fired_beforeListeners = new Set<ChangeListener>();
172
+ afterListeners = new Set<ChangeListener>();
173
+
174
+ /**
175
+ * "binds" the ChangeOperation parameter to the afterListeners
176
+ */
177
+ paramsForAfterListeners = new Map<ChangeListener, ChangeOperation>();
178
+ }
179
+
180
+ const runChangeOperation_Calls = newDefaultMap<object, ChangeCall>(()=> new ChangeCall());
181
+
182
+ /**
183
+ * Informs hooksToServe's beforeListeners + executes changeOperation + informs hooksToServe's afterListeners.
184
+ * All this while preventing listeners from beeing called twice (this is the main purpose of this function!). Even during the same operation (call) that spans a call stack (the stack can go through multiple proxy layers)
185
+ * <p>
186
+ * This function is needed, because there's some overlapping of concerns in listener types, especially for Arrays. Also internal methods may again call the set method which itsself wants to call the propertychange_listeners.
187
+ * </p>
188
+ * @param forTarget object to sync on. All hooks passed to nested runChangeOperation calls will only be fired once.
189
+ * @param paramForListeners the parameter for the change listeners. It won't be run by this function / it's just the parameter. When setting to undefined, it indicates that this runChangeOperation call is only to wrap multiple nested calls / sync them on targetObject. The default anyChange hook won't be called at this level either.
190
+ * @param hooksToServe these hooks will be called (not twice, as mentioned).
191
+ * @param changeOperationFn
192
+ */
193
+ export function runChangeOperation<R>(forTarget: object, paramForListeners: ChangeOperation | undefined, hooksToServe: EventHook[], changeOperationFn: () => R) : R {
194
+ const synchronizeOn = getGlobalOrig(forTarget);
195
+ let isRootCall = !runChangeOperation_Calls.has(synchronizeOn); // is it not nested / the outermost call ?
196
+ const changeCall = runChangeOperation_Calls.get(synchronizeOn);
197
+ try {
198
+ if(paramForListeners) {
199
+ hooksToServe.push(getChangeHooksForObject(forTarget).anyChange); // Always serve this one as well
200
+ objectMembershipInGraphs.get(forTarget)?.forEach(graph => {
201
+ hooksToServe.push(graph._changeHook);
202
+ })
203
+
204
+ // Fire and register before-hooks:
205
+ hooksToServe.forEach(hook => {
206
+ hook.beforeListeners.forEach(listener => {
207
+ if (!changeCall.fired_beforeListeners.has(listener)) {
208
+ listener(paramForListeners); // fire
209
+ changeCall.fired_beforeListeners.add(listener);
210
+ }
211
+ })
212
+
213
+ hook.afterListeners.forEach(afterListener => {
214
+ if (!changeCall.afterListeners.has(afterListener)) {
215
+ changeCall.afterListeners.add(afterListener);
216
+ changeCall.paramsForAfterListeners.set(afterListener, paramForListeners); // Ensure, it is called with the proper changeOperation parameter afterwards. Otherwise stuff from a higher level facade would leak to a change listeners, registered in a lower facade
217
+ }
218
+ }); // schedule afterListeners
219
+ });
220
+ }
221
+
222
+ const result = changeOperationFn();
223
+
224
+ if(isRootCall) {
225
+ // call afterListeners:
226
+ for (const listener of changeCall.afterListeners) {
227
+ listener(changeCall.paramsForAfterListeners.get(listener)!); // fire
228
+ }
229
+ }
230
+
231
+ return result;
232
+ }
233
+ finally {
234
+ if (isRootCall) {
235
+ runChangeOperation_Calls.delete(synchronizeOn);
236
+ }
237
+ }
238
+ }
239
+
240
+
241
+ let esRuntimeBehaviourAlreadyChecked = false;
242
+ export function checkEsRuntimeBehaviour() {
243
+ if(esRuntimeBehaviourAlreadyChecked) {
244
+ return;
245
+ }
246
+ // **************************************************************************************************
247
+ // **** The following code is generated via `npm run dev:generateEsRuntimeBehaviourCheckerCode`: ****
248
+ // **************************************************************************************************
249
+ expectUsingMethodsOrFields(["a"], v=>v.at(0), ["at","length","0"])
250
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.concat("d","e","f"), ["concat","constructor",Symbol.isConcatSpreadable,"length","0","1","2"])
251
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.map(x=>read(x)), ["map","length","constructor","0","1","2"])
252
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.forEach(x=>read(x)), ["forEach","length","0","1","2"])
253
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.join(","), ["join","length","0","1","2"])
254
+ expectUsingMethodsOrFields(["a","b","c","d"], v=>v.slice(1,3), ["slice","length","constructor","1","2"])
255
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.some(x=>x==="a"), ["some","length","0"])
256
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.filter(x=>x==="a"), ["filter","length","constructor","0","1","2"])
257
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.find(x=>x==="a"), ["find","length","0"])
258
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.every(x=>x==="a"), ["every","length","0","1"])
259
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.findIndex(x=>x==="a"), ["findIndex","length","0"])
260
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.includes("b",1), ["includes","length","1"])
261
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.indexOf("b",1), ["indexOf","length","1"])
262
+ expectUsingMethodsOrFields(["a","b","c"], v=>v[Symbol.iterator]().next(), [Symbol.iterator,"length","0"])
263
+ expectUsingMethodsOrFields(["a","b","b"], v=>v.lastIndexOf("b",1), ["lastIndexOf","length","1"])
264
+ expectUsingMethodsOrFields(["a","b","b"], v=>v.reduce((p,c)=>p+c), ["reduce","length","0","1","2"])
265
+ expectUsingMethodsOrFields(["a","b","b"], v=>v.reduceRight((p,c)=>p+c), ["reduceRight","length","2","1","0"])
266
+ expectUsingMethodsOrFields(["a","b","b"], v=>v.toLocaleString(), ["toLocaleString","length","0","1","2"])
267
+ expectUsingMethodsOrFields(["a","b","b"], v=>v.toString(), ["toString","join","length","0","1","2"])
268
+ expectUsingMethodsOrFields(["a","b","c"], v=>v.unshift("_a","_b"), ["length","2","1","0"])
269
+ expectUsingMethodsOrFields(["a","b","c","d"], v=>v.splice(1,2,"newB","newC","newX"), ["length","1","2","3"])
270
+ expectUsingMethodsOrFields(["a","b","c","d"], v=>v.copyWithin(3,1,3), ["length","1","0","2","3"])
271
+ expectUsingMethodsOrFields(["a","b","c","d"], v=>v.reverse(), ["length","0","3","1","2"])
272
+ //@ts-ignore
273
+ if([].values().forEach) { // Runtime supports these iterator functions like forEach, filter, ....
274
+ expectUsingMethodsOrFields(["a","b","c"][Symbol.iterator](), it=>it.forEach(x=>x), ["forEach","next"])
275
+ expectUsingMethodsOrFields(["a","b","c"][Symbol.iterator](), it=>it.filter(x=>x==="b"), ["filter","next"])
276
+ expectUsingMethodsOrFields(["a","b","c"][Symbol.iterator](), it=>it.take(2), ["take","next"])
277
+ expectUsingMethodsOrFields(["a","b","c"][Symbol.iterator](), it=>it.toArray(), ["toArray","next"])
278
+ }
279
+
280
+
281
+
282
+
283
+ // **************************************************************************************************
284
+ // **************************************************************************************************
285
+ // **************************************************************************************************
286
+
287
+ function expectUsingMethodsOrFields<T extends object>(orig: T, tester: (orig: T) => void, expectedMethodsOrFields: Array<string | symbol> ) {
288
+ // Run the tester and record used methods/fields:
289
+ const usedMethodsOrFields = new Set<string | symbol>();
290
+ const proxy = new Proxy(orig, {
291
+ get(target: T, p: string | symbol, receiver: any): any {
292
+ usedMethodsOrFields.add(p)
293
+ if(p === "next") {
294
+ //@ts-ignore
295
+ return (...args: unknown[]) => target.next(...args); // .next() method must run on target, not on proxy
296
+ }
297
+ //@ts-ignore
298
+ return target[p];
299
+ }
300
+ })
301
+ read(tester(proxy));
302
+
303
+ !expectedMethodsOrFields.some(mf => mf !== "constructor" && !usedMethodsOrFields.has(mf)) || throwError(new Error(`The javascript runtime is not behaving as expected. Please report this as a bug along with your javascript runtime (or Browser) version`))
304
+ }
305
+ esRuntimeBehaviourAlreadyChecked = true;
306
+ }
307
+
308
+ export interface IWatchedProxyHandler_common {
309
+ /**
310
+ * Registers the Read to this WatchedProxyHandler and fires it on the WatchedFacade (informs WatchedFacade's listeners)
311
+ * @param read
312
+ */
313
+ fireAfterRead(read: RecordedReadOnProxiedObject): void;
314
+
315
+ getFacade(): ProxyFacade<any>
316
+ }
317
+
318
+ export interface ForWatchedProxyHandler<T> extends DualUseTracker<T> {
319
+ /**
320
+ * Will return the handler when called through the handler
321
+ */
322
+ get _watchedProxyHandler(): IWatchedProxyHandler_common;
323
+
324
+ /**
325
+ * The original (unproxied) object
326
+ */
327
+ get _target(): T
328
+ }
329
+
330
+ /**
331
+ * Configures tracking behaviour for a certain class
332
+ */
333
+ export abstract class ClassTrackingConfiguration {
334
+ /**
335
+ * For which is this config?
336
+ */
337
+ abstract clazz: Clazz // TODO: Minor: better type than Clazz.
338
+
339
+ worksForSubclasses = false;
340
+
341
+ readTracker?: Clazz;
342
+ changeTracker?: Clazz;
343
+ /**
344
+ * Built-in Methods, which are using fields / calling methods on the proxy transparently/loyally, so those methods don't call/use internal stuff directly.
345
+ * Tested with, see dev_generateEsRuntimeBehaviourCheckerCode.ts
346
+ * May include read-only / reader methods
347
+ */
348
+ knownHighLevelMethods = new Set<ObjKey>();
349
+ /**
350
+ * Non-high level. These fire `RecordedUnspecificRead`s then. So better implement them instead to fire i.e RecordedArrayValuesRead.
351
+ */
352
+ readOnlyMethods = new Set<ObjKey>();
353
+
354
+ /**
355
+ * Non-high level. Same as above: better implement them
356
+ */
357
+ readOnlyFields = new Set<ObjKey>();
358
+
359
+ /**
360
+ * Default, if not listed as high-level method
361
+ */
362
+ receiverMustBeNonProxied=true;
363
+
364
+ /**
365
+ * Makes the WatchedProxyFacade's handler also track/fire reads for methods that are not **directly** in the this.readTracker class.
366
+ */
367
+ trackTreads=true;
368
+
369
+ /**
370
+ * (For Array:) Flags to track setting properties, meaning changes are not only done by calling methods. This will use a Proxy (install a Proxy as Prototype).
371
+ */
372
+ trackSettingObjectProperties=false;
373
+
374
+ /**
375
+ * Wrap the results of methods which are not in the readTracker or changeTracker in proxies
376
+ * Take caution when enabling this. It is not always a good idea. I.e. Map#entries() return new intermediates arrays [] and these will then also be proxied and result in a false positive something-has-changed detection when comparing recorded Reads.
377
+ */
378
+ proxyUnhandledMethodResults=false
379
+
380
+ /**
381
+ * Lists read and changeTracker as far as they're present
382
+ */
383
+ getTrackerClasses(): Clazz[] {
384
+ const result = [];
385
+ if(this.readTracker !== undefined) {
386
+ result.push(this.readTracker);
387
+ }
388
+ if(this.changeTracker !== undefined) {
389
+ result.push(this.changeTracker);
390
+ }
391
+ return result;
392
+ }
393
+ }
394
+
395
+ export function recordedReadsArraysAreEqual(a: RecordedRead[], b: RecordedRead[]) {
396
+ return arraysAreEqualsByPredicateFn(a, b, (a, b) => a.equals(b));
397
+ }
398
+
399
+ /**
400
+ * Patches the iterator so it runs the value through the translateFn
401
+ * @param iterator
402
+ * @param translateFn
403
+ */
404
+ export function makeIteratorTranslateValue<V, IT extends Iterator<V>>(iterator: IT, translateFn: (value: V) => V): IT {
405
+ const originalNext = iterator.next;
406
+
407
+ function next(this: Iterator<V>, ...args: unknown[]): ReturnType<Iterator<V>["next"]> {
408
+ const result = originalNext.apply(this, args as [any]);
409
+ if(!result.done) {
410
+ result.value = translateFn(result.value);
411
+ }
412
+ return result;
413
+ }
414
+ iterator.next = next; // Patch iterator
415
+ return iterator;
416
+ }
417
+
418
+
419
+ /**
420
+ * Base for ProxyFacades and change-tracking of original objects (without proxy facades) See {@see changeTrackedOriginaObjects the changeTrackedOriginaObjects global instance}
421
+ */
422
+ export class PartialGraph {
423
+ /**
424
+ * True means, it spreads it's self when members are read or set. Not yet implemented for non-proxy-facades.
425
+ * Always true for proxy-facade subclasses (that's their job).
426
+ */
427
+ viral = false;
428
+
429
+ /**
430
+ * Called after a change has been made to any object inside this graph
431
+ * Note: There are also listeners for specified properties/situations (which are more capable)
432
+ * @protected
433
+ */
434
+ _changeHook = new EventHook()
435
+
436
+ /**
437
+ *
438
+ * @param listener Called when a change is made to any object inside this graph.
439
+ * The listener is called when the change is not yet written unlike {@see onAfterChange}. So throwing an exception in the listener will prevent the actual change from happening.
440
+ */
441
+ onBeforeChange(listener: ChangeListener) {
442
+ this._changeHook.beforeListeners.add(listener);
443
+ }
444
+
445
+ /**
446
+ * Unregister listener from {@see PartialGraph#onBeforeChange}
447
+ * @param listener
448
+ */
449
+ offBeforeChange(listener: ChangeListener) {
450
+ this._changeHook.beforeListeners.delete(listener);
451
+ }
452
+
453
+ /**
454
+ *
455
+ * @param listener Called after a change has been made to any object inside this graph
456
+ */
457
+ onAfterChange(listener: ChangeListener) {
458
+ this._changeHook.afterListeners.add(listener);
459
+ }
460
+
461
+ /**
462
+ * Unregister listener from {@see PartialGraph#onAfterChange}
463
+ * @param listener
464
+ */
465
+ offAfterChange(listener: ChangeListener) {
466
+ this._changeHook.afterListeners.delete(listener);
467
+ }
468
+
469
+ hasObj(obj: object) {
470
+ return objectMembershipInGraphs.get(obj)?.has(this);
471
+ }
472
+
473
+ _register(obj: object) {
474
+ objectMembershipInGraphs.add(obj, this);
475
+ }
476
+ }
477
+
478
+ export const objectMembershipInGraphs = new WeakMapSet<object, PartialGraph>();
479
+
480
+ /**
481
+ * TODO: Implement subclasses
482
+ */
483
+ export class UnspecificObjectChange extends ChangeOperation {
484
+ constructor(target?: object) {
485
+ super();
486
+ if (target !== undefined) {
487
+ //@ts-ignore
488
+ this.inputs = [target, /* state of target AFTER the opertation*/];
489
+ }
490
+ }
491
+
492
+ _do(...inputs: unknown[]) {
493
+ // TODO: restore state after
494
+ return {result: undefined, undoInfo: undefined};
495
+ }
496
+
497
+ _unDo(undoInfo: ReturnType<this["_do"]>["undoInfo"]): void {
498
+ throw new Error("Not yet implemented");
499
+ }
500
+ }
501
+ registerChangeOperationClass(UnspecificObjectChange);
@@ -0,0 +1,10 @@
1
+ /**
2
+ *
3
+ */
4
+ declare function outputExpecterCode<T extends object>(orig: T | (() => T), fn: (proxy: T) => void): void;
5
+ /**
6
+ * Just do something the runtime can't optimize away
7
+ * @param value
8
+ */
9
+ declare function read(value: any): void;
10
+ //# sourceMappingURL=dev_generateEsRuntimeBehaviourCheckerCode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev_generateEsRuntimeBehaviourCheckerCode.d.ts","sourceRoot":"","sources":["dev_generateEsRuntimeBehaviourCheckerCode.ts"],"names":[],"mappings":"AA4CA;;GAEG;AACH,iBAAS,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAM,IAAI,QA0BzF;AAED;;;GAGG;AACH,iBAAS,IAAI,CAAC,KAAK,EAAE,GAAG,QAIvB"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ // **** See the function common.ts#checkEsRuntimeBehaviour ***
3
+ // Array:
4
+ outputExpecterCode(["a"], (v) => v.at(0));
5
+ outputExpecterCode(["a", "b", "c"], (v) => v.concat("d", "e", "f"));
6
+ outputExpecterCode(["a", "b", "c"], (v) => v.map(x => read(x)));
7
+ outputExpecterCode(["a", "b", "c"], (v) => v.forEach(x => read(x)));
8
+ outputExpecterCode(["a", "b", "c"], (v) => v.join(","));
9
+ //outputExpecterCode(["a", "b", "c"], (v) => v.keys());
10
+ //outputExpecterCode(["a", "b", "c"], (v) => v.values());
11
+ outputExpecterCode(["a", "b", "c", "d"], (v) => v.slice(1, 3));
12
+ outputExpecterCode(["a", "b", "c"], (v) => v.some(x => x === "a"));
13
+ outputExpecterCode(["a", "b", "c"], (v) => v.filter(x => x === "a"));
14
+ outputExpecterCode(["a", "b", "c"], (v) => v.find(x => x === "a"));
15
+ //outputExpecterCode(["a", "b", "c"], (v) => v.entries());
16
+ outputExpecterCode(["a", "b", "c"], (v) => v.every(x => x === "a"));
17
+ outputExpecterCode(["a", "b", "c"], (v) => v.findIndex(x => x === "a"));
18
+ outputExpecterCode(["a", "b", "c"], (v) => v.includes("b", 1));
19
+ outputExpecterCode(["a", "b", "c"], (v) => v.indexOf("b", 1));
20
+ outputExpecterCode(["a", "b", "c"], (v) => v[Symbol.iterator]().next());
21
+ outputExpecterCode(["a", "b", "b"], (v) => v.lastIndexOf("b", 1));
22
+ outputExpecterCode(["a", "b", "b"], (v) => v.reduce((p, c) => p + c));
23
+ outputExpecterCode(["a", "b", "b"], (v) => v.reduceRight((p, c) => p + c));
24
+ outputExpecterCode(["a", "b", "b"], (v) => v.toLocaleString());
25
+ outputExpecterCode(["a", "b", "b"], (v) => v.toString());
26
+ outputExpecterCode(["a", "b", "c"], (v) => v.unshift("_a", "_b"));
27
+ outputExpecterCode(["a", "b", "c", "d"], v => v.splice(1, 2, "newB", "newC", "newX"));
28
+ outputExpecterCode(["a", "b", "c", "d"], v => v.copyWithin(3, 1, 3));
29
+ outputExpecterCode(["a", "b", "c", "d"], v => v.reverse());
30
+ // Iterator
31
+ console.log("if([].values().forEach) { // Runtime supports these iterator functions like forEach, filter, .... ");
32
+ outputExpecterCode(() => ["a", "b", "c"][Symbol.iterator](), it => it.forEach(x => x));
33
+ outputExpecterCode(() => ["a", "b", "c"][Symbol.iterator](), it => it.filter(x => x === "b"));
34
+ outputExpecterCode(() => ["a", "b", "c"][Symbol.iterator](), it => it.take(2));
35
+ outputExpecterCode(() => ["a", "b", "c"][Symbol.iterator](), it => it.toArray());
36
+ console.log("}");
37
+ // Set:
38
+ //outputExpecterCode(new Set<string>(["a","b","c"]), v => v.forEach(i => read(i))) // TypeError: Method Set.prototype.forEach called on incompatible receiver #<Set>
39
+ //outputExpecterCode(new Set<string>(["a","b","c"]), v => v.intersection(new Set<string>(["b","c","e"]))) // TypeError: Method Set.prototype.intersection called on incompatible receiver #<Set>
40
+ /**
41
+ *
42
+ */
43
+ function outputExpecterCode(orig, fn) {
44
+ let origJS = JSON.stringify(orig);
45
+ if (typeof orig === "function") {
46
+ origJS = orig.toString().replace(/\s+/g, " ").replace(/^\(\)=>/, "").toString();
47
+ orig = orig();
48
+ }
49
+ const usedFields = new Set();
50
+ const proxy = new Proxy(orig, {
51
+ get(target, p, receiver) {
52
+ usedFields.add(p);
53
+ if (p === "next") {
54
+ //@ts-ignore
55
+ return (...args) => target.next(...args); // .next() method must run on target, not on proxy
56
+ }
57
+ //@ts-ignore
58
+ return target[p];
59
+ }
60
+ });
61
+ read(fn(proxy));
62
+ console.log(`expectUsingMethodsOrFields(${origJS}, ${fnToString(fn)}, [${[...usedFields.values()].map(f => typeof f === "string" ? `"${f}"` : `${f.toString().replace(/(^Symbol\()|(\)$)/g, "")}`).join(",")}])`);
63
+ function fnToString(fn) {
64
+ return fn.toString().replace(/\s+/g, " ").toString();
65
+ }
66
+ }
67
+ /**
68
+ * Just do something the runtime can't optimize away
69
+ * @param value
70
+ */
71
+ function read(value) {
72
+ if (("" + value) == "blaaxyxzzzsdf") {
73
+ throw new Error("should never get here");
74
+ }
75
+ }
76
+ //# sourceMappingURL=dev_generateEsRuntimeBehaviourCheckerCode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev_generateEsRuntimeBehaviourCheckerCode.js","sourceRoot":"","sources":["dev_generateEsRuntimeBehaviourCheckerCode.ts"],"names":[],"mappings":"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"}