eval5: an ES5 JavaScript interpreter for environments with no eval or Function
A JavaScript interpreter written in TypeScript - Support ES5
At a glance
- What is it?
- eval5 is a JavaScript interpreter written in TypeScript that understands complete ES5 syntax, so a script can be parsed and executed inside a browser, a Node.js process or a mini program environment that does not expose eval or the Function constructor. It adds an execution timeout and a scriptable global scope, and it does not implement strict mode.
- Who is it for?
- eval5 suits teams that must run user-supplied JavaScript inside a host that forbids eval and the Function constructor, most obviously WeChat mini program environments, and also suits anyone who wants a hard execution timeout on script evaluation rather than the unbounded behaviour of native eval.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Built for hosts where eval does not exist
The reason this project exists is stated in its own list of use cases. The first is needing a sandbox environment in a browser to execute JavaScript scripts. The second is controlling how long execution takes. The third is JavaScript runtimes that do not support eval or Function, and the README names WeChat mini programs as the case in point, with a demo repository and two sibling projects, we-script and taro-script, linked alongside it. The last is research and study. That list tells you the shape of the audience: developers building a platform where end users supply script snippets, and who cannot hand that code to the host engine because the host has no engine to hand it to. The repository topics follow the same line, including sandbox, vm and wechat-mini. Everything else in the project is a consequence of that brief, including the ES5 ceiling and the absence of strict mode.
Installing and evaluating the first expression
The package is published to npm as eval5, and installation is a single command:
npm install --save eval5The usage example in the README creates an interpreter, evaluates a string and prints the result. The constructor takes a context object and an options object, and the evaluate method returns the value of the last expression:
import { Interpreter } from "eval5";
const interpreter = new Interpreter(window, {
timeout: 1000,
});
let result;
try {
result = interpreter.evaluate("1+1");
console.log(result);The example then defines two variables in separate evaluate calls and reads back their sum, which shows the property that makes this an interpreter rather than a one-shot expression evaluator. State persists across evaluate calls on the same interpreter instance, so a script can be built up in pieces. If you do not need that state, the README also documents a standalone evaluate function that takes the code, an optional context and optional options, with the caveat that each call creates a new interpreter, so variables defined in one call are not visible in the next.
The timeout is the sandbox boundary that actually holds
The options interface is small, and one of its three fields carries most of the weight. timeout is a number, and the README states the default is 0, which means no limit. globalContextInFunction accepts any value, and rootContext accepts an object or null, described as the root scope and read only. The timeout is the practical enforcement mechanism behind the second listed use case, controlling execution duration, because the interpreter can abandon a script that never returns. Two things are worth being clear about. First, an unset timeout means an unbounded evaluation, so a script with an infinite loop in an environment without a working eval will hang the host. Second, the timeout is a duration limit on execution rather than a memory or capability limit, so a script that finishes quickly but allocates heavily is not constrained by it. The README documents no memory ceiling, no instruction-count limit and no way to restrict which globals a script can reach. For a sandbox boundary, that is a narrower guarantee than the word sandbox implies.
No strict mode, and this binding inside functions
The documentation is direct about a deviation from the language. eval5 does not support use strict strict mode, and in a non-strict function this normally points at the global scope, but inside eval5 it is undefined. The globalContextInFunction option exists to set that default. The README gives the contrast in two small examples: with the option unset, this inside the script returns the context object while a function returning this returns undefined, and with Interpreter.globalContextInFunction set to window, the function returns window instead. There is a caveat attached to that second example, because calling a native browser function with the wrong receiver throws. The alert case makes it concrete: with globalContextInFunction set to an empty object and a context holding alert, the script calling alert throws Illegal invocation, because it behaves like alert.call({}, ...) rather than a direct call. That is a compatibility trap for anyone porting scripts from a browser, where alert works in a non-strict function.
Two ways in: the class and the convenience wrappers
The library exposes three entry shapes, and the differences matter more than they look. The Interpreter class is the full interface. It carries the evaluate method, an appendCode method documented as an alias of evaluate, getExecutionTime which returns the duration of the last evaluate call, setExecTimeout which takes a number defaulting to 0, and getOptions which returns the options as a Readonly object. It also exposes static members: version for the current version, and global whose default is an empty object and which sets the default global scope, so a script can reach a host object such as window without it being threaded through every call. The Function export takes the same two defaults, Interpreter.global and Interpreter.globalContextInFunction, and creates a new interpreter for each instance, which gives you a familiar callable shape:
import { Function } from "eval5";
const func = new Function("a", "b", "return a+b;");
console.log(func(100, 200)); // 300The static Interpreter.global is the reason that example reads like ordinary JavaScript rather than a sandbox escape hatch. It is also the reason to think carefully before enabling it in a host that runs untrusted code, since a shared global means every script in the process can see whatever you put there.
How this differs from the host's own eval and from Node's vm
The README lists the Node.js vm API as a related reference, naming vm.createContext, vm.compileFunction, vm.runInContext, vm.runInNewContext and vm.Script. The difference in approach is clear from what eval5 is for. Native eval and the Function constructor run code in the host engine, which means they inherit the host's language version, its strict mode rules and its performance characteristics, and they are unavailable in environments that block them. The Node vm module takes the opposite trade: it does provide a context boundary, but it still executes on V8, so it inherits V8's ES support and it is Node-only. eval5 parses and interprets the script itself, which is why it can work in a mini program with no eval at all, and why the price is a language ceiling at ES5 and the absence of strict mode semantics. The README also links two other interpreter projects, evaljs and closure-interpreter, as related reading, which tells you this is a recognised category of tool with more than one implementation.
A version 1.4.8 package with a quiet release history
The package manifest gives the current published version as 1.4.8, and the releases line up: v1.4.8 on 2024-08-11, v1.4.7 on 2021-10-31 and v1.4.6 on 2020-09-06. The last push to the repository was on 2026-04-02, which is after the newest tag, so the source tree has moved on from what is on npm. That gap matters in practice if you pin the package and hit a bug, because the fix may exist in the repository but not in the registry. The licence is MIT, declared in both the manifest and the README, and the repository also carries a Chinese README alongside README-en_US.md, with the documentation site linked as a live playground. The build itself is a fairly standard TypeScript pipeline: tsc produces the CommonJS and ES module outputs with different targets, rollup produces the UMD bundles including a minified variant, jest runs the tests, and the published files list is umd, lib, dist and the markdown files. The test suite lives in a test directory and the configuration in jest.config.js, so the project does have automated coverage of its own behaviour.
Editorial conclusion
eval5 suits teams that must run user-supplied JavaScript inside a host that forbids eval and the Function constructor, most obviously WeChat mini program environments, and also suits anyone who wants a hard execution timeout on script evaluation rather than the unbounded behaviour of native eval. It is the wrong tool if your code needs anything beyond ES5, since the supported ECMAScript version is listed as ES5, and it is the wrong tool if you rely on strict mode semantics, because eval5 does not support use strict and gives functions a this value of undefined by default. Verify first that the timeout option is set for any script that comes from outside your codebase, since the default is zero, meaning no limit, and check the release situation before committing to it, because v1.4.8 was published on 2024-08-11 and the last push to the repository was on 2026-04-02.
Frequently asked questions
How do I install eval5?
The README gives a single npm command: npm install --save eval5. The package publishes CommonJS, ES module and UMD builds, with type declarations included.
How do I limit how long a script can run in eval5?
Pass the timeout option, for example new Interpreter(window, { timeout: 1000 }), or call setExecTimeout. The README states the default timeout is 0, which means no limit.
Does eval5 support strict mode?
No. The README states that eval5 does not support use strict strict mode, and that in a function this is undefined by default rather than pointing at the global scope. The globalContextInFunction option sets the default for functions.
Which ECMAScript version does eval5 support?
The README lists ES5 under the supported ECMAScript versions, and the repository description says it supports complete ES5 syntax. The package is written in TypeScript.
What is the difference between the Interpreter class and the standalone evaluate function?
The standalone evaluate function creates a new interpreter on every call, so state does not carry between calls, while an Interpreter instance keeps variables across successive evaluate calls. The Function export also creates a new interpreter, using Interpreter.global and Interpreter.globalContextInFunction as defaults.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bplok20010-eval5)Was this useful?