jslike 1.7.3 → 1.8.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.
@@ -1,13 +1,240 @@
1
1
  import { Environment, ReturnValue, BreakSignal, ContinueSignal, ThrowSignal } from '../runtime/environment.js';
2
- import { parse as acornParse } from '../parser.js';
2
+ import { parse as acornParse, tsParse, tsxParse } from '../parser.js';
3
3
  import { createMethodNotFoundError } from '../errors/enhanced-error.js';
4
4
 
5
+ function isTypeScriptPath(sourcePath) {
6
+ return typeof sourcePath === 'string' && /\.(ts|tsx|mts|cts)$/i.test(sourcePath);
7
+ }
8
+
9
+ function isTSXPath(sourcePath) {
10
+ return typeof sourcePath === 'string' && /\.tsx$/i.test(sourcePath);
11
+ }
12
+
13
+ function parseModuleCode(code, sourcePath) {
14
+ const parser = isTSXPath(sourcePath) ? tsxParse : isTypeScriptPath(sourcePath) ? tsParse : acornParse;
15
+ return parser(code, {
16
+ ecmaVersion: isTypeScriptPath(sourcePath) ? 'latest' : 2020,
17
+ sourceType: 'module',
18
+ locations: isTypeScriptPath(sourcePath)
19
+ });
20
+ }
21
+
22
+ const TYPE_ONLY_DECLARATIONS = new Set([
23
+ 'TSTypeAliasDeclaration',
24
+ 'TSInterfaceDeclaration',
25
+ 'TSDeclareFunction'
26
+ ]);
27
+
28
+ const TYPE_WRAPPER_EXPRESSIONS = new Set([
29
+ 'TSAsExpression',
30
+ 'TSTypeAssertion',
31
+ 'TSNonNullExpression',
32
+ 'TSSatisfiesExpression',
33
+ 'TSInstantiationExpression'
34
+ ]);
35
+
36
+ function isTypeOnlyDeclaration(node) {
37
+ return TYPE_ONLY_DECLARATIONS.has(node?.type) || node?.declare === true;
38
+ }
39
+
40
+ function isTypeWrapperExpression(node) {
41
+ return TYPE_WRAPPER_EXPRESSIONS.has(node?.type);
42
+ }
43
+
44
+ function getTypeWrapperInnerExpression(node) {
45
+ return node.expression;
46
+ }
47
+
48
+ function createUnsupportedTypeScriptRuntimeError(node) {
49
+ return new Error(`Unsupported runtime TypeScript syntax: ${node.type}`);
50
+ }
51
+
52
+ function getPatternName(pattern) {
53
+ if (!pattern) return undefined;
54
+ if (pattern.type === 'Identifier') return pattern.name;
55
+ if (pattern.type === 'AssignmentPattern') return getPatternName(pattern.left);
56
+ if (pattern.type === 'TSParameterProperty') return getPatternName(pattern.parameter);
57
+ return pattern.name;
58
+ }
59
+
60
+ function collectRuntimeIdentifierReferences(node) {
61
+ const references = new Set();
62
+ const skipKeys = new Set([
63
+ 'type',
64
+ 'start',
65
+ 'end',
66
+ 'loc',
67
+ 'range',
68
+ 'raw',
69
+ 'typeAnnotation',
70
+ 'returnType',
71
+ 'typeParameters',
72
+ 'typeArguments',
73
+ 'implements'
74
+ ]);
75
+
76
+ const visitPatternDefaults = (pattern) => {
77
+ if (!pattern || typeof pattern !== 'object') return;
78
+ if (pattern.type === 'AssignmentPattern') {
79
+ visit(pattern.right);
80
+ visitPatternDefaults(pattern.left);
81
+ } else if (pattern.type === 'ObjectPattern') {
82
+ for (const property of pattern.properties || []) {
83
+ visitPatternDefaults(property.value || property.argument);
84
+ }
85
+ } else if (pattern.type === 'ArrayPattern') {
86
+ for (const element of pattern.elements || []) {
87
+ visitPatternDefaults(element);
88
+ }
89
+ } else if (pattern.type === 'RestElement') {
90
+ visitPatternDefaults(pattern.argument);
91
+ } else if (pattern.type === 'TSParameterProperty') {
92
+ visitPatternDefaults(pattern.parameter);
93
+ }
94
+ };
95
+
96
+ const visitFunction = (fn) => {
97
+ for (const param of fn.params || []) {
98
+ visitPatternDefaults(param);
99
+ }
100
+ visit(fn.body);
101
+ };
102
+
103
+ const visitJSXName = (jsxName) => {
104
+ if (!jsxName || typeof jsxName !== 'object') return;
105
+ if (jsxName.type === 'JSXIdentifier') {
106
+ if (/^[A-Z]/.test(jsxName.name)) {
107
+ references.add(jsxName.name);
108
+ }
109
+ } else if (jsxName.type === 'JSXMemberExpression') {
110
+ visitJSXName(jsxName.object);
111
+ } else if (jsxName.type === 'JSXNamespacedName') {
112
+ visitJSXName(jsxName.namespace);
113
+ }
114
+ };
115
+
116
+ const visit = (current, parent = null, parentKey = null) => {
117
+ if (!current || typeof current !== 'object') return;
118
+
119
+ if (Array.isArray(current)) {
120
+ for (const item of current) visit(item, parent, parentKey);
121
+ return;
122
+ }
123
+
124
+ if (current.type?.startsWith('TS')) {
125
+ if (isTypeWrapperExpression(current)) {
126
+ visit(getTypeWrapperInnerExpression(current), current, 'expression');
127
+ } else if (current.type === 'TSEnumDeclaration') {
128
+ for (const member of current.members || []) {
129
+ visit(member.initializer);
130
+ }
131
+ }
132
+ return;
133
+ }
134
+
135
+ switch (current.type) {
136
+ case 'Identifier':
137
+ references.add(current.name);
138
+ return;
139
+ case 'ImportDeclaration':
140
+ return;
141
+ case 'ExportNamedDeclaration':
142
+ if (current.declaration) {
143
+ visit(current.declaration, current, 'declaration');
144
+ } else if (current.exportKind !== 'type') {
145
+ for (const specifier of current.specifiers || []) {
146
+ if (specifier.exportKind !== 'type' && specifier.local?.name) {
147
+ references.add(specifier.local.name);
148
+ }
149
+ }
150
+ }
151
+ return;
152
+ case 'ExportDefaultDeclaration':
153
+ visit(current.declaration, current, 'declaration');
154
+ return;
155
+ case 'VariableDeclarator':
156
+ visitPatternDefaults(current.id);
157
+ visit(current.init, current, 'init');
158
+ return;
159
+ case 'FunctionDeclaration':
160
+ visitFunction(current);
161
+ return;
162
+ case 'FunctionExpression':
163
+ case 'ArrowFunctionExpression':
164
+ visitFunction(current);
165
+ return;
166
+ case 'ClassDeclaration':
167
+ case 'ClassExpression':
168
+ visit(current.superClass, current, 'superClass');
169
+ visit(current.body, current, 'body');
170
+ return;
171
+ case 'MemberExpression':
172
+ case 'OptionalMemberExpression':
173
+ visit(current.object, current, 'object');
174
+ if (current.computed) {
175
+ visit(current.property, current, 'property');
176
+ }
177
+ return;
178
+ case 'Property':
179
+ if (current.computed) {
180
+ visit(current.key, current, 'key');
181
+ }
182
+ visit(current.value, current, 'value');
183
+ return;
184
+ case 'MethodDefinition':
185
+ case 'PropertyDefinition':
186
+ if (current.computed) {
187
+ visit(current.key, current, 'key');
188
+ }
189
+ if (!current.declare && !current.abstract) {
190
+ visit(current.value, current, 'value');
191
+ }
192
+ return;
193
+ case 'AssignmentPattern':
194
+ visit(current.right, current, 'right');
195
+ return;
196
+ case 'RestElement':
197
+ return;
198
+ case 'ObjectPattern':
199
+ case 'ArrayPattern':
200
+ visitPatternDefaults(current);
201
+ return;
202
+ case 'JSXElement':
203
+ visitJSXName(current.openingElement?.name);
204
+ for (const child of current.children || []) {
205
+ visit(child);
206
+ }
207
+ return;
208
+ case 'JSXFragment':
209
+ for (const child of current.children || []) {
210
+ visit(child);
211
+ }
212
+ return;
213
+ case 'JSXExpressionContainer':
214
+ visit(current.expression, current, 'expression');
215
+ return;
216
+ }
217
+
218
+ for (const [key, value] of Object.entries(current)) {
219
+ if (skipKeys.has(key)) continue;
220
+ visit(value, current, key);
221
+ }
222
+ };
223
+
224
+ visit(node);
225
+ return references;
226
+ }
227
+
5
228
  export class Interpreter {
6
229
  constructor(globalEnv, options = {}) {
7
230
  this.globalEnv = globalEnv;
8
231
  this.moduleResolver = options.moduleResolver;
9
232
  this.moduleCache = new Map(); // Cache loaded modules
233
+ this.moduleResolutionCache = options.moduleResolutionCache || new Map();
10
234
  this.moduleExports = {}; // Track exports in current module
235
+ this.currentModulePath = options.currentModulePath;
236
+ this.isTypeScriptModule = options.isTypeScriptModule || false;
237
+ this.runtimeIdentifierReferences = null;
11
238
  this.abortSignal = options.abortSignal;
12
239
  this.executionController = options.executionController;
13
240
  }
@@ -163,6 +390,27 @@ export class Interpreter {
163
390
  const checkpointPromise = this._getCheckpointPromise(node, env);
164
391
  if (checkpointPromise) await checkpointPromise;
165
392
 
393
+ if (isTypeOnlyDeclaration(node)) {
394
+ return undefined;
395
+ }
396
+
397
+ if (node.type === 'TSExportAssignment' || node.type === 'TSImportEqualsDeclaration') {
398
+ throw createUnsupportedTypeScriptRuntimeError(node);
399
+ }
400
+
401
+ if (node.type === 'TSEnumDeclaration') {
402
+ return this.evaluateTSEnumDeclaration(node, env);
403
+ }
404
+
405
+ if (node.type === 'TSModuleDeclaration') {
406
+ if (node.declare) return undefined;
407
+ throw createUnsupportedTypeScriptRuntimeError(node);
408
+ }
409
+
410
+ if (isTypeWrapperExpression(node)) {
411
+ return await this.evaluateAsync(getTypeWrapperInnerExpression(node), env);
412
+ }
413
+
166
414
  // Handle await expressions by actually awaiting the promise
167
415
  if (node.type === 'AwaitExpression') {
168
416
  const promise = await this.evaluateAsync(node.argument, env);
@@ -209,15 +457,21 @@ export class Interpreter {
209
457
 
210
458
  // For Program nodes (evaluate all statements async)
211
459
  if (node.type === 'Program') {
460
+ const previousReferences = this.runtimeIdentifierReferences;
461
+ this.runtimeIdentifierReferences = collectRuntimeIdentifierReferences(node);
212
462
  let result = undefined;
213
- for (const statement of node.body) {
214
- result = await this.evaluateAsync(statement, env);
215
- // Handle top-level return and throw
216
- if (result instanceof ReturnValue || result instanceof ThrowSignal) {
217
- return result;
463
+ try {
464
+ for (const statement of node.body) {
465
+ result = await this.evaluateAsync(statement, env);
466
+ // Handle top-level return and throw
467
+ if (result instanceof ReturnValue || result instanceof ThrowSignal) {
468
+ return result;
469
+ }
218
470
  }
471
+ return result;
472
+ } finally {
473
+ this.runtimeIdentifierReferences = previousReferences;
219
474
  }
220
- return result;
221
475
  }
222
476
 
223
477
  // For import declarations (always async)
@@ -814,6 +1068,27 @@ export class Interpreter {
814
1068
  // Check for abort signal before evaluating
815
1069
  this.checkAbortSignal();
816
1070
 
1071
+ if (isTypeOnlyDeclaration(node)) {
1072
+ return undefined;
1073
+ }
1074
+
1075
+ if (node.type === 'TSExportAssignment' || node.type === 'TSImportEqualsDeclaration') {
1076
+ throw createUnsupportedTypeScriptRuntimeError(node);
1077
+ }
1078
+
1079
+ if (node.type === 'TSEnumDeclaration') {
1080
+ return this.evaluateTSEnumDeclaration(node, env);
1081
+ }
1082
+
1083
+ if (node.type === 'TSModuleDeclaration') {
1084
+ if (node.declare) return undefined;
1085
+ throw createUnsupportedTypeScriptRuntimeError(node);
1086
+ }
1087
+
1088
+ if (isTypeWrapperExpression(node)) {
1089
+ return this.evaluate(getTypeWrapperInnerExpression(node), env);
1090
+ }
1091
+
817
1092
  switch (node.type) {
818
1093
  case 'Program':
819
1094
  return this.evaluateProgram(node, env);
@@ -974,6 +1249,9 @@ export class Interpreter {
974
1249
  case 'Property':
975
1250
  return this.evaluateProperty(node, env);
976
1251
 
1252
+ case 'TSEnumDeclaration':
1253
+ return this.evaluateTSEnumDeclaration(node, env);
1254
+
977
1255
  // JSX Support
978
1256
  case 'JSXElement':
979
1257
  return this.evaluateJSXElement(node, env);
@@ -996,27 +1274,33 @@ export class Interpreter {
996
1274
  }
997
1275
 
998
1276
  evaluateProgram(node, env) {
1277
+ const previousReferences = this.runtimeIdentifierReferences;
1278
+ this.runtimeIdentifierReferences = collectRuntimeIdentifierReferences(node);
999
1279
  let result = undefined;
1000
- for (let i = 0; i < node.body.length; i++) {
1001
- const statement = node.body[i];
1002
- const isLast = i === node.body.length - 1;
1003
-
1004
- // Special case: Last statement is a BlockStatement that looks like object literal
1005
- // Handle both shorthand { x, y } and full syntax { key: value, key2: value2 }
1006
- if (isLast && statement.type === 'BlockStatement') {
1007
- const objLiteral = this.tryConvertBlockToObjectLiteral(statement, env);
1008
- if (objLiteral !== null) {
1009
- return objLiteral;
1280
+ try {
1281
+ for (let i = 0; i < node.body.length; i++) {
1282
+ const statement = node.body[i];
1283
+ const isLast = i === node.body.length - 1;
1284
+
1285
+ // Special case: Last statement is a BlockStatement that looks like object literal
1286
+ // Handle both shorthand { x, y } and full syntax { key: value, key2: value2 }
1287
+ if (isLast && statement.type === 'BlockStatement') {
1288
+ const objLiteral = this.tryConvertBlockToObjectLiteral(statement, env);
1289
+ if (objLiteral !== null) {
1290
+ return objLiteral;
1291
+ }
1010
1292
  }
1011
- }
1012
1293
 
1013
- const statementResult = this.evaluate(statement, env);
1014
- if (statementResult instanceof ReturnValue || statementResult instanceof ThrowSignal) {
1015
- return statementResult;
1294
+ const statementResult = this.evaluate(statement, env);
1295
+ if (statementResult instanceof ReturnValue || statementResult instanceof ThrowSignal) {
1296
+ return statementResult;
1297
+ }
1298
+ result = statementResult;
1016
1299
  }
1017
- result = statementResult;
1300
+ return result;
1301
+ } finally {
1302
+ this.runtimeIdentifierReferences = previousReferences;
1018
1303
  }
1019
- return result;
1020
1304
  }
1021
1305
 
1022
1306
  // Try to convert a BlockStatement to an object literal
@@ -1396,7 +1680,9 @@ export class Interpreter {
1396
1680
 
1397
1681
  // Bind parameters
1398
1682
  for (let i = 0; i < metadata.params.length; i++) {
1399
- const param = metadata.params[i];
1683
+ const param = metadata.params[i].type === 'TSParameterProperty'
1684
+ ? metadata.params[i].parameter
1685
+ : metadata.params[i];
1400
1686
 
1401
1687
  if (param.type === 'Identifier') {
1402
1688
  // Simple parameter: function(x)
@@ -1719,6 +2005,34 @@ export class Interpreter {
1719
2005
  return undefined;
1720
2006
  }
1721
2007
 
2008
+ evaluateTSEnumDeclaration(node, env) {
2009
+ const enumObject = {};
2010
+ let nextNumericValue = 0;
2011
+
2012
+ for (const member of node.members) {
2013
+ const memberName = member.id.name ?? member.id.value;
2014
+ let value;
2015
+
2016
+ if (member.initializer) {
2017
+ value = this.evaluate(member.initializer, env);
2018
+ } else {
2019
+ value = nextNumericValue;
2020
+ }
2021
+
2022
+ enumObject[memberName] = value;
2023
+
2024
+ if (typeof value === 'number') {
2025
+ enumObject[value] = memberName;
2026
+ nextNumericValue = value + 1;
2027
+ } else {
2028
+ nextNumericValue = undefined;
2029
+ }
2030
+ }
2031
+
2032
+ env.define(node.id.name, enumObject, false);
2033
+ return undefined;
2034
+ }
2035
+
1722
2036
  bindObjectPattern(pattern, value, env, isConst = false) {
1723
2037
  if (value === null || value === undefined) {
1724
2038
  throw new TypeError('Cannot destructure undefined or null');
@@ -1823,42 +2137,72 @@ export class Interpreter {
1823
2137
  // Get module path from import source
1824
2138
  const modulePath = node.source.value;
1825
2139
 
2140
+ if (node.importKind === 'type' ||
2141
+ (node.specifiers.length > 0 && node.specifiers.every(specifier => specifier.importKind === 'type'))) {
2142
+ return undefined;
2143
+ }
2144
+
2145
+ if (this.isTypeScriptModule &&
2146
+ node.specifiers.length > 0 &&
2147
+ node.specifiers.every(specifier => !this.isRuntimeImportSpecifier(specifier))) {
2148
+ return undefined;
2149
+ }
2150
+
1826
2151
  // Check if module resolver is configured
1827
2152
  if (!this.moduleResolver) {
1828
2153
  throw new Error('Module resolver not configured - cannot import modules');
1829
2154
  }
1830
2155
 
2156
+ const fromPath = this.currentModulePath;
2157
+
2158
+ const resolutionCacheKey = `${fromPath || ''}\0${modulePath}`;
2159
+ let resolution;
2160
+ let resolvedPath = this.moduleResolutionCache.get(resolutionCacheKey);
2161
+ if (!resolvedPath && !modulePath.startsWith('.') && this.moduleCache.has(modulePath)) {
2162
+ resolvedPath = modulePath;
2163
+ }
2164
+
1831
2165
  // Check if module is already cached
1832
2166
  let moduleExports;
1833
- if (this.moduleCache.has(modulePath)) {
1834
- moduleExports = this.moduleCache.get(modulePath);
2167
+ if (resolvedPath && this.moduleCache.has(resolvedPath)) {
2168
+ moduleExports = this.moduleCache.get(resolvedPath);
1835
2169
  } else {
1836
- // Resolve and load module code
1837
- const resolution = await this.moduleResolver.resolve(modulePath);
2170
+ // Resolve first so relative imports can use importer context and cache by resolved path.
2171
+ resolution = await this.moduleResolver.resolve(modulePath, fromPath);
1838
2172
  if (!resolution) {
1839
2173
  throw new Error(`Cannot find module '${modulePath}'`);
1840
2174
  }
1841
2175
 
2176
+ resolvedPath = typeof resolution === 'string'
2177
+ ? modulePath
2178
+ : resolution.path || modulePath;
2179
+ this.moduleResolutionCache.set(resolutionCacheKey, resolvedPath);
2180
+ if (this.moduleCache.has(resolvedPath)) {
2181
+ moduleExports = this.moduleCache.get(resolvedPath);
2182
+ return this.bindImportSpecifiers(node, env, modulePath, moduleExports);
2183
+ }
2184
+
1842
2185
  // Handle native module exports (for libraries like React)
1843
2186
  // If resolution has 'exports' property, use it directly without parsing
1844
2187
  if (resolution.exports) {
1845
2188
  moduleExports = resolution.exports;
1846
- this.moduleCache.set(modulePath, moduleExports);
2189
+ this.moduleCache.set(resolvedPath, moduleExports);
1847
2190
  } else {
1848
2191
  // Handle both old (string) and new (ModuleResolution) formats
1849
2192
  const moduleCode = typeof resolution === 'string' ? resolution : resolution.code;
1850
2193
 
1851
2194
  // Parse and execute module in its own environment
1852
- const moduleAst = acornParse(moduleCode, {
1853
- ecmaVersion: 2020,
1854
- sourceType: 'module',
1855
- locations: false
1856
- });
2195
+ const moduleAst = parseModuleCode(moduleCode, resolvedPath);
1857
2196
  const moduleEnv = new Environment(this.globalEnv);
1858
2197
 
1859
2198
  // Create a new interpreter for the module with shared module cache
1860
2199
  const moduleInterpreter = new Interpreter(this.globalEnv, {
1861
- moduleResolver: this.moduleResolver
2200
+ moduleResolver: this.moduleResolver,
2201
+ moduleResolutionCache: this.moduleResolutionCache,
2202
+ currentModulePath: resolvedPath,
2203
+ isTypeScriptModule: isTypeScriptPath(resolvedPath),
2204
+ abortSignal: this.abortSignal,
2205
+ executionController: this.executionController
1862
2206
  });
1863
2207
  moduleInterpreter.moduleCache = this.moduleCache; // Share cache
1864
2208
 
@@ -1867,12 +2211,21 @@ export class Interpreter {
1867
2211
 
1868
2212
  // Cache the module exports
1869
2213
  moduleExports = moduleInterpreter.moduleExports;
1870
- this.moduleCache.set(modulePath, moduleExports);
2214
+ this.moduleCache.set(resolvedPath, moduleExports);
1871
2215
  }
1872
2216
  }
1873
2217
 
2218
+ this.bindImportSpecifiers(node, env, modulePath, moduleExports);
2219
+ return undefined;
2220
+ }
2221
+
2222
+ bindImportSpecifiers(node, env, modulePath, moduleExports) {
1874
2223
  // Import specified bindings into current environment
1875
2224
  for (const specifier of node.specifiers) {
2225
+ if (!this.isRuntimeImportSpecifier(specifier)) {
2226
+ continue;
2227
+ }
2228
+
1876
2229
  if (specifier.type === 'ImportSpecifier') {
1877
2230
  // Named import: import { foo, bar } from "module"
1878
2231
  const importedName = specifier.imported.name;
@@ -1902,7 +2255,28 @@ export class Interpreter {
1902
2255
  return undefined;
1903
2256
  }
1904
2257
 
2258
+ isRuntimeImportSpecifier(specifier) {
2259
+ if (specifier.importKind === 'type') {
2260
+ return false;
2261
+ }
2262
+
2263
+ if (!this.isTypeScriptModule) {
2264
+ return true;
2265
+ }
2266
+
2267
+ const localName = specifier.local?.name;
2268
+ if (!localName || !this.runtimeIdentifierReferences) {
2269
+ return true;
2270
+ }
2271
+
2272
+ return this.runtimeIdentifierReferences.has(localName);
2273
+ }
2274
+
1905
2275
  evaluateExportNamedDeclaration(node, env) {
2276
+ if (node.exportKind === 'type' || isTypeOnlyDeclaration(node.declaration)) {
2277
+ return undefined;
2278
+ }
2279
+
1906
2280
  // Handle export with declaration: export function foo() {} or export const x = 42
1907
2281
  if (node.declaration) {
1908
2282
  const result = this.evaluate(node.declaration, env);
@@ -1922,6 +2296,9 @@ export class Interpreter {
1922
2296
  // export class Foo {}
1923
2297
  const name = node.declaration.id.name;
1924
2298
  this.moduleExports[name] = env.get(name);
2299
+ } else if (node.declaration.type === 'TSEnumDeclaration') {
2300
+ const name = node.declaration.id.name;
2301
+ this.moduleExports[name] = env.get(name);
1925
2302
  }
1926
2303
 
1927
2304
  return result;
@@ -1930,6 +2307,10 @@ export class Interpreter {
1930
2307
  // Handle export list: export { foo, bar }
1931
2308
  if (node.specifiers && node.specifiers.length > 0) {
1932
2309
  for (const specifier of node.specifiers) {
2310
+ if (specifier.exportKind === 'type') {
2311
+ continue;
2312
+ }
2313
+
1933
2314
  const exportedName = specifier.exported.name;
1934
2315
  const localName = specifier.local.name;
1935
2316
  this.moduleExports[exportedName] = env.get(localName);
@@ -2406,7 +2787,10 @@ export class Interpreter {
2406
2787
 
2407
2788
  // Bind parameters
2408
2789
  for (let i = 0; i < methodFunc.__params.length; i++) {
2409
- const param = methodFunc.__params[i];
2790
+ const originalParam = methodFunc.__params[i];
2791
+ const param = originalParam.type === 'TSParameterProperty'
2792
+ ? originalParam.parameter
2793
+ : originalParam;
2410
2794
 
2411
2795
  if (param.type === 'Identifier') {
2412
2796
  // Simple parameter: function(x)
@@ -2429,6 +2813,13 @@ export class Interpreter {
2429
2813
  // Fallback for simple parameter names
2430
2814
  funcEnv.define(param.name, args[i]);
2431
2815
  }
2816
+
2817
+ if (originalParam.type === 'TSParameterProperty') {
2818
+ const propertyName = getPatternName(originalParam.parameter);
2819
+ if (propertyName) {
2820
+ thisContext[propertyName] = funcEnv.get(propertyName);
2821
+ }
2822
+ }
2432
2823
  }
2433
2824
 
2434
2825
  const result = this.evaluate(methodFunc.__body, funcEnv);