Meziantou.Framework.JavaScriptEngine
1.0.2
Prefix Reserved
dotnet add package Meziantou.Framework.JavaScriptEngine --version 1.0.2
NuGet\Install-Package Meziantou.Framework.JavaScriptEngine -Version 1.0.2
<PackageReference Include="Meziantou.Framework.JavaScriptEngine" Version="1.0.2" />
<PackageVersion Include="Meziantou.Framework.JavaScriptEngine" Version="1.0.2" />
<PackageReference Include="Meziantou.Framework.JavaScriptEngine" />
paket add Meziantou.Framework.JavaScriptEngine --version 1.0.2
#r "nuget: Meziantou.Framework.JavaScriptEngine, 1.0.2"
#:package Meziantou.Framework.JavaScriptEngine@1.0.2
#addin nuget:?package=Meziantou.Framework.JavaScriptEngine&version=1.0.2
#tool nuget:?package=Meziantou.Framework.JavaScriptEngine&version=1.0.2
Meziantou.Framework.JavaScriptEngine
An ECMAScript engine written in .NET: a hand-written parser, a bytecode compiler and an interpreter. It is validated by
test262, the conformance suite of ECMAScript: see
the test262 results, and by the
Web Tooling Benchmark (babel,
TypeScript, prettier, terser... give the same results as in Node.js) and
about 60 npm packages (lightningcss, sass,
tailwindcss, prettier, Vue, date-fns, d3... loaded as ES modules in a page of Meziantou.Framework.WebPlatform, and
compared with Chromium). It implements ECMAScript
2025 (including the proper tail calls of strict code), ECMA-402 (Intl) and Temporal, the stage 3 proposals
decorators (with the accessor fields and the
metadata of Symbol.metadata), import defer, source phase
imports (the module sources are given by the host),
immutable ArrayBuffer (transferToImmutable,
sliceToImmutable), Await Dictionary (Promise.allKeyed and Promise.allSettledKeyed) and Non-extensible Applies to
Private (a private field or method cannot be added to a non-extensible object), and the ShadowRealm,
Import Text and Import Bytes
proposals. It uses no reflection: it is trimming- and Native AOT-compatible, and its results do not depend
on the globalization settings of the process (the Unicode, time zone and CLDR data are part of the library, and the word
lists of ICU that Intl.Segmenter uses for Chinese, Japanese, Thai, Lao, Khmer and Burmese come from
Meziantou.Framework.Unicode.Dictionaries).
It is the script engine of Meziantou.Framework.WebPlatform, through Meziantou.Framework.WebPlatform.JavaScript.
Run scripts
A JsEngine is an agent: it runs the code of its realms on one thread at a time, and owns the job queue of the
promises. A JsRealm has its own global object and intrinsics.
using var engine = new JsEngine(new JsEngineOptions
{
Timeout = TimeSpan.FromSeconds(5), // per entry into JavaScript
RecursionLimit = 1_000,
});
var realm = engine.CreateRealm();
// Expose a .NET function to the scripts
using (engine.Enter())
{
realm.GlobalObject.SetProperty("add", realm.CreateFunction("add", 2, (thisValue, arguments) => arguments[0].AsNumber() + arguments[1].AsNumber()));
}
var result = realm.Execute("const values = [1, 2, 3].map(x => add(x, 10)); values.join('-')");
Assert.Equal("11-12-13", result.AsString());
// The promise jobs run when the host asks for them
realm.Execute("globalThis.log = []; Promise.resolve().then(() => log.push('job')); log.push('script');");
engine.RunJobs();
Assert.Equal("script,job", realm.Execute("log.join()").AsString());
// An uncaught JavaScript error is a JsException
var exception = Assert.Throws<JsException>(() => realm.Execute("null.x"));
Assert.StartsWith("TypeError", exception.Message, StringComparison.Ordinal);
JsEngineOptions limits each entry into JavaScript (a script, a call from .NET): Timeout, MemoryLimit (the bytes
allocated by the thread), MaxStatements, RecursionLimit (10,000 calls by default: the frames of the interpreter are
not on the .NET stack, and an unbounded recursion throws a RangeError), RegExpTimeout and a CancellationToken. A
script that exceeds a limit is stopped with a JsTerminationException, which JavaScript code cannot catch. The options
also give the clock (TimeProvider), the time zone, the default locale, the host hooks (JsHost: the compilation of
strings by eval, the promise rejection tracking, the job callbacks) and the module loader.
The members of the objects (JsObject.GetProperty, SetProperty, JsRealm.CreateObject...) are used inside a scope
of the engine (using var scope = engine.Enter()); JsRealm.Execute, JsEngine.Call and JsEngine.Construct enter
it themselves.
Modules
The modules are loaded by a JsModuleLoader: derive from it and override LoadImportedModule to resolve a specifier
and complete the request with a module (JsRealm.ParseModule, or for the json, text and bytes values of the type
import attribute JsRealm.CreateJsonModule, CreateTextModule and CreateBytesModule), or fail it. A module is
loaded, linked, then evaluated, as in the specification:
var files = new Dictionary<string, string>(StringComparer.Ordinal)
{
["main.js"] = "import { square } from './math.js'; globalThis.result = square(7);",
["math.js"] = "export function square(x) { return x * x; }",
};
using var engine = new JsEngine(new JsEngineOptions { ModuleLoader = new DictionaryModuleLoader(files) });
var realm = engine.CreateRealm();
var module = realm.ParseModule(files["main.js"], "main.js");
module.LoadRequestedModules();
engine.RunJobs();
module.Link();
module.Evaluate();
engine.RunJobs();
Assert.Equal(49, realm.Execute("result").AsNumber());
The value of a source phase import (import source x from and import.source()) is the module source of the module
(JsModule.ModuleSource), set by the module loader: a JsHostObject that extends JsRealm.AbstractModuleSource and
whose ModuleSourceClassName is set (e.g. WebAssembly.Module). The source phase import of a module that has no module
source, such as a JavaScript module, throws a SyntaxError.
Documentation
docs/architecture.md describes the values, the objects, the realms, the compiler and the interpreter.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net11.0 is compatible. |
-
net10.0
- Meziantou.Framework.Language.Regex (>= 4.0.6)
- Meziantou.Framework.Unicode (>= 2.0.13)
- Meziantou.Framework.Unicode.Dictionaries (>= 1.0.1)
-
net11.0
- Meziantou.Framework.Language.Regex (>= 4.0.6)
- Meziantou.Framework.Unicode (>= 2.0.13)
- Meziantou.Framework.Unicode.Dictionaries (>= 1.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Meziantou.Framework.JavaScriptEngine:
| Package | Downloads |
|---|---|
|
Meziantou.Framework.WebPlatform.JavaScript
Runs the scripts of the documents of Meziantou.Framework.WebPlatform with Meziantou.Framework.JavaScriptEngine (a ScriptEngine with the WebIDL bindings of the DOM). |
GitHub repositories
This package is not used by any popular GitHub repositories.