unreflect 0.0.3 → 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
@@ -21,7 +20,29 @@ var ReflectionClass = class {
21
20
  let braceDepth = 0;
22
21
  let bracketDepth = 0;
23
22
  let parenDepth = 0;
23
+ let inConstructor = false;
24
+ let constructorBraceDepth = 0;
24
25
  for (const line of lines) {
26
+ if (/^\s*constructor\s*\(/.test(line)) {
27
+ inConstructor = true;
28
+ constructorBraceDepth = 0;
29
+ for (const ch of line) {
30
+ if (ch === "{") constructorBraceDepth++;
31
+ if (ch === "}") constructorBraceDepth--;
32
+ }
33
+ result.push(line.replace(/\{.*$/, "{}"));
34
+ if (constructorBraceDepth > 0) continue;
35
+ inConstructor = false;
36
+ continue;
37
+ }
38
+ if (inConstructor) {
39
+ for (const ch of line) {
40
+ if (ch === "{") constructorBraceDepth++;
41
+ if (ch === "}") constructorBraceDepth--;
42
+ }
43
+ if (constructorBraceDepth === 0) inConstructor = false;
44
+ continue;
45
+ }
25
46
  const isMethod = /^\s*#\w+\s*\(/.test(line);
26
47
  const fieldMatch = line.match(/^(\s*)(#\w+)/);
27
48
  if (!isMethod && fieldMatch?.[1] !== void 0 && fieldMatch[2] && !skipUntilBalanced) {
@@ -79,6 +100,17 @@ var ReflectionClass = class {
79
100
  }
80
101
  return result.join("\n");
81
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
+ }
82
114
  setProperty(name, value) {
83
115
  const obj = this.obj;
84
116
  const isPrivate = this.isPrivateName(name);
@@ -87,29 +119,53 @@ var ReflectionClass = class {
87
119
  obj[baseName] = value;
88
120
  return;
89
121
  }
122
+ this.values.set(name, value);
90
123
  const proto = Object.getPrototypeOf(obj);
91
- const classSource = proto.constructor.toString();
92
- if (!classSource.includes(`#${baseName}`)) return;
93
- const modifiedSource = this.stripPrivateInitializers(classSource).replace(/^(class\s+\w+)\s*\{/, `$1 { static __reflectionSet__(obj, val) { obj.#${baseName} = val; } static __reflectionGet__(obj) { return obj.#${baseName}; }`);
94
- const ModifiedClass = vm.runInThisContext(`(${modifiedSource})`);
95
- Object.setPrototypeOf(obj, ModifiedClass.prototype);
96
- const originalProps = Object.getOwnPropertyDescriptors(obj);
97
- const freshInstance = new ModifiedClass();
98
- for (const key of Object.getOwnPropertyNames(originalProps)) Object.defineProperty(freshInstance, key, originalProps[key]);
99
- ModifiedClass.__reflectionSet__(freshInstance, value);
100
- this.values.set(name, {
101
- freshInstance,
102
- ModifiedClass
103
- });
104
- Object.setPrototypeOf(obj, proto);
105
- const methodNames = Object.getOwnPropertyNames(proto).filter((n) => n !== "constructor" && typeof proto[n] === "function");
106
- for (const methodName of methodNames) if (proto[methodName].toString().includes(`#${baseName}`)) {
107
- const boundMethod = ModifiedClass.prototype[methodName].bind(freshInstance);
108
- Object.defineProperty(obj, methodName, {
109
- value: boundMethod,
110
- writable: true,
111
- configurable: true
112
- });
124
+ const protoDescriptors = Object.getOwnPropertyDescriptors(proto);
125
+ for (const [propName, descriptor] of Object.entries(protoDescriptors)) {
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
+ }
149
+ if (typeof descriptor.value === "function") {
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);
162
+ Object.defineProperty(obj, propName, {
163
+ value: wrappedMethod,
164
+ writable: true,
165
+ configurable: true
166
+ });
167
+ }
168
+ }
113
169
  }
114
170
  }
115
171
  async getProperty(name) {
@@ -124,11 +180,10 @@ var ReflectionClass = class {
124
180
  };
125
181
  return;
126
182
  }
127
- const cached = this.values.get(name);
128
- if (cached) return {
183
+ if (this.values.has(name)) return {
129
184
  name,
130
185
  visibility: "private",
131
- value: cached.ModifiedClass.__reflectionGet__(cached.freshInstance)
186
+ value: this.values.get(name)
132
187
  };
133
188
  const id = `__ref_${Date.now()}_${Math.random().toString(36).slice(2)}__`;
134
189
  globalThis[id] = obj;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unreflect",
3
- "version": "0.0.3",
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",