@cldmv/slothlet 2.2.0 → 2.3.1

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.
@@ -35,8 +35,102 @@ export const runWithCtx = (ctx, fn, thisArg, args) => {
35
35
  export const getCtx = () => als.getStore() || null;
36
36
 
37
37
 
38
+ const EXCLUDED_CONSTRUCTORS = new Set([Object, Array, Promise, Date, RegExp, Error]);
39
+
40
+
41
+ const EXCLUDED_INSTANCEOF_CLASSES = [ArrayBuffer, Map, Set, WeakMap, WeakSet];
42
+
43
+
44
+ const PROMISE_METHODS = new Set(["then", "catch", "finally"]);
45
+
46
+
47
+ function runtime_shouldWrapMethod(value, prop) {
48
+ return (
49
+ typeof value === "function" &&
50
+ typeof prop === "string" &&
51
+ prop !== "constructor" &&
52
+ !(prop in Object.prototype) &&
53
+ !prop.startsWith("__")
54
+ );
55
+ }
56
+
57
+
58
+ function runtime_isClassInstance(val) {
59
+ if (
60
+ val == null ||
61
+ typeof val !== "object" ||
62
+ !val.constructor ||
63
+ typeof val.constructor !== "function" ||
64
+ EXCLUDED_CONSTRUCTORS.has(val.constructor)
65
+ ) {
66
+ return false;
67
+ }
68
+
69
+ for (const cls of EXCLUDED_INSTANCEOF_CLASSES) {
70
+ if (typeof cls === "function" && val instanceof cls) {
71
+ return false;
72
+ }
73
+ }
74
+
75
+ return true;
76
+ }
77
+
78
+
79
+ function runtime_wrapClassInstance(instance, ctx, wrapFn, instanceCache) {
80
+ if (instanceCache.has(instance)) {
81
+ return instanceCache.get(instance);
82
+ }
83
+
84
+
85
+ const methodCache = new Map();
86
+
87
+ const wrappedInstance = new Proxy(instance, {
88
+ get(target, prop, receiver) {
89
+
90
+ if (methodCache.has(prop)) {
91
+ return methodCache.get(prop);
92
+ }
93
+
94
+ const value = Reflect.get(target, prop, receiver);
95
+
96
+
97
+
98
+ if (runtime_shouldWrapMethod(value, prop)) {
99
+
100
+
101
+ const runtime_contextPreservingMethod = function (...args) {
102
+ const result = runWithCtx(ctx, value, target, args);
103
+
104
+ return wrapFn(result);
105
+ };
106
+
107
+
108
+ methodCache.set(prop, runtime_contextPreservingMethod);
109
+ return runtime_contextPreservingMethod;
110
+ }
111
+
112
+
113
+ return wrapFn(value);
114
+ },
115
+
116
+ set(target, prop, value, receiver) {
117
+
118
+ if (methodCache.has(prop)) {
119
+ methodCache.delete(prop);
120
+ }
121
+ return Reflect.set(target, prop, value, receiver);
122
+ }
123
+ });
124
+
125
+ instanceCache.set(instance, wrappedInstance);
126
+ return wrappedInstance;
127
+ }
128
+
129
+
38
130
  export const makeWrapper = (ctx) => {
39
131
  const cache = new WeakMap();
132
+ const instanceCache = new WeakMap();
133
+ const promiseMethodCache = new WeakMap();
40
134
  const wrap = (val) => {
41
135
  if (val == null || (typeof val !== "object" && typeof val !== "function")) return val;
42
136
  if (cache.has(val)) return cache.get(val);
@@ -53,18 +147,88 @@ export const makeWrapper = (ctx) => {
53
147
 
54
148
 
55
149
 
56
- return runWithCtx(ctx, target, thisArg, args);
150
+
151
+ const result = runWithCtx(ctx, target, thisArg, args);
152
+
153
+
154
+ if (runtime_isClassInstance(result)) {
155
+ return runtime_wrapClassInstance(result, ctx, wrap, instanceCache);
156
+ }
157
+
158
+ return result;
57
159
  },
58
160
  construct(target, args, newTarget) {
59
161
 
60
- return runWithCtx(ctx, Reflect.construct, undefined, [target, args, newTarget]);
162
+ const result = runWithCtx(ctx, Reflect.construct, undefined, [target, args, newTarget]);
163
+
164
+
165
+ if (runtime_isClassInstance(result)) {
166
+ return runtime_wrapClassInstance(result, ctx, wrap, instanceCache);
167
+ }
168
+
169
+ return result;
61
170
  },
62
171
  get(target, prop, receiver) {
63
- return wrap(Reflect.get(target, prop, receiver));
172
+ const value = Reflect.get(target, prop, receiver);
173
+
174
+
175
+
176
+ const isPromiseMethod = typeof value === "function" && PROMISE_METHODS.has(prop);
177
+ const isNativePromise = util.types.isPromise(target);
178
+ const hasThen = typeof target?.then === "function";
179
+
180
+ if (isPromiseMethod && (isNativePromise || hasThen)) {
181
+
182
+ let targetMethodCache = promiseMethodCache.get(target);
183
+ if (!targetMethodCache) {
184
+ targetMethodCache = new Map();
185
+ promiseMethodCache.set(target, targetMethodCache);
186
+ }
187
+
188
+ if (targetMethodCache.has(prop)) {
189
+ return targetMethodCache.get(prop);
190
+ }
191
+
192
+ const wrappedMethod = function (...args) {
193
+
194
+ const wrappedArgs = args.map((arg) => {
195
+ if (typeof arg === "function") {
196
+ return function (...callbackArgs) {
197
+ return runWithCtx(ctx, arg, undefined, callbackArgs);
198
+ };
199
+ }
200
+ return arg;
201
+ });
202
+
203
+
204
+ const result = Reflect.apply(value, target, wrappedArgs);
205
+
206
+ return wrap(result);
207
+ };
208
+
209
+ targetMethodCache.set(prop, wrappedMethod);
210
+ return wrappedMethod;
211
+ }
212
+
213
+ return wrap(value);
214
+ },
215
+ set(target, prop, value, receiver) {
216
+
217
+ const methodCache = promiseMethodCache.get(target);
218
+ if (methodCache && methodCache.has(prop)) {
219
+ methodCache.delete(prop);
220
+ }
221
+ return Reflect.set(target, prop, value, receiver);
64
222
  },
65
- set: Reflect.set,
66
223
  defineProperty: Reflect.defineProperty,
67
- deleteProperty: Reflect.deleteProperty,
224
+ deleteProperty(target, prop) {
225
+
226
+ const methodCache = promiseMethodCache.get(target);
227
+ if (methodCache && methodCache.has(prop)) {
228
+ methodCache.delete(prop);
229
+ }
230
+ return Reflect.deleteProperty(target, prop);
231
+ },
68
232
  ownKeys: Reflect.ownKeys,
69
233
  getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor,
70
234
  has: Reflect.has
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cldmv/slothlet",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
4
4
  "moduleVersions": {
5
5
  "lazy": "1.0.0",
6
6
  "eager": "1.0.0"
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.mts","sourceRoot":"","sources":["../../../../dist/lib/runtime/runtime.mjs"],"names":[],"mappings":"AA0CO,gCAdI,MAAM,yBAEN,GAAG,gBAED,GAAG,CA6Bf;AAiBM,0BAZM,MAAM,GAAC,IAAI,CAY0B;AAsB3C,iCAjBI,MAAM,YAwDhB;AA4RD;;;;;;;;;;;;;GAaG;AACH,mBATU,WAAS,MAAM,CAS6B;AAEtD;;;;;;;;;;;;;GAaG;AACH,sBATU,MAAM,CAS4C;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBATU,MAAM,CASgD"}
1
+ {"version":3,"file":"runtime.d.mts","sourceRoot":"","sources":["../../../../dist/lib/runtime/runtime.mjs"],"names":[],"mappings":"AA0CO,gCAdI,MAAM,yBAEN,GAAG,gBAED,GAAG,CA6Bf;AAiBM,0BAZM,MAAM,GAAC,IAAI,CAY0B;AAiL3C,iCAjBI,MAAM,YAgIhB;AA4RD;;;;;;;;;;;;;GAaG;AACH,mBATU,WAAS,MAAM,CAS6B;AAEtD;;;;;;;;;;;;;GAaG;AACH,sBATU,MAAM,CAS4C;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBATU,MAAM,CASgD"}