unreflect 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -17,6 +17,7 @@ declare class ReflectionClass {
17
17
  private isPrivateName;
18
18
  private getBaseName;
19
19
  private stripPrivateInitializers;
20
+ private createShadowMethod;
20
21
  setProperty(name: string, value: any): void;
21
22
  getProperty(name: string): Promise<ReflectionProperty | undefined>;
22
23
  getPropertyValue(name: string): Promise<any>;
package/dist/index.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import vm from "node:vm";
2
1
  import inspector from "node:inspector/promises";
3
2
 
4
3
  //#region src/index.ts
@@ -101,6 +100,17 @@ var ReflectionClass = class {
101
100
  }
102
101
  return result.join("\n");
103
102
  }
103
+ createShadowMethod(originalMethod, baseName, shadowValues, privateName) {
104
+ const methodSource = originalMethod.toString();
105
+ if (methodSource.includes(`return this.#${baseName}`) || methodSource.includes(`return this.#${baseName};`)) return function(...args) {
106
+ if (shadowValues.has(privateName)) return shadowValues.get(privateName);
107
+ return originalMethod.apply(this, args);
108
+ };
109
+ return function(...args) {
110
+ if (shadowValues.has(privateName)) return shadowValues.get(privateName);
111
+ return originalMethod.apply(this, args);
112
+ };
113
+ }
104
114
  setProperty(name, value) {
105
115
  const obj = this.obj;
106
116
  const isPrivate = this.isPrivateName(name);
@@ -109,50 +119,53 @@ var ReflectionClass = class {
109
119
  obj[baseName] = value;
110
120
  return;
111
121
  }
122
+ this.values.set(name, value);
112
123
  const proto = Object.getPrototypeOf(obj);
113
- const classSource = proto.constructor.toString();
114
- if (!classSource.includes(`#${baseName}`)) return;
115
- const modifiedSource = this.stripPrivateInitializers(classSource).replace(/^(class(?:\s+\w+)?)\s*\{/, `$1 { static __reflectionSet__(obj, val) { obj.#${baseName} = val; } static __reflectionGet__(obj) { return obj.#${baseName}; }`);
116
- const ModifiedClass = vm.runInThisContext(`(${modifiedSource})`);
117
- Object.setPrototypeOf(obj, ModifiedClass.prototype);
118
- const originalProps = Object.getOwnPropertyDescriptors(obj);
119
- const freshInstance = new ModifiedClass();
120
- for (const key of Object.getOwnPropertyNames(originalProps)) Object.defineProperty(freshInstance, key, originalProps[key]);
121
- ModifiedClass.__reflectionSet__(freshInstance, value);
122
- this.values.set(name, {
123
- freshInstance,
124
- ModifiedClass
125
- });
126
- Object.setPrototypeOf(obj, proto);
127
124
  const protoDescriptors = Object.getOwnPropertyDescriptors(proto);
128
125
  for (const [propName, descriptor] of Object.entries(protoDescriptors)) {
129
126
  if (propName === "constructor") continue;
127
+ if (descriptor.get || descriptor.set) {
128
+ const getterSource = descriptor.get?.toString() || "";
129
+ const setterSource = descriptor.set?.toString() || "";
130
+ if (getterSource.includes(`#${baseName}`) || setterSource.includes(`#${baseName}`)) {
131
+ const shadowValues = this.values;
132
+ const privateName = name;
133
+ const originalGetter = descriptor.get;
134
+ const originalSetter = descriptor.set;
135
+ const newDescriptor = {
136
+ configurable: true,
137
+ enumerable: descriptor.enumerable
138
+ };
139
+ if (originalGetter) newDescriptor.get = function() {
140
+ if (shadowValues.has(privateName)) return shadowValues.get(privateName);
141
+ return originalGetter.call(this);
142
+ };
143
+ if (originalSetter) newDescriptor.set = function(val) {
144
+ shadowValues.set(privateName, val);
145
+ };
146
+ Object.defineProperty(obj, propName, newDescriptor);
147
+ }
148
+ }
130
149
  if (typeof descriptor.value === "function") {
131
- if (descriptor.value.toString().includes(`#${baseName}`)) {
132
- const boundMethod = ModifiedClass.prototype[propName].bind(freshInstance);
150
+ const methodSource = descriptor.value.toString();
151
+ if (methodSource.includes(`#${baseName}`)) {
152
+ const shadowValues = this.values;
153
+ const privateName = name;
154
+ const originalMethod = descriptor.value;
155
+ const isSimpleGetter = methodSource.includes(`return this.#${baseName}`) || methodSource.includes(`return this.#${baseName};`);
156
+ let wrappedMethod;
157
+ if (isSimpleGetter) wrappedMethod = function(...args) {
158
+ if (shadowValues.has(privateName)) return shadowValues.get(privateName);
159
+ return originalMethod.apply(this, args);
160
+ };
161
+ else wrappedMethod = this.createShadowMethod(originalMethod, baseName, shadowValues, privateName);
133
162
  Object.defineProperty(obj, propName, {
134
- value: boundMethod,
163
+ value: wrappedMethod,
135
164
  writable: true,
136
165
  configurable: true
137
166
  });
138
167
  }
139
168
  }
140
- if (descriptor.get || descriptor.set) {
141
- const getterSource = descriptor.get?.toString() || "";
142
- const setterSource = descriptor.set?.toString() || "";
143
- if (getterSource.includes(`#${baseName}`) || setterSource.includes(`#${baseName}`)) {
144
- const modifiedDescriptor = Object.getOwnPropertyDescriptor(ModifiedClass.prototype, propName);
145
- if (modifiedDescriptor) {
146
- const newDescriptor = {
147
- configurable: true,
148
- enumerable: descriptor.enumerable
149
- };
150
- if (modifiedDescriptor.get) newDescriptor.get = modifiedDescriptor.get.bind(freshInstance);
151
- if (modifiedDescriptor.set) newDescriptor.set = modifiedDescriptor.set.bind(freshInstance);
152
- Object.defineProperty(obj, propName, newDescriptor);
153
- }
154
- }
155
- }
156
169
  }
157
170
  }
158
171
  async getProperty(name) {
@@ -167,11 +180,10 @@ var ReflectionClass = class {
167
180
  };
168
181
  return;
169
182
  }
170
- const cached = this.values.get(name);
171
- if (cached) return {
183
+ if (this.values.has(name)) return {
172
184
  name,
173
185
  visibility: "private",
174
- value: cached.ModifiedClass.__reflectionGet__(cached.freshInstance)
186
+ value: this.values.get(name)
175
187
  };
176
188
  const id = `__ref_${Date.now()}_${Math.random().toString(36).slice(2)}__`;
177
189
  globalThis[id] = obj;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unreflect",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Access and modify private class fields and methods in JavaScript",
5
5
  "repository": "KABBOUCHI/unreflect",
6
6
  "license": "MIT",