jslike 1.7.0 → 1.7.2

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.
@@ -141,6 +141,9 @@ export class Interpreter {
141
141
 
142
142
  if (node.callee.type === 'MemberExpression') {
143
143
  thisContext = await this.evaluateAsync(node.callee.object, env);
144
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
145
+ return undefined;
146
+ }
144
147
  const prop = node.callee.computed
145
148
  ? await this.evaluateAsync(node.callee.property, env)
146
149
  : node.callee.property.name;
@@ -1230,6 +1233,9 @@ export class Interpreter {
1230
1233
  if (node.callee.type === 'MemberExpression') {
1231
1234
  // For method calls like obj.method(), set this to obj
1232
1235
  thisContext = this.evaluate(node.callee.object, env);
1236
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
1237
+ return undefined;
1238
+ }
1233
1239
  const prop = node.callee.computed
1234
1240
  ? this.evaluate(node.callee.property, env)
1235
1241
  : node.callee.property.name;
@@ -1308,8 +1314,14 @@ export class Interpreter {
1308
1314
  // Get function name for call stack tracking
1309
1315
  const funcName = metadata.name || func.name || 'anonymous';
1310
1316
 
1311
- // Bind 'this' if provided (for method calls)
1312
- if (thisContext !== undefined) {
1317
+ // Bind 'this': for arrow functions use captured this (lexical), for regular functions use call-site this
1318
+ if (metadata.isArrow) {
1319
+ // Arrow functions use lexically captured 'this', ignoring call-site 'this'
1320
+ if (metadata.capturedThis !== undefined) {
1321
+ funcEnv.define('this', metadata.capturedThis);
1322
+ }
1323
+ } else if (thisContext !== undefined) {
1324
+ // Regular functions use 'this' from the call site
1313
1325
  funcEnv.define('this', thisContext);
1314
1326
  }
1315
1327
 
@@ -1490,13 +1502,28 @@ export class Interpreter {
1490
1502
  }
1491
1503
 
1492
1504
  evaluateFunctionExpression(node, env) {
1505
+ const isArrow = node.type === 'ArrowFunctionExpression';
1506
+
1507
+ // For arrow functions, capture 'this' lexically from the enclosing scope
1508
+ let capturedThis;
1509
+ if (isArrow) {
1510
+ try {
1511
+ capturedThis = env.get('this');
1512
+ } catch (e) {
1513
+ // 'this' not defined in enclosing scope, leave undefined
1514
+ capturedThis = undefined;
1515
+ }
1516
+ }
1517
+
1493
1518
  const funcMetadata = {
1494
1519
  __isFunction: true,
1495
1520
  params: node.params,
1496
1521
  body: node.body,
1497
1522
  closure: env,
1498
- expression: node.type === 'ArrowFunctionExpression' && node.expression,
1499
- async: node.async || false
1523
+ expression: isArrow && node.expression,
1524
+ async: node.async || false,
1525
+ isArrow: isArrow,
1526
+ capturedThis: isArrow ? capturedThis : undefined
1500
1527
  };
1501
1528
 
1502
1529
  // Wrap in actual JavaScript function so it can be called by native code
package/dist/index.cjs CHANGED
@@ -6579,6 +6579,9 @@ var Interpreter = class _Interpreter {
6579
6579
  let methodName = null;
6580
6580
  if (node.callee.type === "MemberExpression") {
6581
6581
  thisContext = await this.evaluateAsync(node.callee.object, env);
6582
+ if (node.callee.optional && (thisContext === null || thisContext === void 0)) {
6583
+ return void 0;
6584
+ }
6582
6585
  const prop = node.callee.computed ? await this.evaluateAsync(node.callee.property, env) : node.callee.property.name;
6583
6586
  callee = thisContext[prop];
6584
6587
  methodName = prop;
@@ -7447,6 +7450,9 @@ var Interpreter = class _Interpreter {
7447
7450
  let methodName = null;
7448
7451
  if (node.callee.type === "MemberExpression") {
7449
7452
  thisContext = this.evaluate(node.callee.object, env);
7453
+ if (node.callee.optional && (thisContext === null || thisContext === void 0)) {
7454
+ return void 0;
7455
+ }
7450
7456
  const prop = node.callee.computed ? this.evaluate(node.callee.property, env) : node.callee.property.name;
7451
7457
  callee = thisContext[prop];
7452
7458
  methodName = prop;
@@ -7504,7 +7510,11 @@ var Interpreter = class _Interpreter {
7504
7510
  const metadata = func.__metadata || func;
7505
7511
  const funcEnv = new Environment(metadata.closure);
7506
7512
  const funcName = metadata.name || func.name || "anonymous";
7507
- if (thisContext !== void 0) {
7513
+ if (metadata.isArrow) {
7514
+ if (metadata.capturedThis !== void 0) {
7515
+ funcEnv.define("this", metadata.capturedThis);
7516
+ }
7517
+ } else if (thisContext !== void 0) {
7508
7518
  funcEnv.define("this", thisContext);
7509
7519
  }
7510
7520
  for (let i = 0; i < metadata.params.length; i++) {
@@ -7639,13 +7649,24 @@ var Interpreter = class _Interpreter {
7639
7649
  return obj;
7640
7650
  }
7641
7651
  evaluateFunctionExpression(node, env) {
7652
+ const isArrow = node.type === "ArrowFunctionExpression";
7653
+ let capturedThis;
7654
+ if (isArrow) {
7655
+ try {
7656
+ capturedThis = env.get("this");
7657
+ } catch (e) {
7658
+ capturedThis = void 0;
7659
+ }
7660
+ }
7642
7661
  const funcMetadata = {
7643
7662
  __isFunction: true,
7644
7663
  params: node.params,
7645
7664
  body: node.body,
7646
7665
  closure: env,
7647
- expression: node.type === "ArrowFunctionExpression" && node.expression,
7648
- async: node.async || false
7666
+ expression: isArrow && node.expression,
7667
+ async: node.async || false,
7668
+ isArrow,
7669
+ capturedThis: isArrow ? capturedThis : void 0
7649
7670
  };
7650
7671
  const interpreter = this;
7651
7672
  const wrappedFunc = funcMetadata.async ? async function(...args) {
package/dist/index.d.cts CHANGED
@@ -7306,6 +7306,9 @@ class Interpreter {
7306
7306
 
7307
7307
  if (node.callee.type === 'MemberExpression') {
7308
7308
  thisContext = await this.evaluateAsync(node.callee.object, env);
7309
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
7310
+ return undefined;
7311
+ }
7309
7312
  const prop = node.callee.computed
7310
7313
  ? await this.evaluateAsync(node.callee.property, env)
7311
7314
  : node.callee.property.name;
@@ -8395,6 +8398,9 @@ class Interpreter {
8395
8398
  if (node.callee.type === 'MemberExpression') {
8396
8399
  // For method calls like obj.method(), set this to obj
8397
8400
  thisContext = this.evaluate(node.callee.object, env);
8401
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
8402
+ return undefined;
8403
+ }
8398
8404
  const prop = node.callee.computed
8399
8405
  ? this.evaluate(node.callee.property, env)
8400
8406
  : node.callee.property.name;
@@ -8473,8 +8479,14 @@ class Interpreter {
8473
8479
  // Get function name for call stack tracking
8474
8480
  const funcName = metadata.name || func.name || 'anonymous';
8475
8481
 
8476
- // Bind 'this' if provided (for method calls)
8477
- if (thisContext !== undefined) {
8482
+ // Bind 'this': for arrow functions use captured this (lexical), for regular functions use call-site this
8483
+ if (metadata.isArrow) {
8484
+ // Arrow functions use lexically captured 'this', ignoring call-site 'this'
8485
+ if (metadata.capturedThis !== undefined) {
8486
+ funcEnv.define('this', metadata.capturedThis);
8487
+ }
8488
+ } else if (thisContext !== undefined) {
8489
+ // Regular functions use 'this' from the call site
8478
8490
  funcEnv.define('this', thisContext);
8479
8491
  }
8480
8492
 
@@ -8655,13 +8667,28 @@ class Interpreter {
8655
8667
  }
8656
8668
 
8657
8669
  evaluateFunctionExpression(node, env) {
8670
+ const isArrow = node.type === 'ArrowFunctionExpression';
8671
+
8672
+ // For arrow functions, capture 'this' lexically from the enclosing scope
8673
+ let capturedThis;
8674
+ if (isArrow) {
8675
+ try {
8676
+ capturedThis = env.get('this');
8677
+ } catch (e) {
8678
+ // 'this' not defined in enclosing scope, leave undefined
8679
+ capturedThis = undefined;
8680
+ }
8681
+ }
8682
+
8658
8683
  const funcMetadata = {
8659
8684
  __isFunction: true,
8660
8685
  params: node.params,
8661
8686
  body: node.body,
8662
8687
  closure: env,
8663
- expression: node.type === 'ArrowFunctionExpression' && node.expression,
8664
- async: node.async || false
8688
+ expression: isArrow && node.expression,
8689
+ async: node.async || false,
8690
+ isArrow: isArrow,
8691
+ capturedThis: isArrow ? capturedThis : undefined
8665
8692
  };
8666
8693
 
8667
8694
  // Wrap in actual JavaScript function so it can be called by native code
package/dist/index.d.ts CHANGED
@@ -7306,6 +7306,9 @@ class Interpreter {
7306
7306
 
7307
7307
  if (node.callee.type === 'MemberExpression') {
7308
7308
  thisContext = await this.evaluateAsync(node.callee.object, env);
7309
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
7310
+ return undefined;
7311
+ }
7309
7312
  const prop = node.callee.computed
7310
7313
  ? await this.evaluateAsync(node.callee.property, env)
7311
7314
  : node.callee.property.name;
@@ -8395,6 +8398,9 @@ class Interpreter {
8395
8398
  if (node.callee.type === 'MemberExpression') {
8396
8399
  // For method calls like obj.method(), set this to obj
8397
8400
  thisContext = this.evaluate(node.callee.object, env);
8401
+ if (node.callee.optional && (thisContext === null || thisContext === undefined)) {
8402
+ return undefined;
8403
+ }
8398
8404
  const prop = node.callee.computed
8399
8405
  ? this.evaluate(node.callee.property, env)
8400
8406
  : node.callee.property.name;
@@ -8473,8 +8479,14 @@ class Interpreter {
8473
8479
  // Get function name for call stack tracking
8474
8480
  const funcName = metadata.name || func.name || 'anonymous';
8475
8481
 
8476
- // Bind 'this' if provided (for method calls)
8477
- if (thisContext !== undefined) {
8482
+ // Bind 'this': for arrow functions use captured this (lexical), for regular functions use call-site this
8483
+ if (metadata.isArrow) {
8484
+ // Arrow functions use lexically captured 'this', ignoring call-site 'this'
8485
+ if (metadata.capturedThis !== undefined) {
8486
+ funcEnv.define('this', metadata.capturedThis);
8487
+ }
8488
+ } else if (thisContext !== undefined) {
8489
+ // Regular functions use 'this' from the call site
8478
8490
  funcEnv.define('this', thisContext);
8479
8491
  }
8480
8492
 
@@ -8655,13 +8667,28 @@ class Interpreter {
8655
8667
  }
8656
8668
 
8657
8669
  evaluateFunctionExpression(node, env) {
8670
+ const isArrow = node.type === 'ArrowFunctionExpression';
8671
+
8672
+ // For arrow functions, capture 'this' lexically from the enclosing scope
8673
+ let capturedThis;
8674
+ if (isArrow) {
8675
+ try {
8676
+ capturedThis = env.get('this');
8677
+ } catch (e) {
8678
+ // 'this' not defined in enclosing scope, leave undefined
8679
+ capturedThis = undefined;
8680
+ }
8681
+ }
8682
+
8658
8683
  const funcMetadata = {
8659
8684
  __isFunction: true,
8660
8685
  params: node.params,
8661
8686
  body: node.body,
8662
8687
  closure: env,
8663
- expression: node.type === 'ArrowFunctionExpression' && node.expression,
8664
- async: node.async || false
8688
+ expression: isArrow && node.expression,
8689
+ async: node.async || false,
8690
+ isArrow: isArrow,
8691
+ capturedThis: isArrow ? capturedThis : undefined
8665
8692
  };
8666
8693
 
8667
8694
  // Wrap in actual JavaScript function so it can be called by native code
package/dist/index.js CHANGED
@@ -6545,6 +6545,9 @@ var Interpreter = class _Interpreter {
6545
6545
  let methodName = null;
6546
6546
  if (node.callee.type === "MemberExpression") {
6547
6547
  thisContext = await this.evaluateAsync(node.callee.object, env);
6548
+ if (node.callee.optional && (thisContext === null || thisContext === void 0)) {
6549
+ return void 0;
6550
+ }
6548
6551
  const prop = node.callee.computed ? await this.evaluateAsync(node.callee.property, env) : node.callee.property.name;
6549
6552
  callee = thisContext[prop];
6550
6553
  methodName = prop;
@@ -7413,6 +7416,9 @@ var Interpreter = class _Interpreter {
7413
7416
  let methodName = null;
7414
7417
  if (node.callee.type === "MemberExpression") {
7415
7418
  thisContext = this.evaluate(node.callee.object, env);
7419
+ if (node.callee.optional && (thisContext === null || thisContext === void 0)) {
7420
+ return void 0;
7421
+ }
7416
7422
  const prop = node.callee.computed ? this.evaluate(node.callee.property, env) : node.callee.property.name;
7417
7423
  callee = thisContext[prop];
7418
7424
  methodName = prop;
@@ -7470,7 +7476,11 @@ var Interpreter = class _Interpreter {
7470
7476
  const metadata = func.__metadata || func;
7471
7477
  const funcEnv = new Environment(metadata.closure);
7472
7478
  const funcName = metadata.name || func.name || "anonymous";
7473
- if (thisContext !== void 0) {
7479
+ if (metadata.isArrow) {
7480
+ if (metadata.capturedThis !== void 0) {
7481
+ funcEnv.define("this", metadata.capturedThis);
7482
+ }
7483
+ } else if (thisContext !== void 0) {
7474
7484
  funcEnv.define("this", thisContext);
7475
7485
  }
7476
7486
  for (let i = 0; i < metadata.params.length; i++) {
@@ -7605,13 +7615,24 @@ var Interpreter = class _Interpreter {
7605
7615
  return obj;
7606
7616
  }
7607
7617
  evaluateFunctionExpression(node, env) {
7618
+ const isArrow = node.type === "ArrowFunctionExpression";
7619
+ let capturedThis;
7620
+ if (isArrow) {
7621
+ try {
7622
+ capturedThis = env.get("this");
7623
+ } catch (e) {
7624
+ capturedThis = void 0;
7625
+ }
7626
+ }
7608
7627
  const funcMetadata = {
7609
7628
  __isFunction: true,
7610
7629
  params: node.params,
7611
7630
  body: node.body,
7612
7631
  closure: env,
7613
- expression: node.type === "ArrowFunctionExpression" && node.expression,
7614
- async: node.async || false
7632
+ expression: isArrow && node.expression,
7633
+ async: node.async || false,
7634
+ isArrow,
7635
+ capturedThis: isArrow ? capturedThis : void 0
7615
7636
  };
7616
7637
  const interpreter = this;
7617
7638
  const wrappedFunc = funcMetadata.async ? async function(...args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jslike",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Production-ready JavaScript interpreter with full ES6+ support using Acorn parser",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",