eval5: JavaScript ES5 Interpreter

raw JSON →
1.4.8 verified Sat Apr 25 auth: no javascript

eval5 is a JavaScript interpreter written in TypeScript, designed to execute full ES5 syntax within various JavaScript environments including browsers, Node.js, and mini-programs like WeChat and Taro. Currently at version 1.4.8, the project maintains an active release cadence, primarily focusing on bug fixes and minor improvements. Its key differentiators include providing a sandboxed execution environment, allowing control over script execution time, and enabling JavaScript execution in environments where native `eval` or `Function` constructors are unavailable or restricted. It's particularly useful for scenarios requiring isolated script execution or educational purposes, strictly adhering to the ES5 specification without support for newer ECMAScript features.

error ReferenceError: <variable_name> is not defined
cause Attempting to access a variable that was defined in a previous `evaluate` call using the standalone `evaluate` function, or accessing a variable not in the current interpreter's scope.
fix
If you need shared state across multiple code snippets, use an Interpreter instance. If using the standalone evaluate function, pass all necessary variables and functions into its ctx parameter for each invocation.
error TypeError: Illegal invocation
cause A host environment function (like `alert` or `console.log`) was called from within the `eval5` interpreter without its original `this` context.
fix
Bind the host function to its original object before passing it into the interpreter's context. Example: new Interpreter({ alert: window.alert.bind(window) }).
error TypeError: Cannot read properties of undefined (reading '<property>')
cause Attempting to access a property on `this` inside a function executed by `eval5` when `this` is `undefined` (which is the default behavior if `globalContextInFunction` is not set).
fix
Configure the globalContextInFunction option in the Interpreter constructor or globally via Interpreter.globalContextInFunction to set the desired this context for functions.
breaking The `rootContext` property on the `Interpreter` constructor options was removed in version 1.4.0. It was replaced by `globalContextInFunction`.
fix Use `globalContextInFunction` option in the `Interpreter` constructor instead of `rootContext` to control the 'this' context within functions.
gotcha By default, `this` inside functions evaluated by `eval5` will be `undefined`, unlike native non-strict JavaScript where it defaults to the global object. This can lead to unexpected behavior for code expecting `this` to point to `window` or `global`.
fix Set the `globalContextInFunction` option in the `Interpreter` constructor or globally via `Interpreter.globalContextInFunction` to the desired global object (e.g., `window` or `globalThis`) to control `this` behavior in functions.
gotcha When calling host environment methods (like `alert` or `console.log`) passed into the interpreter's context, you might encounter 'Illegal invocation' errors if the methods are not correctly bound. This happens because `eval5` might call them without the correct `this` context.
fix Bind host functions explicitly when passing them to the interpreter's context. For example: `const ctx = { alert: alert.bind(window) };` or `const ctx = { console: { log: console.log.bind(console) } };`.
gotcha eval5 only supports the ES5 specification. It does not parse or execute newer ECMAScript features (ES6+), such as `let`/`const`, arrow functions, classes, modules, or async/await.
fix Ensure that all JavaScript code provided to `eval5` is transpiled down to ES5 syntax using tools like Babel if it originates from a newer ECMAScript version.
npm install eval5
yarn add eval5
pnpm add eval5

Demonstrates how to create an `Interpreter` instance with a custom global context and options, then execute multiple JavaScript code snippets sequentially, maintaining state across calls and logging results.

import { Interpreter } from "eval5";

// Define a custom context for the interpreter
const myContext = {
  customVar: 42,
  log: (...args: any[]) => console.log('INTERPRETER LOG:', ...args)
};

const interpreter = new Interpreter(myContext, {
  timeout: 5000, // Set a timeout for execution (5 seconds)
  // globalContextInFunction: window // For browser environments to set 'this' in functions
});

let result;

try {
  interpreter.evaluate("var a = 100;");
  interpreter.evaluate("var b = customVar * 2;");
  result = interpreter.evaluate("a + b;");
  myContext.log(`First evaluation result: ${result}`); // INTERPRETER LOG: First evaluation result: 184

  interpreter.evaluate("function add(x, y) { return x + y; }");
  result = interpreter.evaluate("add(a, b);");
  myContext.log(`Second evaluation result (calling function): ${result}`); // INTERPRETER LOG: Second evaluation result (calling function): 184

  // Demonstrate scope isolation
  const outerScopeVar = 500;
  interpreter.evaluate(`
    var c = ${outerScopeVar};
    log('Inside interpreter, c is:', c);
    var d = 10;
  `);

  // Accessing 'd' outside the interpreter's scope would fail:
  // console.log(interpreter.evaluate("d;")); // ReferenceError: d is not defined

  myContext.log('Interpreter operations complete.');
} catch (e: any) {
  console.error("Interpreter error:", e.message);
}