---
title: "Move from Jint or ClearScript"
url: https://recursiveai.org/oneecma/cookbook/migrate-from-jint-clearscript/
description: "Move a .NET host from Jint or ClearScript to OneEcma: how engine creation, limits, exposing functions and objects, running code and catching errors map…"
version: "1.0.0"
---

# Move from Jint or ClearScript

Move a .NET host from Jint or ClearScript to OneEcma: how engine creation, limits, exposing functions and objects, running code and catching errors map, with one program run on all three engines and what each prints for the same mistake.

## The same job on three engines

The script calls a host function `load`, which returns an object with `items`, and then reads `lines`. The packages are Jint 4.17.0, Microsoft.ClearScript.V8 7.5.1.1 with its linux-x64 native package, and RecursiveAI.OneEcma 1.0.0, in one project:

```csharp
using Jint;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;
using RecursiveAI.OneEcma.Diagnostics;
using OneEcmaEngine = RecursiveAI.OneEcma.ScriptEngine;
using RecursiveAI.OneEcma;
using JsValue = RecursiveAI.OneEcma.JsValue;
using JsException = RecursiveAI.OneEcma.JsException;

const string script = """
    function invoiceTotal(inv) {
      return inv.lines.reduce((sum, l) => sum + l.qty * l.price, 0);
    }
    const invoice = load("INV-7");
    log("total " + invoiceTotal(invoice));
    """;

// Jint 4.17.0
Console.WriteLine("--- Jint");
var jint = new Engine(o => o.TimeoutInterval(TimeSpan.FromSeconds(1)).MaxStatements(100_000).LimitMemory(16_000_000).LimitRecursion(500));
jint.SetValue("log", new Action<string>(Console.WriteLine));
jint.Execute("globalThis.load = id => ({ id, items: [1, 2] });");
try { jint.Execute(script, "invoice.js"); }
catch (Jint.Runtime.JavaScriptException e) { Console.WriteLine(e.Message); Console.WriteLine(e.JavaScriptStackTrace); }

// ClearScript V8 7.5.1.1
Console.WriteLine("--- ClearScript");
using (var v8 = new V8ScriptEngine { MaxRuntimeHeapSize = (UIntPtr)(64 << 20) })
{
    v8.AddHostObject("log", new Action<string>(Console.WriteLine));
    v8.Script.load = v8.Evaluate("id => ({ id, items: [1, 2] })");
    try { v8.Execute(new DocumentInfo("invoice.js"), script); }
    catch (ScriptEngineException e) { Console.WriteLine(e.ErrorDetails); }
}

// OneEcma 1.0.0
Console.WriteLine("--- OneEcma");
var oneecma = new OneEcmaEngine(new ScriptEngineOptions
{
    Limits = new EngineLimits { WallClockMs = 1_000, Fuel = 100_000, MaxAllocatedBytes = 16_000_000, MaxCallDepth = 500 },
    Configure = e =>
    {
        e.DefineGlobalFunction("log", 1, (_, a) => { Console.WriteLine(e.ToDisplayString(a[0])); return JsValue.Undefined; });
        e.DefineGlobalFunction("load", 1, (_, a) =>
        {
            JsRealm realm = e.MainRealm;
            JsObject inv = realm.NewObject();
            realm.DefineData(inv, "id", a[0]);
            realm.DefineData(inv, "items", JsValue.FromObject(realm.NewArray([JsValue.FromNumber(1), JsValue.FromNumber(2)])));
            return JsValue.FromObject(inv);
        });
    },
});
try { oneecma.Evaluate(script, "invoice.js"); }
catch (JsException e)
{
    Console.WriteLine(oneecma.ToDisplayString(oneecma.MainRealm.Get(e.Value.AsObject!, "stack")));
    Console.WriteLine(DiagnosticRenderer.Render(e.Report!));
}
```

```text
--- Jint
Cannot read property 'reduce' of undefined
    at invoiceTotal (invoice.js:2:10)
    at invoice.js:5:16
--- ClearScript
TypeError: Cannot read properties of undefined (reading 'reduce')
    at invoiceTotal (invoice.js:2:20) ->   return inv.lines.reduce((sum, l) => sum + l.qty * l.price, 0);
    at invoice.js:5:16
--- OneEcma
TypeError: Cannot read properties of undefined (reading 'reduce')
    at invoiceTotal (invoice.js:2:20)
    at invoice.js:5:16
error[TypeError]: Cannot read properties of undefined (reading 'reduce')
 --> invoice.js:2:14
  |
2 |   return inv.lines.reduce((sum, l) => sum + l.qty * l.price, 0);
  |              ^^^^^ `inv.lines` is undefined
  |
  = help: did you mean `inv.items`? (Array, 2 items)
  = stack: invoiceTotal (invoice.js:2) ← <top-level> (invoice.js:5)
```

`log` is never reached: all three stop at `inv.lines.reduce`. OneEcma’s `err.stack` is the same as V8’s (through ClearScript) here, line and column included, and its report adds what the object held.

## How the APIs map

| Job | Jint 4 | ClearScript (V8) | OneEcma |
|---|---|---|---|
| Create an engine | `new Engine(options => …)` | `new V8ScriptEngine()` | `new ScriptEngine(new ScriptEngineOptions { … })` |
| Limits | `LimitMemory`, `TimeoutInterval`, `MaxStatements`, `LimitRecursion`, `CancellationToken` on the options | `MaxRuntimeHeapSize`; `Interrupt()` from another thread for a deadline | `EngineLimits`: `MaxAllocatedBytes`, `WallClockMs`, `Fuel`, `MaxCallDepth`, `MaxStringLength`; a `CancellationToken` on each call |
| Run code | `Execute(code, source)`, `Evaluate(code)` | `Execute(documentInfo, code)`, `Evaluate(code)` | `Evaluate(code, fileName)`; `EvaluateAsyncBody` for top-level `await` and `return`; `EvaluateModule` |
| Expose a function | `SetValue("log", new Action<string>(…))` | `AddHostObject("log", new Action<string>(…))` | `DefineGlobalFunction("log", 1, (this, args) => …)` or `realm.NewFunction` |
| Expose an object or type | `SetValue("api", obj)`; `TypeReference.CreateTypeReference<T>(engine)`; `AllowClr()` for whole assemblies | `AddHostObject("api", obj)`; `AddHostType(typeof(T))` | `[JsExport]` on the type, then `JsExports.InstallAll(realm)` and `realm.Wrap(obj)` |
| Call script from C# | `Invoke("fn", args)` | `Script.fn(args)` | `engine.Call(fn, this, args)` or `realm.Call` |
| Catch a script error | `JavaScriptException`: `Message`, `JavaScriptStackTrace` | `ScriptEngineException`: `ErrorDetails` | `JsException`: `Value`, `Report`, `Frames`; `JsLimitException` for a limit |

## What changes when you move

- **Exposing .NET is opt-in, member by member.** Jint wraps any CLR object passed to `SetValue`, and `AllowClr()` opens whole assemblies to script ([Jint README, v4.17.0](https://github.com/sebastienros/jint/blob/v4.17.0/README.md)). ClearScript’s exposed objects “require no modification, decoration, or special coding of any kind” and scripts reach “most of the features of exposed objects and types” ([ClearScript README](https://github.com/microsoft/ClearScript)). In OneEcma only types marked `[JsExport]` and their public members exist in script, the bindings are written at build time, and nothing is found by reflection. Plan one pass that marks the types your scripts use: see [Expose .NET objects with [JsExport]](https://recursiveai.org/oneecma/cookbook/jsexport/).
- **Conversions are strict.** A string isn’t accepted where a number is expected, or the other way round; the error names the member, the argument path and both types.
- **Host setup moves into `Configure`.** OneEcma explains a failure by replaying the run, and the replay rebuilds the world by calling `Configure` again. Setup done after the engine exists still works, but its failures aren’t explained.
- **Limits are counted differently.** Jint’s `MaxStatements` counts statements; OneEcma’s `Fuel` counts calls, loop back-edges, RegExp backtracking steps and units of built-in work, so retune the number rather than copying it. ClearScript’s heap limit is V8’s heap; OneEcma’s `MaxAllocatedBytes` counts bytes requested over the run.
- **Error text.** OneEcma’s `err.message` and `err.stack` follow V8’s wording and format, so code that matched ClearScript’s V8 messages keeps matching. Jint 4.17.0 printed “Cannot read property 'reduce' of undefined” for this script, where V8 prints “Cannot read properties of undefined (reading 'reduce')”.
- **No native code.** ClearScript embeds V8 through a native library per platform. OneEcma is managed C# with no dependency beyond the base class library, and runs under NativeAOT and trimming.
- **No `console`.** OneEcma gives scripts the language and its built-ins only. Define `console.log`, `print` or a logger yourself, as `log` is defined above.

## Good to know

- ClearScript’s `MaxRuntimeHeapSize`, `Interrupt` and `ScriptEngineException.ErrorDetails` are in the [ClearScript reference](https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_V8_V8ScriptEngine_MaxRuntimeHeapSize.htm). Jint’s constraints are under “Execution Constraints” in its [README](https://github.com/sebastienros/jint/blob/v4.17.0/README.md#execution-constraints).
- How OneEcma’s speed compares with Jint on lodash, preact and a React server render, with the method, is in [benchmarks](https://recursiveai.org/oneecma/docs/benchmarks/).
