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/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export {RecordedRead, RecordedReadOnProxiedObject, ClassTrackingConfiguration, dualUseTracker_callOrigMethodOnTarget, IteratorReturningProxiedValue, GetIteratorValueProxiedFn, DualUseTracker, ForWatchedProxyHandler} from "./common"
2
+ export {ProxyFacade, FacadeProxyHandler, invalidateObject, getGlobalOrig} from "./proxyFacade";
3
+ export {deleteProperty, changeTrackedOrigObjects, installChangeTracker} from "./origChangeTracking"
4
+ export {RecordedArrayValuesRead} from "./class-trackers/Array"
5
+ export {RecordedMap_has, RecordedMap_get, RecordedMapEntriesRead, RecordedMapKeysRead, RecordedMapValuesRead} from "./class-trackers/Map"
6
+ export {RecordedSet_has, RecordedSetValuesRead} from "./class-trackers/Set"
7
+ export {RecordedValueRead, RecordedUnspecificRead, RecordedPropertyRead,RecordedOwnKeysRead, WatchedProxyFacade, WatchedProxyHandler} from "./watchedProxyFacade";
package/index_esm.mjs ADDED
@@ -0,0 +1,44 @@
1
+ // A wrapper file for ESM to avoid the 'dual package hazard'. See https://nodejs.org/api/packages.html#approach-1-use-an-es-module-wrapper
2
+
3
+ import cjsCommon from "./common.js"
4
+ export const RecordedRead = cjsCommon.RecordedRead;
5
+ export const RecordedReadOnProxiedObject = cjsCommon.RecordedReadOnProxiedObject;
6
+ export const ClassTrackingConfiguration = cjsCommon.ClassTrackingConfiguration;
7
+ export const dualUseTracker_callOrigMethodOnTarget = cjsCommon.dualUseTracker_callOrigMethodOnTarget;
8
+ export const IteratorReturningProxiedValue = cjsCommon.IteratorReturningProxiedValue;
9
+ export const GetIteratorValueProxiedFn = cjsCommon.GetIteratorValueProxiedFn;
10
+ export const DualUseTracker = cjsCommon.DualUseTracker;
11
+ export const ForWatchedProxyHandler = cjsCommon.ForWatchedProxyHandler
12
+
13
+ import cjsProxyFacade from "./proxyFacade"
14
+ export const ProxyFacade = cjsProxyFacade.ProxyFacade;
15
+ export const FacadeProxyHandler = cjsProxyFacade.FacadeProxyHandler;
16
+ export const invalidateObject = cjsProxyFacade.invalidateObject;
17
+ export const getGlobalOrig = cjsProxyFacade.getGlobalOrig;
18
+
19
+ import cjsOrigChangeTracking from "./origChangeTracking"
20
+ export const deleteProperty = cjsOrigChangeTracking.deleteProperty;
21
+ export const changeTrackedOrigObjects = cjsOrigChangeTracking.changeTrackedOrigObjects;
22
+ export const installChangeTracker = cjsOrigChangeTracking.installChangeTracker;
23
+
24
+ import cjsClassTrackers_Array from "./class-trackers/Array";
25
+ export const RecordedArrayValuesRead = cjsClassTrackers_Array.RecordedArrayValuesRead
26
+
27
+ import cjsClassTrackers_Map from "./class-trackers/Map";
28
+ export const RecordedMap_has = cjsClassTrackers_Map.RecordedMap_has;
29
+ export const RecordedMap_get = cjsClassTrackers_Map.RecordedMap_get;
30
+ export const RecordedMapEntriesRead = cjsClassTrackers_Map.RecordedMapEntriesRead;
31
+ export const RecordedMapKeysRead = cjsClassTrackers_Map.RecordedMapKeysRead;
32
+ export const RecordedMapValuesRead = cjsClassTrackers_Map.RecordedMapValuesRead;
33
+
34
+ import cjsClassTrackers_Set from "./class-trackers/Set";
35
+ export const RecordedSet_has = cjsClassTrackers_Set.RecordedSet_has;
36
+ export const RecordedSetValuesRead = cjsClassTrackers_Set.RecordedSetValuesRead;
37
+
38
+ import cjsWatchedProxyFacade from "./watchedProxyFacade"
39
+ export const RecordedValueRead = cjsWatchedProxyFacade.RecordedValueRead;
40
+ export const RecordedUnspecificRead = cjsWatchedProxyFacade.RecordedUnspecificRead;
41
+ export const RecordedPropertyRead = cjsWatchedProxyFacade.RecordedPropertyRead;
42
+ export const RecordedOwnKeysRead = cjsWatchedProxyFacade.RecordedOwnKeysRead;
43
+ export const WatchedProxyFacade = cjsWatchedProxyFacade.WatchedProxyFacade;
44
+ export const WatchedProxyHandler = cjsWatchedProxyFacade.WatchedProxyHandler;
@@ -0,0 +1,43 @@
1
+ import { ClassTrackingConfiguration, EventHook, ObjKey } from "./common";
2
+ /**
3
+ * Contains change listeners for one specific object.
4
+ * Note for specificity: There will be only one of the **change** events fired. The Recorded...Read.onChange handler will add the listeners to all possible candidates. It's this way around.
5
+ * Does not apply to setterInvoke.. These are fired in addition (not thought through for all situations)
6
+ */
7
+ declare class ObjectChangeHooks {
8
+ /**
9
+ * For writes on **setters** (also if these are the same/unchanged values)
10
+ */
11
+ setterInvoke: import("./Util").DefaultMap<ObjKey, EventHook>;
12
+ changeSpecificProperty: import("./Util").DefaultMap<ObjKey, EventHook>;
13
+ changeAnyProperty: EventHook;
14
+ /**
15
+ * Means, the result of Object.keys will be different after the change. All iterations over the object/arrays's keys or values are informed that there was a change. Individual {@link changeSpecificProperty} are not affected!
16
+ */
17
+ changeOwnKeys: EventHook;
18
+ /**
19
+ * These will always be called, no matter how specific a change is
20
+ */
21
+ anyChange: EventHook;
22
+ /**
23
+ *
24
+ */
25
+ unspecificChange: EventHook;
26
+ }
27
+ export declare const changeHooksForObject: WeakMap<object, ObjectChangeHooks>;
28
+ export declare function getChangeHooksForObject(obj: object): ObjectChangeHooks;
29
+ export declare class ObjectProxyHandler implements ProxyHandler<object> {
30
+ target: object;
31
+ origPrototype: object | null;
32
+ proxy: object;
33
+ trackingConfig?: ClassTrackingConfiguration;
34
+ constructor(target: object, trackingConfig: ClassTrackingConfiguration | undefined);
35
+ installSetterTrap(key: ObjKey): void;
36
+ protected withUnspecificChange<R>(changeFn: () => R): R;
37
+ get(fake_target: object, key: ObjKey, receiver: any): any;
38
+ set(fake_target: object, key: ObjKey, value: any, receiver: any): boolean;
39
+ getPrototypeOf(target: object): object | null;
40
+ defineProperty(target: object, property: string | symbol, attributes: PropertyDescriptor): boolean;
41
+ }
42
+ export {};
43
+ //# sourceMappingURL=objectChangeTracking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"objectChangeTracking.d.ts","sourceRoot":"","sources":["objectChangeTracking.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,0BAA0B,EAC1B,SAAS,EAGT,MAAM,EAIT,MAAM,UAAU,CAAC;AAElB;;;;GAIG;AACH,cAAM,iBAAiB;IACnB;;OAEG;IACH,YAAY,iDAA4D;IACxE,sBAAsB,iDAA4D;IAClF,iBAAiB,YAAmB;IAEpC;;OAEG;IACH,aAAa,YAAmB;IAChC;;OAEG;IACH,SAAS,YAAmB;IAE5B;;OAEG;IACH,gBAAgB,YAAmB;CACtC;AAID,eAAO,MAAM,oBAAoB,oCAA2C,CAAC;AAC7E,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,qBAMlD;AAED,qBAAa,kBAAmB,YAAW,YAAY,CAAC,MAAM,CAAC;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,0BAA0B,CAAA;gBAE/B,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,0BAA0B,GAAG,SAAS;IAmBlF,iBAAiB,CAAC,GAAG,EAAE,MAAM;IAkE7B,SAAS,CAAC,oBAAoB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC;IAIvD,GAAG,CAAC,WAAW,EAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAC,GAAG,GAAG,GAAG;IA2EvD,GAAG,CAAC,WAAW,EAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAC,GAAG,EAAE,QAAQ,EAAC,GAAG;IAkB5D,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI7C,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,OAAO;CAIrG"}
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ObjectProxyHandler = exports.changeHooksForObject = void 0;
4
+ exports.getChangeHooksForObject = getChangeHooksForObject;
5
+ /**
6
+ * Listeners for one object
7
+ */
8
+ const Util_1 = require("./Util");
9
+ const common_1 = require("./common");
10
+ /**
11
+ * Contains change listeners for one specific object.
12
+ * Note for specificity: There will be only one of the **change** events fired. The Recorded...Read.onChange handler will add the listeners to all possible candidates. It's this way around.
13
+ * Does not apply to setterInvoke.. These are fired in addition (not thought through for all situations)
14
+ */
15
+ class ObjectChangeHooks {
16
+ constructor() {
17
+ /**
18
+ * For writes on **setters** (also if these are the same/unchanged values)
19
+ */
20
+ this.setterInvoke = (0, Util_1.newDefaultMap)(() => new common_1.EventHook());
21
+ this.changeSpecificProperty = (0, Util_1.newDefaultMap)(() => new common_1.EventHook());
22
+ this.changeAnyProperty = new common_1.EventHook();
23
+ /**
24
+ * Means, the result of Object.keys will be different after the change. All iterations over the object/arrays's keys or values are informed that there was a change. Individual {@link changeSpecificProperty} are not affected!
25
+ */
26
+ this.changeOwnKeys = new common_1.EventHook();
27
+ /**
28
+ * These will always be called, no matter how specific a change is
29
+ */
30
+ this.anyChange = new common_1.EventHook();
31
+ /**
32
+ *
33
+ */
34
+ this.unspecificChange = new common_1.EventHook();
35
+ }
36
+ }
37
+ exports.changeHooksForObject = new WeakMap();
38
+ function getChangeHooksForObject(obj) {
39
+ let result = exports.changeHooksForObject.get(obj);
40
+ if (result === undefined) {
41
+ exports.changeHooksForObject.set(obj, result = new ObjectChangeHooks());
42
+ }
43
+ return result;
44
+ }
45
+ class ObjectProxyHandler {
46
+ constructor(target, trackingConfig) {
47
+ this.target = target;
48
+ this.trackingConfig = trackingConfig;
49
+ this.origPrototype = Object.getPrototypeOf(target);
50
+ Object.getOwnPropertyNames(target).forEach(key => {
51
+ if (key === "length" && Array.isArray(target)) {
52
+ return; // Leave the length property as is. It won't be set directly anyway
53
+ }
54
+ this.installSetterTrap(key);
55
+ });
56
+ // Create proxy:
57
+ //const targetForProxy = {}; // The virtual way
58
+ const targetForProxy = target; // Preserves Object.keys and instanceof behaviour :), iterators and other stuff. But the downside with this is, that it does not allow to proxy read only properties
59
+ this.proxy = new Proxy(targetForProxy, this);
60
+ }
61
+ installSetterTrap(key) {
62
+ let target = this.target;
63
+ let origDescriptor = (0, common_1.getPropertyDescriptor)(target, key);
64
+ //@ts-ignore
65
+ let currentValue = (origDescriptor === null || origDescriptor === void 0 ? void 0 : origDescriptor.value /* performance */) || target[key];
66
+ const origSetter = origDescriptor === null || origDescriptor === void 0 ? void 0 : origDescriptor.set;
67
+ const origGetter = origDescriptor === null || origDescriptor === void 0 ? void 0 : origDescriptor.get;
68
+ let origOwnDescriptor = Object.getOwnPropertyDescriptor(target, key);
69
+ if (origOwnDescriptor !== undefined) {
70
+ if (origOwnDescriptor.configurable !== true) {
71
+ throw new Error("Cannot delete non- 'configurable' property:" + String(key));
72
+ }
73
+ //@ts-ignore
74
+ delete target[key]; // delete the old, or the following Object.defineProperty will conflict
75
+ }
76
+ const newSetter = (newValue) => {
77
+ const changeHooksForTarget = getChangeHooksForObject(target);
78
+ if (origSetter !== undefined) {
79
+ (0, common_1.runChangeOperation)(target, new common_1.UnspecificObjectChange(target), [changeHooksForTarget.setterInvoke.get(key)], () => {
80
+ origSetter.apply(target, [newValue]); // call the setter
81
+ });
82
+ return;
83
+ }
84
+ if (origGetter !== undefined) {
85
+ currentValue = origGetter.apply(target); // call the getter. Is this a good idea to refresh the value here?
86
+ throw new TypeError("Target originally had a getter and no setter but the property is set.");
87
+ }
88
+ //@ts-ignore
89
+ if (newValue !== currentValue) { // modify ?
90
+ // run change operation and call listeners:
91
+ const hooksToServe = [];
92
+ if (Array.isArray(target)) {
93
+ hooksToServe.push(changeHooksForTarget.unspecificChange);
94
+ }
95
+ hooksToServe.push(changeHooksForTarget.changeSpecificProperty.get(key));
96
+ hooksToServe.push(changeHooksForTarget.changeAnyProperty);
97
+ (0, common_1.runChangeOperation)(target, new common_1.UnspecificObjectChange(target), hooksToServe, () => {
98
+ //@ts-ignore
99
+ currentValue = newValue;
100
+ });
101
+ }
102
+ };
103
+ newSetter.origHadSetter = origSetter !== undefined;
104
+ const newGetter = () => {
105
+ if (origGetter !== undefined) {
106
+ currentValue = origGetter.apply(target); // call the getter
107
+ }
108
+ return currentValue;
109
+ };
110
+ newGetter.origHadGetter = origGetter !== undefined;
111
+ Object.defineProperty(target, key, {
112
+ set: newSetter,
113
+ get: newGetter,
114
+ enumerable: origOwnDescriptor !== undefined ? origOwnDescriptor === null || origOwnDescriptor === void 0 ? void 0 : origOwnDescriptor.enumerable : true,
115
+ configurable: true, // Allow to delete the property. Note that you should use the {@link deleteProperty} function
116
+ });
117
+ }
118
+ withUnspecificChange(changeFn) {
119
+ return (0, common_1.runChangeOperation)(this.target, new common_1.UnspecificObjectChange(this.target), [getChangeHooksForObject(this.target).unspecificChange], changeFn);
120
+ }
121
+ get(fake_target, key, receiver) {
122
+ var _a, _b, _c;
123
+ // Validity check
124
+ const target = this.target;
125
+ if (receiver !== target) {
126
+ throw new Error("Invalid state. Get was called on a different object than this write-tracker-proxy (which is set as the prototype) is for. Did you clone the object, resulting in shared prototypes?");
127
+ }
128
+ // Check for and use change tracker class:
129
+ const changeTrackerClass = (_a = this.trackingConfig) === null || _a === void 0 ? void 0 : _a.changeTracker;
130
+ if (changeTrackerClass !== undefined) {
131
+ let propOnSupervisor = Object.getOwnPropertyDescriptor(changeTrackerClass.prototype, key);
132
+ if (propOnSupervisor !== undefined) { // Supervisor class is responsible for the property (or method) ?
133
+ //@ts-ignore
134
+ if (propOnSupervisor.get) { // Prop is a getter?
135
+ return propOnSupervisor.get.apply(target);
136
+ }
137
+ else if (propOnSupervisor.value) { // Prop is a value, meaning a function. (Supervisors don't have fields)
138
+ return changeTrackerClass.prototype[key];
139
+ }
140
+ }
141
+ else {
142
+ const origValue = changeTrackerClass.prototype[key];
143
+ if (typeof origValue === "function") {
144
+ origMethod = origValue;
145
+ if ((_b = this.trackingConfig) === null || _b === void 0 ? void 0 : _b.knownHighLevelMethods.has(key)) {
146
+ return trapForHighLevelWriterMethod;
147
+ }
148
+ else if (!((_c = this.trackingConfig) === null || _c === void 0 ? void 0 : _c.readOnlyMethods.has(key)) && !(key in Object.prototype)) { // Read-write method that was not handled directly by change tracker class?
149
+ return trapForGenericWriterMethod; // Assume the worst, that it is a writer method
150
+ }
151
+ }
152
+ }
153
+ }
154
+ // return this.target[key]; // This line does not work because it does not consult ObjectProxyHandler#getPrototypeOf and therefore uses the actual tinkered prototype chain which has this proxy in there and calls get (endless recursion)
155
+ const propDesc = (0, common_1.getPropertyDescriptor)(target, key);
156
+ if (propDesc !== undefined) {
157
+ let result;
158
+ let getter = propDesc.get;
159
+ if (getter !== undefined) {
160
+ result = getter.apply(target);
161
+ }
162
+ else {
163
+ result = propDesc.value;
164
+ }
165
+ return result;
166
+ }
167
+ var origMethod = undefined;
168
+ /**
169
+ * Calls the unspecificChange listeners
170
+ * @param args
171
+ */
172
+ function trapForGenericWriterMethod(...args) {
173
+ if (this !== receiver) {
174
+ //throw new Error("Invalid state. Method was called on invalid target")
175
+ }
176
+ return (0, common_1.runChangeOperation)(target, new common_1.UnspecificObjectChange(target), [getChangeHooksForObject(target).unspecificChange], () => {
177
+ return origMethod.apply(this, args); // call original method
178
+ });
179
+ }
180
+ /**
181
+ * Wraps it in runAndCallListenersOnce_after
182
+ * @param args
183
+ */
184
+ function trapForHighLevelWriterMethod(...args) {
185
+ if (this !== receiver) {
186
+ //throw new Error("Invalid state. Method was called on invalid target")
187
+ }
188
+ return (0, common_1.runChangeOperation)(target, undefined, [], () => {
189
+ return origMethod.apply(this, args); // call original method
190
+ });
191
+ }
192
+ }
193
+ set(fake_target, key, value, receiver) {
194
+ // Validity check
195
+ if (receiver !== this.target) {
196
+ throw new Error("Invalid state. Set was called on a different object than this write-tracker-proxy (which is set as the prototype) is for. Did you clone the object, resulting in shared prototypes?");
197
+ }
198
+ (0, common_1.runChangeOperation)(this.target, new common_1.UnspecificObjectChange(this.target), [getChangeHooksForObject(this.target).changeOwnKeys], () => {
199
+ // if this "set" method got called, there is no setter trap installed yet
200
+ this.installSetterTrap(key);
201
+ //@ts-ignore
202
+ this.target[key] = value; // Set value again. this should call the setter trap
203
+ });
204
+ return true;
205
+ }
206
+ getPrototypeOf(target) {
207
+ return this.origPrototype;
208
+ }
209
+ defineProperty(target, property, attributes) {
210
+ throw new Error("Defineproperty not yet supported");
211
+ }
212
+ }
213
+ exports.ObjectProxyHandler = ObjectProxyHandler;
214
+ //# sourceMappingURL=objectChangeTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"objectChangeTracking.js","sourceRoot":"","sources":["objectChangeTracking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Listeners for one object
3
+ */
4
+ import {newDefaultMap} from "./Util";
5
+ import {
6
+ ClassTrackingConfiguration,
7
+ EventHook,
8
+ getPropertyDescriptor,
9
+ GetterFlags,
10
+ ObjKey,
11
+ runChangeOperation,
12
+ SetterFlags,
13
+ UnspecificObjectChange,
14
+ } from "./common";
15
+
16
+ /**
17
+ * Contains change listeners for one specific object.
18
+ * Note for specificity: There will be only one of the **change** events fired. The Recorded...Read.onChange handler will add the listeners to all possible candidates. It's this way around.
19
+ * Does not apply to setterInvoke.. These are fired in addition (not thought through for all situations)
20
+ */
21
+ class ObjectChangeHooks {
22
+ /**
23
+ * For writes on **setters** (also if these are the same/unchanged values)
24
+ */
25
+ setterInvoke = newDefaultMap<ObjKey, EventHook>( () => new EventHook());
26
+ changeSpecificProperty = newDefaultMap<ObjKey, EventHook>( () => new EventHook());
27
+ changeAnyProperty = new EventHook();
28
+
29
+ /**
30
+ * Means, the result of Object.keys will be different after the change. All iterations over the object/arrays's keys or values are informed that there was a change. Individual {@link changeSpecificProperty} are not affected!
31
+ */
32
+ changeOwnKeys = new EventHook();
33
+ /**
34
+ * These will always be called, no matter how specific a change is
35
+ */
36
+ anyChange = new EventHook();
37
+
38
+ /**
39
+ *
40
+ */
41
+ unspecificChange = new EventHook();
42
+ }
43
+
44
+
45
+
46
+ export const changeHooksForObject = new WeakMap<object, ObjectChangeHooks>();
47
+ export function getChangeHooksForObject(obj: object) {
48
+ let result = changeHooksForObject.get(obj);
49
+ if(result === undefined) {
50
+ changeHooksForObject.set(obj, result = new ObjectChangeHooks());
51
+ }
52
+ return result;
53
+ }
54
+
55
+ export class ObjectProxyHandler implements ProxyHandler<object> {
56
+ target: object;
57
+ origPrototype: object | null;
58
+ proxy: object;
59
+ trackingConfig?: ClassTrackingConfiguration
60
+
61
+ constructor(target: object, trackingConfig: ClassTrackingConfiguration | undefined) {
62
+ this.target = target;
63
+ this.trackingConfig = trackingConfig;
64
+ this.origPrototype = Object.getPrototypeOf(target);
65
+
66
+
67
+ Object.getOwnPropertyNames(target).forEach(key => {
68
+ if(key === "length" && Array.isArray(target)) {
69
+ return; // Leave the length property as is. It won't be set directly anyway
70
+ }
71
+ this.installSetterTrap(key)
72
+ });
73
+
74
+ // Create proxy:
75
+ //const targetForProxy = {}; // The virtual way
76
+ const targetForProxy=target // Preserves Object.keys and instanceof behaviour :), iterators and other stuff. But the downside with this is, that it does not allow to proxy read only properties
77
+ this.proxy = new Proxy(targetForProxy, this);
78
+ }
79
+
80
+ installSetterTrap(key: ObjKey) {
81
+ let target = this.target;
82
+ let origDescriptor = getPropertyDescriptor(target, key);
83
+ //@ts-ignore
84
+ let currentValue = origDescriptor?.value /* performance */ || target[key];
85
+ const origSetter = origDescriptor?.set;
86
+ const origGetter = origDescriptor?.get;
87
+
88
+ let origOwnDescriptor = Object.getOwnPropertyDescriptor(target, key);
89
+ if(origOwnDescriptor !== undefined) {
90
+ if(origOwnDescriptor.configurable !== true) {
91
+ throw new Error("Cannot delete non- 'configurable' property:" + String(key));
92
+ }
93
+ //@ts-ignore
94
+ delete target[key]; // delete the old, or the following Object.defineProperty will conflict
95
+ }
96
+
97
+ const newSetter= (newValue: any) => {
98
+ const changeHooksForTarget = getChangeHooksForObject(target);
99
+
100
+ if(origSetter !== undefined) {
101
+ runChangeOperation(target, new UnspecificObjectChange(target),[changeHooksForTarget.setterInvoke.get(key)],() => {
102
+ origSetter.apply(target, [newValue]); // call the setter
103
+ });
104
+ return;
105
+ }
106
+
107
+ if(origGetter !== undefined) {
108
+ currentValue = origGetter.apply(target); // call the getter. Is this a good idea to refresh the value here?
109
+ throw new TypeError("Target originally had a getter and no setter but the property is set.");
110
+ }
111
+
112
+ //@ts-ignore
113
+ if (newValue !== currentValue) { // modify ?
114
+ // run change operation and call listeners:
115
+ const hooksToServe: EventHook[] = [];
116
+ if(Array.isArray(target)) {
117
+ hooksToServe.push(changeHooksForTarget.unspecificChange);
118
+ }
119
+ hooksToServe.push(changeHooksForTarget.changeSpecificProperty.get(key))
120
+ hooksToServe.push(changeHooksForTarget.changeAnyProperty)
121
+ runChangeOperation(target, new UnspecificObjectChange(target),hooksToServe,() => {
122
+ //@ts-ignore
123
+ currentValue = newValue;
124
+ });
125
+ }
126
+
127
+ }
128
+ (newSetter as SetterFlags).origHadSetter = origSetter !== undefined;
129
+
130
+ const newGetter = () => {
131
+ if(origGetter !== undefined) {
132
+ currentValue = origGetter.apply(target); // call the getter
133
+ }
134
+ return currentValue;
135
+ }
136
+ (newGetter as GetterFlags).origHadGetter = origGetter !== undefined;
137
+
138
+ Object.defineProperty( target, key, { // TODO: [Performance optimization tipps, see js example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#description)
139
+ set: newSetter,
140
+ get: newGetter,
141
+ enumerable: origOwnDescriptor !== undefined?origOwnDescriptor?.enumerable:true,
142
+ configurable: true, // Allow to delete the property. Note that you should use the {@link deleteProperty} function
143
+ })
144
+ }
145
+
146
+ protected withUnspecificChange<R>(changeFn: () => R): R {
147
+ return runChangeOperation(this.target, new UnspecificObjectChange(this.target), [getChangeHooksForObject(this.target).unspecificChange], changeFn)
148
+ }
149
+
150
+ get(fake_target:object, key: ObjKey, receiver:any): any {
151
+ // Validity check
152
+ const target = this.target;
153
+
154
+ if(receiver !== target) {
155
+ throw new Error("Invalid state. Get was called on a different object than this write-tracker-proxy (which is set as the prototype) is for. Did you clone the object, resulting in shared prototypes?")
156
+ }
157
+
158
+ // Check for and use change tracker class:
159
+ const changeTrackerClass = this.trackingConfig?.changeTracker
160
+ if (changeTrackerClass !== undefined) {
161
+ let propOnSupervisor = Object.getOwnPropertyDescriptor(changeTrackerClass.prototype, key);
162
+ if (propOnSupervisor !== undefined) { // Supervisor class is responsible for the property (or method) ?
163
+ //@ts-ignore
164
+ if (propOnSupervisor.get) { // Prop is a getter?
165
+ return propOnSupervisor.get.apply(target)
166
+ } else if (propOnSupervisor.value) { // Prop is a value, meaning a function. (Supervisors don't have fields)
167
+ return changeTrackerClass.prototype[key];
168
+ }
169
+ }
170
+ else {
171
+ const origValue = changeTrackerClass.prototype[key]
172
+ if(typeof origValue === "function") {
173
+ origMethod = origValue;
174
+ if (this.trackingConfig?.knownHighLevelMethods.has(key)) {
175
+ return trapForHighLevelWriterMethod
176
+ } else if (!this.trackingConfig?.readOnlyMethods.has(key) && !(key as any in Object.prototype)) { // Read-write method that was not handled directly by change tracker class?
177
+ return trapForGenericWriterMethod // Assume the worst, that it is a writer method
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ // return this.target[key]; // This line does not work because it does not consult ObjectProxyHandler#getPrototypeOf and therefore uses the actual tinkered prototype chain which has this proxy in there and calls get (endless recursion)
184
+ const propDesc = getPropertyDescriptor(target, key)
185
+ if (propDesc !== undefined) {
186
+ let result: unknown;
187
+ let getter = propDesc.get;
188
+ if (getter !== undefined) {
189
+ result = getter.apply(target);
190
+ }
191
+ else {
192
+ result = propDesc.value;
193
+ }
194
+ return result;
195
+ }
196
+
197
+ var origMethod: ((this:unknown, ...args:unknown[]) => unknown) | undefined = undefined;
198
+ /**
199
+ * Calls the unspecificChange listeners
200
+ * @param args
201
+ */
202
+ function trapForGenericWriterMethod(this:object, ...args: unknown[]) {
203
+ if(this !== receiver) {
204
+ //throw new Error("Invalid state. Method was called on invalid target")
205
+ }
206
+ return runChangeOperation(target, new UnspecificObjectChange(target),[getChangeHooksForObject(target as Array<unknown>).unspecificChange],() => {
207
+ return origMethod!.apply(this, args); // call original method
208
+ });
209
+ }
210
+
211
+ /**
212
+ * Wraps it in runAndCallListenersOnce_after
213
+ * @param args
214
+ */
215
+ function trapForHighLevelWriterMethod(this:object, ...args: unknown[]) {
216
+ if(this !== receiver) {
217
+ //throw new Error("Invalid state. Method was called on invalid target")
218
+ }
219
+ return runChangeOperation(target, undefined,[],() => {
220
+ return origMethod!.apply(this, args); // call original method
221
+ });
222
+ }
223
+ }
224
+
225
+ set(fake_target:object, key: ObjKey, value:any, receiver:any) {
226
+ // Validity check
227
+ if(receiver !== this.target) {
228
+ throw new Error("Invalid state. Set was called on a different object than this write-tracker-proxy (which is set as the prototype) is for. Did you clone the object, resulting in shared prototypes?")
229
+ }
230
+
231
+ runChangeOperation(this.target, new UnspecificObjectChange(this.target),[getChangeHooksForObject(this.target).changeOwnKeys],() => { // There was no setter trap yet. This means that the key is new. Inform those listeners:
232
+
233
+ // if this "set" method got called, there is no setter trap installed yet
234
+ this.installSetterTrap(key);
235
+
236
+ //@ts-ignore
237
+ this.target[key] = value; // Set value again. this should call the setter trap
238
+ });
239
+
240
+ return true;
241
+ }
242
+
243
+ getPrototypeOf(target: object): object | null {
244
+ return this.origPrototype;
245
+ }
246
+
247
+ defineProperty(target: object, property: string | symbol, attributes: PropertyDescriptor): boolean {
248
+ throw new Error("Defineproperty not yet supported");
249
+ }
250
+
251
+ }
@@ -0,0 +1,14 @@
1
+ import { PartialGraph } from "./common";
2
+ export declare const changeTrackedOrigObjects: PartialGraph;
3
+ /**
4
+ *
5
+ * @param obj
6
+ */
7
+ export declare function installChangeTracker(obj: object): void;
8
+ /**
9
+ * Use this to delete properties on objects that have a write tracker installed. Otherwise they are not deletable and the write tracker cannot track the object's keys modification and inform listeners
10
+ * @param obj
11
+ * @param key
12
+ */
13
+ export declare function deleteProperty<O extends object>(obj: O, key: keyof O): boolean;
14
+ //# sourceMappingURL=origChangeTracking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origChangeTracking.d.ts","sourceRoot":"","sources":["origChangeTracking.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,YAAY,EAA6C,MAAM,UAAU,CAAC;AAUlF,eAAO,MAAM,wBAAwB,cAAqB,CAAC;AAI3D;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,QA2B/C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,WAepE"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ // This file has functions / classes that allow to watch writes to the original unproxied objects (or arrays/sets/maps)
3
+ // unproxied=not part of a proxy facade. Technically this can install Proxys as the prototype, to catch writes.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.changeTrackedOrigObjects = void 0;
6
+ exports.installChangeTracker = installChangeTracker;
7
+ exports.deleteProperty = deleteProperty;
8
+ const common_1 = require("./common");
9
+ const objectChangeTracking_1 = require("./objectChangeTracking");
10
+ const index_1 = require("./class-trackers/index");
11
+ const proxyFacade_1 = require("./proxyFacade");
12
+ const Util_1 = require("./Util");
13
+ exports.changeTrackedOrigObjects = new common_1.PartialGraph();
14
+ /**
15
+ *
16
+ * @param obj
17
+ */
18
+ function installChangeTracker(obj) {
19
+ !(0, proxyFacade_1.isProxyForAFacade)(obj) || (0, Util_1.throwError)("Cannot install change tracker on a proxy. The proxy should already support change tracking.");
20
+ if (exports.changeTrackedOrigObjects.hasObj(obj)) {
21
+ return;
22
+ }
23
+ function inner() {
24
+ const trackingConfig = (0, index_1.getTrackingConfigFor)(obj);
25
+ if (trackingConfig) {
26
+ if (trackingConfig.trackSettingObjectProperties) {
27
+ // Achieve this with the ObjectProxyhandler. It will consider getTrackingConfigFor(obj).changeTracker itsself:
28
+ const proxy = new objectChangeTracking_1.ObjectProxyHandler(obj, trackingConfig).proxy;
29
+ Object.setPrototypeOf(obj, proxy);
30
+ return;
31
+ }
32
+ if (trackingConfig.changeTracker !== undefined) {
33
+ Object.setPrototypeOf(obj, trackingConfig.changeTracker.prototype);
34
+ }
35
+ }
36
+ else { // Non-special object ?
37
+ const proxy = new objectChangeTracking_1.ObjectProxyHandler(obj, trackingConfig).proxy;
38
+ Object.setPrototypeOf(obj, proxy);
39
+ }
40
+ }
41
+ inner();
42
+ exports.changeTrackedOrigObjects._register(obj);
43
+ }
44
+ /**
45
+ * Use this to delete properties on objects that have a write tracker installed. Otherwise they are not deletable and the write tracker cannot track the object's keys modification and inform listeners
46
+ * @param obj
47
+ * @param key
48
+ */
49
+ function deleteProperty(obj, key) {
50
+ if (!exports.changeTrackedOrigObjects.hasObj(obj)) {
51
+ return delete obj[key];
52
+ }
53
+ const doesExist = Object.getOwnPropertyDescriptor(obj, key) !== undefined;
54
+ if (!doesExist) {
55
+ return true;
56
+ }
57
+ return (0, common_1.runChangeOperation)(obj, new common_1.UnspecificObjectChange(obj), [(0, objectChangeTracking_1.getChangeHooksForObject)(obj).changeOwnKeys], () => {
58
+ //@ts-ignore
59
+ obj[key] = undefined; // Set to undefined first, so property change listeners will get informed
60
+ return delete obj[key];
61
+ });
62
+ }
63
+ //# sourceMappingURL=origChangeTracking.js.map