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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origChangeTracking.js","sourceRoot":"","sources":["origChangeTracking.ts"],"names":[],"mappings":";AAAA,uHAAuH;AACvH,+GAA+G;;;AAqB/G,oDA2BC;AAOD,wCAeC;AAnED,qCAAkF;AAClF,iEAIgC;AAChC,kDAA4D;AAC5D,+CAAgD;AAChD,iCAAkC;AAErB,QAAA,wBAAwB,GAAG,IAAI,qBAAY,EAAE,CAAC;AAI3D;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,GAAW;IAC5C,CAAC,IAAA,+BAAiB,EAAC,GAAG,CAAC,IAAI,IAAA,iBAAU,EAAC,6FAA6F,CAAC,CAAC;IACrI,IAAG,gCAAwB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,OAAO;IACX,CAAC;IAED,SAAS,KAAK;QACV,MAAM,cAAc,GAAG,IAAA,4BAAoB,EAAC,GAAG,CAAC,CAAC;QACjD,IAAI,cAAc,EAAE,CAAC;YACjB,IAAI,cAAc,CAAC,4BAA4B,EAAE,CAAC;gBAC9C,8GAA8G;gBAC9G,MAAM,KAAK,GAAG,IAAI,yCAAkB,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,KAAK,CAAC;gBAChE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBAClC,OAAO;YACX,CAAC;YAED,IAAI,cAAc,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;gBAC7C,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,cAAc,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;YACvE,CAAC;QACL,CAAC;aAAM,CAAC,CAAC,uBAAuB;YAC5B,MAAM,KAAK,GAAG,IAAI,yCAAkB,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,KAAK,CAAC;YAChE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACtC,CAAC;IACL,CAAC;IACD,KAAK,EAAE,CAAC;IAER,gCAAwB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,SAAgB,cAAc,CAAmB,GAAM,EAAE,GAAY;IACjE,IAAG,CAAC,gCAAwB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,OAAO,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,SAAS,CAAC;IAC1E,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,IAAA,2BAAkB,EAAC,GAAG,EAAE,IAAI,+BAAsB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,8CAAuB,EAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE;QAC/G,YAAY;QACZ,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,yEAAyE;QAC/F,OAAO,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,72 @@
1
+ // This file has functions / classes that allow to watch writes to the original unproxied objects (or arrays/sets/maps)
2
+ // unproxied=not part of a proxy facade. Technically this can install Proxys as the prototype, to catch writes.
3
+
4
+
5
+ import {PartialGraph, runChangeOperation, UnspecificObjectChange} from "./common";
6
+ import {
7
+ ObjectProxyHandler,
8
+ changeHooksForObject,
9
+ getChangeHooksForObject
10
+ } from "./objectChangeTracking";
11
+ import {getTrackingConfigFor} from "./class-trackers/index";
12
+ import {isProxyForAFacade} from "./proxyFacade";
13
+ import {throwError} from "./Util";
14
+
15
+ export const changeTrackedOrigObjects = new PartialGraph();
16
+
17
+
18
+
19
+ /**
20
+ *
21
+ * @param obj
22
+ */
23
+ export function installChangeTracker(obj: object) {
24
+ !isProxyForAFacade(obj) || throwError("Cannot install change tracker on a proxy. The proxy should already support change tracking.");
25
+ if(changeTrackedOrigObjects.hasObj(obj)) {
26
+ return;
27
+ }
28
+
29
+ function inner() {
30
+ const trackingConfig = getTrackingConfigFor(obj);
31
+ if (trackingConfig) {
32
+ if (trackingConfig.trackSettingObjectProperties) {
33
+ // Achieve this with the ObjectProxyhandler. It will consider getTrackingConfigFor(obj).changeTracker itsself:
34
+ const proxy = new ObjectProxyHandler(obj, trackingConfig).proxy;
35
+ Object.setPrototypeOf(obj, proxy);
36
+ return;
37
+ }
38
+
39
+ if (trackingConfig.changeTracker !== undefined) {
40
+ Object.setPrototypeOf(obj, trackingConfig.changeTracker.prototype);
41
+ }
42
+ } else { // Non-special object ?
43
+ const proxy = new ObjectProxyHandler(obj, trackingConfig).proxy;
44
+ Object.setPrototypeOf(obj, proxy);
45
+ }
46
+ }
47
+ inner();
48
+
49
+ changeTrackedOrigObjects._register(obj);
50
+ }
51
+
52
+ /**
53
+ * 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
54
+ * @param obj
55
+ * @param key
56
+ */
57
+ export function deleteProperty<O extends object>(obj: O, key: keyof O) {
58
+ if(!changeTrackedOrigObjects.hasObj(obj)) {
59
+ return delete obj[key];
60
+ }
61
+
62
+ const doesExist = Object.getOwnPropertyDescriptor(obj, key) !== undefined;
63
+ if (!doesExist) {
64
+ return true;
65
+ }
66
+
67
+ return runChangeOperation(obj, new UnspecificObjectChange(obj), [getChangeHooksForObject(obj).changeOwnKeys], () => {
68
+ //@ts-ignore
69
+ obj[key] = undefined; // Set to undefined first, so property change listeners will get informed
70
+ return delete obj[key];
71
+ });
72
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "proxy-facades",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "keywords": [
6
+ "proxy",
7
+ "tracker",
8
+ "read-tracking",
9
+ "write-tracking"
10
+ ],
11
+ "author": "Boris Gingold <bogeee@bogitech.de>",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/bogeeee/proxy-facades.git"
15
+ },
16
+ "license": "MIT",
17
+ "main": "index.js",
18
+ "exports": {
19
+ ".": {
20
+ "import": "./index_esm.mjs",
21
+ "require": "./index.js"
22
+ },
23
+ "./develop": {
24
+ "browser": "./index.ts"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "dev:playground.ts": "tsx devPlayground.ts",
29
+ "dev:generateEsRuntimeBehaviourCheckerCode": "tsx dev_generateEsRuntimeBehaviourCheckerCode.ts",
30
+ "clean": "tsc --build --clean && rimraf dist",
31
+ "build": "tsc --build --force && tsc -module ES6 --outDir dist/mjs",
32
+ "test": "npm run clean && vitest --clearScreen --hideSkippedTests --poolOptions.threads.singleThread",
33
+ "test_specific": "npm run clean && vitest --clearScreen --hideSkippedTests --poolOptions.threads.singleThread --testNamePattern \"add.*should behave normally. With writes through installed write tracker\"",
34
+ "prepublish": "npm run clean && npm run build",
35
+ "publish:npmlogin": "npm login",
36
+ "publish:publish": "npm run prepublish && npm publish"
37
+
38
+ },
39
+ "dependencies": {
40
+ "underscore": "^1.13.3",
41
+ "@types/underscore": "^1.11.4",
42
+ "@types/node": "^20.12.7"
43
+ },
44
+ "devDependencies": {
45
+ "tsx": "^4.7.0",
46
+ "@vitest/ui": "^1.5.1",
47
+ "rimraf": "=5.0.5",
48
+ "ncp": "=2.0.0",
49
+ "typescript": "^5.4.5",
50
+ "vitest": "^1.5.0"
51
+ }
52
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ *
3
+ */
4
+ import { ObjKey, PartialGraph } from "./common";
5
+ export declare abstract class ProxyFacade<HANDLER extends FacadeProxyHandler<any>> extends PartialGraph {
6
+ /**
7
+ * Treats them like functions, meaning, they get a proxied 'this'. WatchProxies will see the access to the real properties
8
+ */
9
+ propertyAccessorsAsWhiteBox: boolean;
10
+ protected objectsToProxyHandlers: WeakMap<object, HANDLER>;
11
+ protected abstract crateHandler(target: object, facade: any): HANDLER;
12
+ getProxyFor<O>(value: O): O;
13
+ /**
14
+ *
15
+ * @param value
16
+ * @return the original non-proxied value
17
+ */
18
+ getUnproxiedValue<O>(value: O): O;
19
+ getHandlerFor(obj: object): HANDLER;
20
+ }
21
+ export declare abstract class FacadeProxyHandler<FACADE extends ProxyFacade<any>> implements ProxyHandler<object> {
22
+ target: object;
23
+ proxy: object;
24
+ facade: FACADE;
25
+ constructor(target: object, facade: FACADE);
26
+ deleteProperty(target: object, key: string | symbol): boolean;
27
+ defineProperty(target: object, property: string | symbol, attributes: PropertyDescriptor): boolean;
28
+ get(fake_target: object, p: string | symbol, receiver: any): any;
29
+ protected rawRead(key: ObjKey): unknown;
30
+ set(fake_target: object, p: string | symbol, value: any, receiver: any): boolean;
31
+ protected rawChange(p: string | symbol, newUnproxiedValue: any): void;
32
+ }
33
+ export declare function isProxyForAFacade(obj: object): boolean;
34
+ /**
35
+ * Makes the obj throw an error when trying to access it
36
+ * @param obj
37
+ * @param message
38
+ * @param cause
39
+ */
40
+ export declare function invalidateObject(obj: object, message: string, cause?: Error): void;
41
+ /**
42
+ * @returns the real real origial object from the real world
43
+ */
44
+ export declare function getGlobalOrig<T extends object>(obj: T): T;
45
+ //# sourceMappingURL=proxyFacade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyFacade.d.ts","sourceRoot":"","sources":["proxyFacade.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAIH,MAAM,EACN,YAAY,EAEf,MAAM,UAAU,CAAC;AAIlB,8BAAsB,WAAW,CAAC,OAAO,SAAS,kBAAkB,CAAC,GAAG,CAAC,CAAE,SAAQ,YAAY;IAE3F;;OAEG;IACI,2BAA2B,UAAQ;IAG1C,SAAS,CAAC,sBAAsB,2BAAkC;IAElE,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO;IAErE,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC;IAwB3B;;;;OAIG;IACH,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC;IAQjC,aAAa,CAAC,GAAG,EAAE,MAAM,GAC4B,OAAO;CAG/D;AAED,8BAAsB,kBAAkB,CAAC,MAAM,SAAS,WAAW,CAAC,GAAG,CAAC,CAAE,YAAW,YAAY,CAAC,MAAM,CAAC;IACrG,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAU1C,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO;IAK7D,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,OAAO;IAIlG,GAAG,CAAE,WAAW,EAAC,MAAM,EAAE,CAAC,EAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAC,GAAG;IA+BxD,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAKvC,GAAG,CAAC,WAAW,EAAC,MAAM,EAAE,CAAC,EAAC,MAAM,GAAG,MAAM,EAAE,KAAK,EAAC,GAAG,EAAE,QAAQ,EAAC,GAAG;IAoBlE,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,GAAG;CAOjE;AAQD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,WAE5C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,QAoC3E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAMzD"}
package/proxyFacade.js ADDED
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FacadeProxyHandler = exports.ProxyFacade = void 0;
4
+ exports.isProxyForAFacade = isProxyForAFacade;
5
+ exports.invalidateObject = invalidateObject;
6
+ exports.getGlobalOrig = getGlobalOrig;
7
+ /**
8
+ *
9
+ */
10
+ const common_1 = require("./common");
11
+ const origChangeTracking_1 = require("./origChangeTracking");
12
+ class ProxyFacade extends common_1.PartialGraph {
13
+ constructor() {
14
+ super(...arguments);
15
+ // *** Configuration: ***
16
+ /**
17
+ * Treats them like functions, meaning, they get a proxied 'this'. WatchProxies will see the access to the real properties
18
+ */
19
+ this.propertyAccessorsAsWhiteBox = true;
20
+ // *** State: ***
21
+ this.objectsToProxyHandlers = new WeakMap();
22
+ }
23
+ getProxyFor(value) {
24
+ if (value === null || typeof value !== "object") { // not an object?
25
+ return value;
26
+ }
27
+ if (this.hasObj(value)) { // Already our proxied object ?
28
+ return value;
29
+ }
30
+ let handlerForObj = this.objectsToProxyHandlers.get(value);
31
+ if (handlerForObj !== undefined) { // value was an unproxied object and we have the proxy for it ?
32
+ return handlerForObj.proxy;
33
+ }
34
+ handlerForObj = this.crateHandler(value, this);
35
+ // register:
36
+ proxyToProxyHandler.set(handlerForObj.proxy, handlerForObj);
37
+ this.objectsToProxyHandlers.set(value, handlerForObj);
38
+ this._register(handlerForObj.proxy);
39
+ return handlerForObj.proxy;
40
+ }
41
+ /**
42
+ *
43
+ * @param value
44
+ * @return the original non-proxied value
45
+ */
46
+ getUnproxiedValue(value) {
47
+ var _a;
48
+ if (value === null || typeof value !== "object") { // not an object?
49
+ return value;
50
+ }
51
+ return ((_a = proxyToProxyHandler.get(value)) === null || _a === void 0 ? void 0 : _a.target) || value;
52
+ }
53
+ getHandlerFor(obj) {
54
+ return getProxyHandler(this.getProxyFor(obj));
55
+ }
56
+ }
57
+ exports.ProxyFacade = ProxyFacade;
58
+ class FacadeProxyHandler {
59
+ constructor(target, facade) {
60
+ this.target = target;
61
+ this.facade = facade;
62
+ // Create proxy:
63
+ //const targetForProxy = {}; // The virtual way
64
+ 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
65
+ this.proxy = new Proxy(targetForProxy, this);
66
+ }
67
+ deleteProperty(target, key) {
68
+ //@ts-ignore
69
+ return (0, origChangeTracking_1.deleteProperty)(this.target, key);
70
+ }
71
+ defineProperty(target, property, attributes) {
72
+ throw new Error("Must not use defineProperty on a proxied object. Handling of change tracking etc. for this may not be implemented");
73
+ }
74
+ get(fake_target, p, receiver) {
75
+ var _a;
76
+ // Validity check
77
+ if (receiver !== this.proxy) {
78
+ throw new Error("Invalid state. Get was called on a different object than this proxy is for."); // Cannot imagine a legal case
79
+ }
80
+ const getter = (_a = (0, common_1.getPropertyDescriptor)(this.target, p)) === null || _a === void 0 ? void 0 : _a.get;
81
+ let value;
82
+ if (this.facade.propertyAccessorsAsWhiteBox && getter !== undefined && getter.origHadGetter !== false) { // Access via real property accessor ?
83
+ return value = getter.apply(this.proxy, []); // Call the accessor with a proxied this
84
+ }
85
+ else {
86
+ //@ts-ignore
87
+ value = this.rawRead(p);
88
+ }
89
+ if (value != null && typeof value === "object") {
90
+ const descriptor = Object.getOwnPropertyDescriptor(this.target, p);
91
+ // Handle read-only property:
92
+ if (descriptor !== undefined && descriptor.writable === false) {
93
+ // The js runtime would prevent us from returning a proxy :( Pretty mean :(
94
+ throw new Error("Cannot proxy a read-only property. This is not implemented."); // TODO: Implement the virtual way (see constructor)
95
+ }
96
+ return this.facade.getProxyFor(value);
97
+ }
98
+ return value;
99
+ }
100
+ rawRead(key) {
101
+ //@ts-ignore
102
+ return this.target[key];
103
+ }
104
+ set(fake_target, p, value, receiver) {
105
+ var _a;
106
+ // Validity check
107
+ if (receiver !== this.proxy) {
108
+ throw new Error("Invalid state. Set was called on a different object than this proxy is for."); // Cannot imagine a legal case
109
+ }
110
+ const setter = (_a = (0, common_1.getPropertyDescriptor)(this.target, p)) === null || _a === void 0 ? void 0 : _a.set;
111
+ if (this.facade.propertyAccessorsAsWhiteBox && setter !== undefined && setter.origHadSetter !== false) { // Setting via real property accessor ?
112
+ setter.apply(this.proxy, [value]); // Only call the accessor with a proxied this
113
+ }
114
+ else {
115
+ const unproxiedValue = this.facade.getUnproxiedValue(value);
116
+ //@ts-ignore
117
+ if (this.target[p] !== unproxiedValue) { // modify ?
118
+ this.rawChange(p, unproxiedValue);
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+ rawChange(p, newUnproxiedValue) {
124
+ //@ts-ignore
125
+ this.target[p] = newUnproxiedValue;
126
+ }
127
+ }
128
+ exports.FacadeProxyHandler = FacadeProxyHandler;
129
+ const proxyToProxyHandler = new WeakMap();
130
+ function getProxyHandler(proxy) {
131
+ return proxyToProxyHandler.get(proxy);
132
+ }
133
+ function isProxyForAFacade(obj) {
134
+ return proxyToProxyHandler.has(obj);
135
+ }
136
+ /**
137
+ * Makes the obj throw an error when trying to access it
138
+ * @param obj
139
+ * @param message
140
+ * @param cause
141
+ */
142
+ function invalidateObject(obj, message, cause) {
143
+ const throwInvalid = () => {
144
+ throw new Error(message, { cause: cause });
145
+ };
146
+ // Delete all writeable own props:
147
+ const descrs = Object.getOwnPropertyDescriptors(obj);
148
+ for (const k in descrs) {
149
+ const desc = descrs[k];
150
+ if (desc.configurable) {
151
+ //@ts-ignore
152
+ delete obj[k];
153
+ }
154
+ }
155
+ Object.setPrototypeOf(obj, new Proxy(obj, {
156
+ get(target, p, receiver) {
157
+ throwInvalid();
158
+ },
159
+ set(target, p, newValue, receiver) {
160
+ throwInvalid();
161
+ return false;
162
+ },
163
+ defineProperty(target, property, attributes) {
164
+ throwInvalid();
165
+ return false;
166
+ },
167
+ deleteProperty(target, p) {
168
+ throwInvalid();
169
+ return false;
170
+ },
171
+ ownKeys(target) {
172
+ throwInvalid();
173
+ return [];
174
+ }
175
+ }));
176
+ }
177
+ /**
178
+ * @returns the real real origial object from the real world
179
+ */
180
+ function getGlobalOrig(obj) {
181
+ let handler;
182
+ while ((handler = proxyToProxyHandler.get(obj)) !== undefined) {
183
+ obj = handler.target;
184
+ }
185
+ return obj;
186
+ }
187
+ //# sourceMappingURL=proxyFacade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyFacade.js","sourceRoot":"","sources":["proxyFacade.ts"],"names":[],"mappings":"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"}
package/proxyFacade.ts ADDED
@@ -0,0 +1,222 @@
1
+ /**
2
+ *
3
+ */
4
+ import {
5
+ getPropertyDescriptor,
6
+ GetterFlags,
7
+ objectMembershipInGraphs,
8
+ ObjKey,
9
+ PartialGraph,
10
+ SetterFlags
11
+ } from "./common";
12
+ import {deleteProperty} from "./origChangeTracking";
13
+
14
+
15
+ export abstract class ProxyFacade<HANDLER extends FacadeProxyHandler<any>> extends PartialGraph {
16
+ // *** Configuration: ***
17
+ /**
18
+ * Treats them like functions, meaning, they get a proxied 'this'. WatchProxies will see the access to the real properties
19
+ */
20
+ public propertyAccessorsAsWhiteBox = true;
21
+
22
+ // *** State: ***
23
+ protected objectsToProxyHandlers = new WeakMap<object, HANDLER>();
24
+
25
+ protected abstract crateHandler(target: object, facade: any): HANDLER;
26
+
27
+ getProxyFor<O>(value: O): O {
28
+ if(value === null || typeof value !== "object") { // not an object?
29
+ return value;
30
+ }
31
+
32
+ if(this.hasObj(value)) { // Already our proxied object ?
33
+ return value;
34
+ }
35
+
36
+ let handlerForObj = this.objectsToProxyHandlers.get(value);
37
+ if(handlerForObj !== undefined) { // value was an unproxied object and we have the proxy for it ?
38
+ return handlerForObj.proxy as O;
39
+ }
40
+
41
+ handlerForObj = this.crateHandler(value, this);
42
+ // register:
43
+ proxyToProxyHandler.set(handlerForObj.proxy, handlerForObj);
44
+ this.objectsToProxyHandlers.set(value, handlerForObj);
45
+ this._register(handlerForObj.proxy);
46
+
47
+
48
+ return handlerForObj.proxy as O;
49
+ }
50
+
51
+ /**
52
+ *
53
+ * @param value
54
+ * @return the original non-proxied value
55
+ */
56
+ getUnproxiedValue<O>(value: O): O {
57
+ if(value === null || typeof value !== "object") { // not an object?
58
+ return value;
59
+ }
60
+
61
+ return proxyToProxyHandler.get(value)?.target as O|| value;
62
+ }
63
+
64
+ getHandlerFor(obj: object) {
65
+ return getProxyHandler(this.getProxyFor(obj)) as HANDLER;
66
+ }
67
+
68
+ }
69
+
70
+ export abstract class FacadeProxyHandler<FACADE extends ProxyFacade<any>> implements ProxyHandler<object> {
71
+ target: object;
72
+ proxy: object;
73
+ facade: FACADE;
74
+
75
+ constructor(target: object, facade: FACADE) {
76
+ this.target = target;
77
+ this.facade = facade;
78
+
79
+ // Create proxy:
80
+ //const targetForProxy = {}; // The virtual way
81
+ 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
82
+ this.proxy = new Proxy(targetForProxy, this);
83
+ }
84
+
85
+ deleteProperty(target: object, key: string | symbol): boolean {
86
+ //@ts-ignore
87
+ return deleteProperty(this.target,key);
88
+ }
89
+
90
+ defineProperty(target: object, property: string | symbol, attributes: PropertyDescriptor): boolean {
91
+ throw new Error("Must not use defineProperty on a proxied object. Handling of change tracking etc. for this may not be implemented");
92
+ }
93
+
94
+ get (fake_target:object, p:string | symbol, receiver:any) {
95
+ // Validity check
96
+ if(receiver !== this.proxy) {
97
+ throw new Error("Invalid state. Get was called on a different object than this proxy is for."); // Cannot imagine a legal case
98
+ }
99
+
100
+ const getter = getPropertyDescriptor(this.target, p)?.get;
101
+ let value;
102
+ if(this.facade.propertyAccessorsAsWhiteBox && getter !== undefined && (getter as GetterFlags).origHadGetter !== false) { // Access via real property accessor ?
103
+ return value = getter.apply(this.proxy,[]); // Call the accessor with a proxied this
104
+ }
105
+ else {
106
+ //@ts-ignore
107
+ value = this.rawRead(p);
108
+ }
109
+
110
+ if(value != null && typeof value === "object") {
111
+ const descriptor = Object.getOwnPropertyDescriptor(this.target, p);
112
+
113
+ // Handle read-only property:
114
+ if(descriptor !== undefined && descriptor.writable === false) {
115
+ // The js runtime would prevent us from returning a proxy :( Pretty mean :(
116
+ throw new Error("Cannot proxy a read-only property. This is not implemented."); // TODO: Implement the virtual way (see constructor)
117
+ }
118
+
119
+ return this.facade.getProxyFor(value);
120
+ }
121
+
122
+ return value;
123
+ }
124
+
125
+ protected rawRead(key: ObjKey): unknown {
126
+ //@ts-ignore
127
+ return this.target[key as any];
128
+ }
129
+
130
+ set(fake_target:object, p:string | symbol, value:any, receiver:any) {
131
+ // Validity check
132
+ if(receiver !== this.proxy) {
133
+ throw new Error("Invalid state. Set was called on a different object than this proxy is for."); // Cannot imagine a legal case
134
+ }
135
+
136
+ const setter = getPropertyDescriptor(this.target, p)?.set;
137
+ if(this.facade.propertyAccessorsAsWhiteBox && setter !== undefined && (setter as SetterFlags).origHadSetter !== false) { // Setting via real property accessor ?
138
+ setter.apply(this.proxy,[value]); // Only call the accessor with a proxied this
139
+ }
140
+ else {
141
+ const unproxiedValue = this.facade.getUnproxiedValue(value);
142
+ //@ts-ignore
143
+ if (this.target[p] !== unproxiedValue) { // modify ?
144
+ this.rawChange(p, unproxiedValue);
145
+ }
146
+ }
147
+ return true
148
+ }
149
+
150
+ protected rawChange(p: string | symbol, newUnproxiedValue: any) {
151
+ //@ts-ignore
152
+ this.target[p] = newUnproxiedValue
153
+ }
154
+
155
+
156
+
157
+ }
158
+
159
+
160
+ const proxyToProxyHandler = new WeakMap<object, FacadeProxyHandler<any>>();
161
+ function getProxyHandler(proxy: object) {
162
+ return proxyToProxyHandler.get(proxy);
163
+ }
164
+
165
+ export function isProxyForAFacade(obj: object) {
166
+ return proxyToProxyHandler.has(obj);
167
+ }
168
+
169
+ /**
170
+ * Makes the obj throw an error when trying to access it
171
+ * @param obj
172
+ * @param message
173
+ * @param cause
174
+ */
175
+ export function invalidateObject(obj: object, message: string, cause?: Error) {
176
+ const throwInvalid = () => {
177
+ throw new Error(message, {cause: cause});
178
+ }
179
+
180
+ // Delete all writeable own props:
181
+ const descrs = Object.getOwnPropertyDescriptors(obj);
182
+ for(const k in descrs) {
183
+ const desc = descrs[k];
184
+ if(desc.configurable) {
185
+ //@ts-ignore
186
+ delete obj[k];
187
+ }
188
+ }
189
+
190
+ Object.setPrototypeOf(obj, new Proxy(obj, {
191
+ get(target: object, p: string | symbol, receiver: any): any {
192
+ throwInvalid();
193
+ },
194
+ set(target: object, p: string | symbol, newValue: any, receiver: any): boolean {
195
+ throwInvalid()
196
+ return false;
197
+ },
198
+ defineProperty(target: object, property: string | symbol, attributes: PropertyDescriptor): boolean {
199
+ throwInvalid();
200
+ return false;
201
+ },
202
+ deleteProperty(target: object, p: string | symbol): boolean {
203
+ throwInvalid()
204
+ return false;
205
+ },
206
+ ownKeys(target: object): ArrayLike<string | symbol> {
207
+ throwInvalid()
208
+ return [];
209
+ }
210
+ }))
211
+ }
212
+
213
+ /**
214
+ * @returns the real real origial object from the real world
215
+ */
216
+ export function getGlobalOrig<T extends object>(obj: T): T {
217
+ let handler: FacadeProxyHandler<any> | undefined
218
+ while((handler = proxyToProxyHandler.get(obj)) !== undefined) {
219
+ obj = handler.target as T;
220
+ }
221
+ return obj;
222
+ }