jslike 1.7.2 → 1.8.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.
package/README.md CHANGED
@@ -473,7 +473,10 @@ Execute JavaScript code and return the result.
473
473
  const result = await execute(code, env, {
474
474
  moduleResolver, // For import statements
475
475
  executionController, // For pause/resume/abort
476
- abortSignal // For cancellation
476
+ abortSignal, // For cancellation
477
+ sourcePath, // Optional importer path for resolving top-level imports
478
+ typescript, // Parse TypeScript syntax
479
+ tsx // Parse TypeScript + JSX syntax
477
480
  });
478
481
  ```
479
482
 
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Use bundled Acorn parser for zero runtime dependencies
2
- import { parse as acornParse } from './parser.js';
2
+ import { parse as acornParse, tsParse, tsxParse } from './parser.js';
3
3
  import { Interpreter } from './interpreter/interpreter.js';
4
4
  import { Environment, ReturnValue } from './runtime/environment.js';
5
5
  import { createGlobalEnvironment } from './runtime/builtins.js';
@@ -9,7 +9,7 @@ function containsModuleSyntax(code) {
9
9
  // Trigger module mode for:
10
10
  // 1. import/export statements
11
11
  // 2. Top-level await (await not inside a function)
12
- if (/^\s*(import|export)\s+/m.test(code)) {
12
+ if (/(^|[;{\n])\s*(import|export)\s+/m.test(code)) {
13
13
  return true;
14
14
  }
15
15
 
@@ -23,6 +23,13 @@ function containsModuleSyntax(code) {
23
23
  return false;
24
24
  }
25
25
 
26
+ function isTypeScriptPath(sourcePath) {
27
+ return typeof sourcePath === 'string' && /\.(ts|tsx|mts|cts)$/i.test(sourcePath);
28
+ }
29
+
30
+ function isTSXPath(sourcePath) {
31
+ return typeof sourcePath === 'string' && /\.tsx$/i.test(sourcePath);
32
+ }
26
33
 
27
34
  export function parse(code, options = {}) {
28
35
  // Determine sourceType: use 'module' ONLY if explicitly requested or if code has imports/exports
@@ -32,10 +39,13 @@ export function parse(code, options = {}) {
32
39
  sourceType = 'module';
33
40
  }
34
41
 
42
+ const shouldParseTypeScript = options.typescript || options.tsx || isTypeScriptPath(options.sourcePath);
43
+ const parser = options.tsx || isTSXPath(options.sourcePath) ? tsxParse : shouldParseTypeScript ? tsParse : acornParse;
44
+
35
45
  // Parse with Acorn
36
46
  try {
37
- return acornParse(code, {
38
- ecmaVersion: 2022, // Support ES2022 features (including top-level await)
47
+ return parser(code, {
48
+ ecmaVersion: shouldParseTypeScript ? 'latest' : 2022, // Support ES2022 features (including top-level await)
39
49
  sourceType: sourceType,
40
50
  locations: true, // Track source locations for better error messages
41
51
  allowReturnOutsideFunction: true, // Allow top-level return statements
@@ -119,7 +129,8 @@ export async function execute(code, env = null, options = {}) {
119
129
  const interpreter = new Interpreter(env, {
120
130
  moduleResolver: options.moduleResolver,
121
131
  abortSignal: options.abortSignal,
122
- executionController: controller
132
+ executionController: controller,
133
+ currentModulePath: options.sourcePath
123
134
  });
124
135
 
125
136
  // Use async evaluation if:
@@ -103,7 +103,8 @@ export class WangInterpreter {
103
103
  const options = {
104
104
  moduleResolver: this.moduleResolver,
105
105
  executionController: userOptions.executionController,
106
- abortSignal: userOptions.abortSignal // Pass abort signal to interpreter for cancellation support
106
+ abortSignal: userOptions.abortSignal, // Pass abort signal to interpreter for cancellation support
107
+ sourcePath: userOptions.sourcePath ?? this.options.sourcePath
107
108
  // sourceType will be auto-detected from code
108
109
  };
109
110
 
@@ -1,13 +1,70 @@
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
+
5
60
  export class Interpreter {
6
61
  constructor(globalEnv, options = {}) {
7
62
  this.globalEnv = globalEnv;
8
63
  this.moduleResolver = options.moduleResolver;
9
64
  this.moduleCache = new Map(); // Cache loaded modules
65
+ this.moduleResolutionCache = options.moduleResolutionCache || new Map();
10
66
  this.moduleExports = {}; // Track exports in current module
67
+ this.currentModulePath = options.currentModulePath;
11
68
  this.abortSignal = options.abortSignal;
12
69
  this.executionController = options.executionController;
13
70
  }
@@ -39,6 +96,121 @@ export class Interpreter {
39
96
  }
40
97
  }
41
98
 
99
+ async evaluateAsyncRawValue(node, env) {
100
+ if (!node) return { value: undefined };
101
+
102
+ if (node.type === 'CallExpression') {
103
+ return await this.evaluateCallExpressionAsyncRawValue(node, env);
104
+ }
105
+
106
+ if (node.type === 'MemberExpression') {
107
+ const obj = (await this.evaluateAsyncRawValue(node.object, env)).value;
108
+
109
+ if (node.optional && (obj === null || obj === undefined)) {
110
+ return { value: undefined };
111
+ }
112
+
113
+ if (obj === null || obj === undefined) {
114
+ throw new TypeError(`Cannot read property of ${obj}`);
115
+ }
116
+
117
+ const prop = node.computed
118
+ ? await this.evaluateAsync(node.property, env)
119
+ : node.property.name;
120
+
121
+ return { value: obj[prop] };
122
+ }
123
+
124
+ if (node.type === 'ChainExpression') {
125
+ return await this.evaluateAsyncRawValue(node.expression, env);
126
+ }
127
+
128
+ if (node.type === 'ConditionalExpression') {
129
+ const test = await this.evaluateAsync(node.test, env);
130
+ return await this.evaluateAsyncRawValue(test ? node.consequent : node.alternate, env);
131
+ }
132
+
133
+ if (node.type === 'LogicalExpression') {
134
+ const left = await this.evaluateAsync(node.left, env);
135
+ if (node.operator === '&&') {
136
+ return left ? await this.evaluateAsyncRawValue(node.right, env) : { value: left };
137
+ }
138
+ if (node.operator === '||') {
139
+ return left ? { value: left } : await this.evaluateAsyncRawValue(node.right, env);
140
+ }
141
+ if (node.operator === '??') {
142
+ return left !== null && left !== undefined
143
+ ? { value: left }
144
+ : await this.evaluateAsyncRawValue(node.right, env);
145
+ }
146
+ }
147
+
148
+ if (node.type === 'SequenceExpression') {
149
+ for (let i = 0; i < node.expressions.length - 1; i++) {
150
+ await this.evaluateAsync(node.expressions[i], env);
151
+ }
152
+ return await this.evaluateAsyncRawValue(node.expressions[node.expressions.length - 1], env);
153
+ }
154
+
155
+ if (node.type === 'NewExpression') {
156
+ return { value: this.evaluateNewExpression(node, env) };
157
+ }
158
+
159
+ if (['Literal', 'Identifier', 'ThisExpression', 'Super'].includes(node.type)) {
160
+ return { value: this.evaluate(node, env) };
161
+ }
162
+
163
+ return { value: await this.evaluateAsync(node, env) };
164
+ }
165
+
166
+ async evaluateCallExpressionAsyncRawValue(node, env) {
167
+ let thisContext = undefined;
168
+ let callee;
169
+ let objectName = null;
170
+ let methodName = null;
171
+
172
+ if (node.callee.type === 'MemberExpression') {
173
+ thisContext = (await this.evaluateAsyncRawValue(node.callee.object, env)).value;
174
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
175
+ return { value: undefined };
176
+ }
177
+ const prop = node.callee.computed
178
+ ? await this.evaluateAsync(node.callee.property, env)
179
+ : node.callee.property.name;
180
+ callee = thisContext[prop];
181
+
182
+ methodName = prop;
183
+ objectName = this.getExpressionName(node.callee.object);
184
+ } else {
185
+ callee = await this.evaluateAsync(node.callee, env);
186
+ }
187
+
188
+ if (node.optional && (callee === null || callee === undefined)) {
189
+ return { value: undefined };
190
+ }
191
+
192
+ const rawArgs = [];
193
+ for (const arg of node.arguments) {
194
+ rawArgs.push(await this.evaluateAsync(arg, env));
195
+ }
196
+ const args = this.flattenSpreadArgs(rawArgs);
197
+
198
+ if (typeof callee === 'function') {
199
+ const value = thisContext !== undefined
200
+ ? callee.call(thisContext, ...args)
201
+ : callee(...args);
202
+ return { value };
203
+ } else if (callee && callee.__isFunction) {
204
+ return { value: this.callUserFunction(callee, args, env, thisContext) };
205
+ }
206
+
207
+ if (objectName && methodName) {
208
+ throw createMethodNotFoundError(objectName, methodName, thisContext);
209
+ }
210
+
211
+ throw new TypeError(`${node.callee.name || 'Expression'} is not a function`);
212
+ }
213
+
42
214
  // Async evaluation for async functions - handles await expressions
43
215
  async evaluateAsync(node, env) {
44
216
  if (!node) return undefined;
@@ -48,6 +220,27 @@ export class Interpreter {
48
220
  const checkpointPromise = this._getCheckpointPromise(node, env);
49
221
  if (checkpointPromise) await checkpointPromise;
50
222
 
223
+ if (isTypeOnlyDeclaration(node)) {
224
+ return undefined;
225
+ }
226
+
227
+ if (node.type === 'TSExportAssignment' || node.type === 'TSImportEqualsDeclaration') {
228
+ throw createUnsupportedTypeScriptRuntimeError(node);
229
+ }
230
+
231
+ if (node.type === 'TSEnumDeclaration') {
232
+ return this.evaluateTSEnumDeclaration(node, env);
233
+ }
234
+
235
+ if (node.type === 'TSModuleDeclaration') {
236
+ if (node.declare) return undefined;
237
+ throw createUnsupportedTypeScriptRuntimeError(node);
238
+ }
239
+
240
+ if (isTypeWrapperExpression(node)) {
241
+ return await this.evaluateAsync(getTypeWrapperInnerExpression(node), env);
242
+ }
243
+
51
244
  // Handle await expressions by actually awaiting the promise
52
245
  if (node.type === 'AwaitExpression') {
53
246
  const promise = await this.evaluateAsync(node.argument, env);
@@ -77,7 +270,7 @@ export class Interpreter {
77
270
  if (node.type === 'VariableDeclaration') {
78
271
  for (const declarator of node.declarations) {
79
272
  const value = declarator.init
80
- ? await this.evaluateAsync(declarator.init, env)
273
+ ? (await this.evaluateAsyncRawValue(declarator.init, env)).value
81
274
  : undefined;
82
275
 
83
276
  const isConst = node.kind === 'const';
@@ -134,54 +327,8 @@ export class Interpreter {
134
327
 
135
328
  // For call expressions (might be calling async functions)
136
329
  if (node.type === 'CallExpression') {
137
- let thisContext = undefined;
138
- let callee;
139
- let objectName = null;
140
- let methodName = null;
141
-
142
- if (node.callee.type === 'MemberExpression') {
143
- thisContext = await this.evaluateAsync(node.callee.object, env);
144
- if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
145
- return undefined;
146
- }
147
- const prop = node.callee.computed
148
- ? await this.evaluateAsync(node.callee.property, env)
149
- : node.callee.property.name;
150
- callee = thisContext[prop];
151
-
152
- // Capture names for enhanced error messages
153
- methodName = prop;
154
- objectName = this.getExpressionName(node.callee.object);
155
- } else {
156
- callee = await this.evaluateAsync(node.callee, env);
157
- }
158
-
159
- // Handle optional call - if optional and callee is null/undefined, return undefined
160
- if (node.optional && (callee === null || callee === undefined)) {
161
- return undefined;
162
- }
163
-
164
- const rawArgs = [];
165
- for (const arg of node.arguments) {
166
- rawArgs.push(await this.evaluateAsync(arg, env));
167
- }
168
- const args = this.flattenSpreadArgs(rawArgs);
169
-
170
- if (typeof callee === 'function') {
171
- if (thisContext !== undefined) {
172
- return await callee.call(thisContext, ...args);
173
- }
174
- return await callee(...args);
175
- } else if (callee && callee.__isFunction) {
176
- return await this.callUserFunction(callee, args, env, thisContext);
177
- }
178
-
179
- // Throw enhanced error for member expression calls
180
- if (objectName && methodName) {
181
- throw createMethodNotFoundError(objectName, methodName, thisContext);
182
- }
183
-
184
- throw new TypeError(`${node.callee.name || 'Expression'} is not a function`);
330
+ const result = (await this.evaluateCallExpressionAsyncRawValue(node, env)).value;
331
+ return await result;
185
332
  }
186
333
 
187
334
  // For chain expressions (optional chaining)
@@ -191,7 +338,7 @@ export class Interpreter {
191
338
 
192
339
  // For member expressions in async context
193
340
  if (node.type === 'MemberExpression') {
194
- const obj = await this.evaluateAsync(node.object, env);
341
+ const obj = (await this.evaluateAsyncRawValue(node.object, env)).value;
195
342
 
196
343
  // Handle optional chaining
197
344
  if (node.optional && (obj === null || obj === undefined)) {
@@ -513,7 +660,7 @@ export class Interpreter {
513
660
 
514
661
  // For AssignmentExpression with async value
515
662
  if (node.type === 'AssignmentExpression') {
516
- const value = await this.evaluateAsync(node.right, env);
663
+ const value = (await this.evaluateAsyncRawValue(node.right, env)).value;
517
664
 
518
665
  if (node.left.type === 'Identifier') {
519
666
  const name = node.left.name;
@@ -745,6 +892,27 @@ export class Interpreter {
745
892
  // Check for abort signal before evaluating
746
893
  this.checkAbortSignal();
747
894
 
895
+ if (isTypeOnlyDeclaration(node)) {
896
+ return undefined;
897
+ }
898
+
899
+ if (node.type === 'TSExportAssignment' || node.type === 'TSImportEqualsDeclaration') {
900
+ throw createUnsupportedTypeScriptRuntimeError(node);
901
+ }
902
+
903
+ if (node.type === 'TSEnumDeclaration') {
904
+ return this.evaluateTSEnumDeclaration(node, env);
905
+ }
906
+
907
+ if (node.type === 'TSModuleDeclaration') {
908
+ if (node.declare) return undefined;
909
+ throw createUnsupportedTypeScriptRuntimeError(node);
910
+ }
911
+
912
+ if (isTypeWrapperExpression(node)) {
913
+ return this.evaluate(getTypeWrapperInnerExpression(node), env);
914
+ }
915
+
748
916
  switch (node.type) {
749
917
  case 'Program':
750
918
  return this.evaluateProgram(node, env);
@@ -905,6 +1073,9 @@ export class Interpreter {
905
1073
  case 'Property':
906
1074
  return this.evaluateProperty(node, env);
907
1075
 
1076
+ case 'TSEnumDeclaration':
1077
+ return this.evaluateTSEnumDeclaration(node, env);
1078
+
908
1079
  // JSX Support
909
1080
  case 'JSXElement':
910
1081
  return this.evaluateJSXElement(node, env);
@@ -1327,7 +1498,9 @@ export class Interpreter {
1327
1498
 
1328
1499
  // Bind parameters
1329
1500
  for (let i = 0; i < metadata.params.length; i++) {
1330
- const param = metadata.params[i];
1501
+ const param = metadata.params[i].type === 'TSParameterProperty'
1502
+ ? metadata.params[i].parameter
1503
+ : metadata.params[i];
1331
1504
 
1332
1505
  if (param.type === 'Identifier') {
1333
1506
  // Simple parameter: function(x)
@@ -1650,6 +1823,34 @@ export class Interpreter {
1650
1823
  return undefined;
1651
1824
  }
1652
1825
 
1826
+ evaluateTSEnumDeclaration(node, env) {
1827
+ const enumObject = {};
1828
+ let nextNumericValue = 0;
1829
+
1830
+ for (const member of node.members) {
1831
+ const memberName = member.id.name ?? member.id.value;
1832
+ let value;
1833
+
1834
+ if (member.initializer) {
1835
+ value = this.evaluate(member.initializer, env);
1836
+ } else {
1837
+ value = nextNumericValue;
1838
+ }
1839
+
1840
+ enumObject[memberName] = value;
1841
+
1842
+ if (typeof value === 'number') {
1843
+ enumObject[value] = memberName;
1844
+ nextNumericValue = value + 1;
1845
+ } else {
1846
+ nextNumericValue = undefined;
1847
+ }
1848
+ }
1849
+
1850
+ env.define(node.id.name, enumObject, false);
1851
+ return undefined;
1852
+ }
1853
+
1653
1854
  bindObjectPattern(pattern, value, env, isConst = false) {
1654
1855
  if (value === null || value === undefined) {
1655
1856
  throw new TypeError('Cannot destructure undefined or null');
@@ -1754,42 +1955,65 @@ export class Interpreter {
1754
1955
  // Get module path from import source
1755
1956
  const modulePath = node.source.value;
1756
1957
 
1958
+ if (node.importKind === 'type' ||
1959
+ (node.specifiers.length > 0 && node.specifiers.every(specifier => specifier.importKind === 'type'))) {
1960
+ return undefined;
1961
+ }
1962
+
1757
1963
  // Check if module resolver is configured
1758
1964
  if (!this.moduleResolver) {
1759
1965
  throw new Error('Module resolver not configured - cannot import modules');
1760
1966
  }
1761
1967
 
1968
+ const fromPath = this.currentModulePath;
1969
+
1970
+ const resolutionCacheKey = `${fromPath || ''}\0${modulePath}`;
1971
+ let resolution;
1972
+ let resolvedPath = this.moduleResolutionCache.get(resolutionCacheKey);
1973
+ if (!resolvedPath && !modulePath.startsWith('.') && this.moduleCache.has(modulePath)) {
1974
+ resolvedPath = modulePath;
1975
+ }
1976
+
1762
1977
  // Check if module is already cached
1763
1978
  let moduleExports;
1764
- if (this.moduleCache.has(modulePath)) {
1765
- moduleExports = this.moduleCache.get(modulePath);
1979
+ if (resolvedPath && this.moduleCache.has(resolvedPath)) {
1980
+ moduleExports = this.moduleCache.get(resolvedPath);
1766
1981
  } else {
1767
- // Resolve and load module code
1768
- const resolution = await this.moduleResolver.resolve(modulePath);
1982
+ // Resolve first so relative imports can use importer context and cache by resolved path.
1983
+ resolution = await this.moduleResolver.resolve(modulePath, fromPath);
1769
1984
  if (!resolution) {
1770
1985
  throw new Error(`Cannot find module '${modulePath}'`);
1771
1986
  }
1772
1987
 
1988
+ resolvedPath = typeof resolution === 'string'
1989
+ ? modulePath
1990
+ : resolution.path || modulePath;
1991
+ this.moduleResolutionCache.set(resolutionCacheKey, resolvedPath);
1992
+ if (this.moduleCache.has(resolvedPath)) {
1993
+ moduleExports = this.moduleCache.get(resolvedPath);
1994
+ return this.bindImportSpecifiers(node, env, modulePath, moduleExports);
1995
+ }
1996
+
1773
1997
  // Handle native module exports (for libraries like React)
1774
1998
  // If resolution has 'exports' property, use it directly without parsing
1775
1999
  if (resolution.exports) {
1776
2000
  moduleExports = resolution.exports;
1777
- this.moduleCache.set(modulePath, moduleExports);
2001
+ this.moduleCache.set(resolvedPath, moduleExports);
1778
2002
  } else {
1779
2003
  // Handle both old (string) and new (ModuleResolution) formats
1780
2004
  const moduleCode = typeof resolution === 'string' ? resolution : resolution.code;
1781
2005
 
1782
2006
  // Parse and execute module in its own environment
1783
- const moduleAst = acornParse(moduleCode, {
1784
- ecmaVersion: 2020,
1785
- sourceType: 'module',
1786
- locations: false
1787
- });
2007
+ const moduleAst = parseModuleCode(moduleCode, resolvedPath);
1788
2008
  const moduleEnv = new Environment(this.globalEnv);
1789
2009
 
1790
2010
  // Create a new interpreter for the module with shared module cache
1791
2011
  const moduleInterpreter = new Interpreter(this.globalEnv, {
1792
- moduleResolver: this.moduleResolver
2012
+ moduleResolver: this.moduleResolver,
2013
+ moduleResolutionCache: this.moduleResolutionCache,
2014
+ currentModulePath: resolvedPath,
2015
+ abortSignal: this.abortSignal,
2016
+ executionController: this.executionController
1793
2017
  });
1794
2018
  moduleInterpreter.moduleCache = this.moduleCache; // Share cache
1795
2019
 
@@ -1798,12 +2022,21 @@ export class Interpreter {
1798
2022
 
1799
2023
  // Cache the module exports
1800
2024
  moduleExports = moduleInterpreter.moduleExports;
1801
- this.moduleCache.set(modulePath, moduleExports);
2025
+ this.moduleCache.set(resolvedPath, moduleExports);
1802
2026
  }
1803
2027
  }
1804
2028
 
2029
+ this.bindImportSpecifiers(node, env, modulePath, moduleExports);
2030
+ return undefined;
2031
+ }
2032
+
2033
+ bindImportSpecifiers(node, env, modulePath, moduleExports) {
1805
2034
  // Import specified bindings into current environment
1806
2035
  for (const specifier of node.specifiers) {
2036
+ if (specifier.importKind === 'type') {
2037
+ continue;
2038
+ }
2039
+
1807
2040
  if (specifier.type === 'ImportSpecifier') {
1808
2041
  // Named import: import { foo, bar } from "module"
1809
2042
  const importedName = specifier.imported.name;
@@ -1834,6 +2067,10 @@ export class Interpreter {
1834
2067
  }
1835
2068
 
1836
2069
  evaluateExportNamedDeclaration(node, env) {
2070
+ if (node.exportKind === 'type' || isTypeOnlyDeclaration(node.declaration)) {
2071
+ return undefined;
2072
+ }
2073
+
1837
2074
  // Handle export with declaration: export function foo() {} or export const x = 42
1838
2075
  if (node.declaration) {
1839
2076
  const result = this.evaluate(node.declaration, env);
@@ -1853,6 +2090,9 @@ export class Interpreter {
1853
2090
  // export class Foo {}
1854
2091
  const name = node.declaration.id.name;
1855
2092
  this.moduleExports[name] = env.get(name);
2093
+ } else if (node.declaration.type === 'TSEnumDeclaration') {
2094
+ const name = node.declaration.id.name;
2095
+ this.moduleExports[name] = env.get(name);
1856
2096
  }
1857
2097
 
1858
2098
  return result;
@@ -1861,6 +2101,10 @@ export class Interpreter {
1861
2101
  // Handle export list: export { foo, bar }
1862
2102
  if (node.specifiers && node.specifiers.length > 0) {
1863
2103
  for (const specifier of node.specifiers) {
2104
+ if (specifier.exportKind === 'type') {
2105
+ continue;
2106
+ }
2107
+
1864
2108
  const exportedName = specifier.exported.name;
1865
2109
  const localName = specifier.local.name;
1866
2110
  this.moduleExports[exportedName] = env.get(localName);
@@ -2337,7 +2581,10 @@ export class Interpreter {
2337
2581
 
2338
2582
  // Bind parameters
2339
2583
  for (let i = 0; i < methodFunc.__params.length; i++) {
2340
- const param = methodFunc.__params[i];
2584
+ const originalParam = methodFunc.__params[i];
2585
+ const param = originalParam.type === 'TSParameterProperty'
2586
+ ? originalParam.parameter
2587
+ : originalParam;
2341
2588
 
2342
2589
  if (param.type === 'Identifier') {
2343
2590
  // Simple parameter: function(x)
@@ -2360,6 +2607,13 @@ export class Interpreter {
2360
2607
  // Fallback for simple parameter names
2361
2608
  funcEnv.define(param.name, args[i]);
2362
2609
  }
2610
+
2611
+ if (originalParam.type === 'TSParameterProperty') {
2612
+ const propertyName = getPatternName(originalParam.parameter);
2613
+ if (propertyName) {
2614
+ thisContext[propertyName] = funcEnv.get(propertyName);
2615
+ }
2616
+ }
2363
2617
  }
2364
2618
 
2365
2619
  const result = this.evaluate(methodFunc.__body, funcEnv);