Skip to content

Commit

Permalink
Can reuse module
Browse files Browse the repository at this point in the history
  • Loading branch information
free.li committed Sep 15, 2022
1 parent c99869c commit 646777c
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Jint.Tests/Runtime/ModuleTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Esprima;
using Jint.Native;
using Jint.Runtime;

Expand Down Expand Up @@ -336,6 +337,21 @@ public void CanImportFromFileWithSpacesInPath()
Assert.Equal("John Doe", result);
}

[Fact]
public void CanReuseModule()
{
const string Code = "export function formatName(firstName, lastName) {\r\n return `${firstName} ${lastName}`;\r\n}";
var module = new JavaScriptParser().ParseModule(Code);
for (var i = 0; i < 5; i++)
{
var engine = new Engine();
engine.AddModule("__main__", x => x.AddModule(module));
var ns = engine.ImportModule("__main__");
var result = engine.Invoke(ns.Get("formatName"), "John" + i, "Doe").AsString();
Assert.Equal($"John{i} Doe", result);
}
}

internal static string GetBasePath()
{
var assemblyDirectory = new DirectoryInfo(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory);
Expand Down
14 changes: 14 additions & 0 deletions Jint/Engine.Ast.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ public static Script PrepareScript(string script, string? source = null)
return new JavaScriptParser(options).ParseScript(script, source);
}

/// <summary>
/// Prepares a module for the engine that includes static analysis data to speed up execution during run-time.
/// </summary>
/// <remarks>
/// Returned instance is reusable and thread-safe. You should prepare modules only once and then reuse them.
/// </remarks>
public static Module PrepareModule(string script, string? source = null)
{
var astAnalyzer = new AstAnalyzer();
var options = ParserOptions.Default with { OnNodeCreated = astAnalyzer.NodeVisitor };

return new JavaScriptParser(options).ParseModule(script, source);
}

private sealed class AstAnalyzer
{
private readonly Dictionary<string, EnvironmentRecord.BindingName> _bindingNames = new();
Expand Down
21 changes: 21 additions & 0 deletions Jint/ModuleBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public sealed class ModuleBuilder
{
private readonly Engine _engine;
private readonly string _specifier;
private Module? _module;
private readonly List<string> _sourceRaw = new();
private readonly Dictionary<string, JsValue> _exports = new();
private readonly ParserOptions _options;
Expand All @@ -24,10 +25,29 @@ internal ModuleBuilder(Engine engine, string specifier)

public ModuleBuilder AddSource(string code)
{
if (_module != null)
{
throw new InvalidOperationException("Cannot have both source text and pre-compiled.");
}
_sourceRaw.Add(code);
return this;
}

public ModuleBuilder AddModule(Module module)
{
if (_sourceRaw.Count > 0)
{
throw new InvalidOperationException("Cannot have both source text and pre-compiled.");
}

if (_module != null)
{
throw new InvalidOperationException("pre-compiled module already exists.");
}
_module = module;
return this;
}

public ModuleBuilder ExportValue(string name, JsValue value)
{
_exports.Add(name, value);
Expand Down Expand Up @@ -104,6 +124,7 @@ public ModuleBuilder WithOptions(Action<ParserOptions> configure)

internal Module Parse()
{
if (_module != null) return _module;
if (_sourceRaw.Count <= 0)
{
return new Module(NodeList.Create(Array.Empty<Statement>()));
Expand Down

0 comments on commit 646777c

Please sign in to comment.