Skip to content

Commit

Permalink
Update the jint options to support System.text.json (#15449)
Browse files Browse the repository at this point in the history
  • Loading branch information
hyzx86 authored Mar 14, 2024
1 parent 50583b0 commit b83e2dc
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json.Nodes;
using Jint;
using Jint.Native;
using Jint.Runtime.Interop;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.FileProviders;

Expand All @@ -19,7 +23,40 @@ public JavaScriptEngine(IMemoryCache memoryCache)

public IScriptingScope CreateScope(IEnumerable<GlobalMethod> methods, IServiceProvider serviceProvider, IFileProvider fileProvider, string basePath)
{
var engine = new Engine();
var engine = new Engine(options =>
{
// Make JsonArray behave like JS array.
options.SetWrapObjectHandler(static (e, target, type) =>
{
if (target is JsonArray)
{
var wrapped = new ObjectWrapper(e, target)
{
Prototype = e.Intrinsics.Array.PrototypeObject
};
return wrapped;
}
return new ObjectWrapper(e, target);
});
options.AddObjectConverter<JsonValueConverter>();
// We cannot access this[string] with anything else than JsonObject, otherwise itw will throw.
options.SetTypeResolver(new TypeResolver
{
MemberFilter = static info =>
{
if (info.ReflectedType != typeof(JsonObject) && info.Name == "Item" && info is PropertyInfo p)
{
var parameters = p.GetIndexParameters();
return parameters.Length != 1 || parameters[0].ParameterType != typeof(string);
}
return true;
}
});
});

foreach (var method in methods)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Jint;
using Jint.Native;
using Jint.Runtime.Interop;

namespace OrchardCore.Scripting.JavaScript;
public class JsonValueConverter : IObjectConverter
{
public bool TryConvert(Engine engine, object value, out JsValue result)
{
if (value is JsonValue jsonValue)
{
var valueKind = jsonValue.GetValueKind();
switch (valueKind)
{
case JsonValueKind.Object:
case JsonValueKind.Array:
result = JsValue.FromObject(engine, jsonValue);
break;
case JsonValueKind.String:
result = jsonValue.ToString();
break;
case JsonValueKind.Number:
if (jsonValue.TryGetValue<double>(out var doubleValue))
{
result = JsNumber.Create(doubleValue);
}
else
{
result = JsValue.Undefined;
}
break;
case JsonValueKind.True:
result = JsBoolean.True;
break;
case JsonValueKind.False:
result = JsBoolean.False;
break;
case JsonValueKind.Undefined:
result = JsValue.Undefined;
break;
case JsonValueKind.Null:
result = JsValue.Null;
break;
default:
result = JsValue.Undefined;
break;
}
return true;
}
result = JsValue.Undefined;
return false;

}
}
88 changes: 88 additions & 0 deletions test/OrchardCore.Tests/Scripting/ScriptFunctionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Text.Json.Nodes;
using OrchardCore.Scripting;
using OrchardCore.Tests.Apis.Context;

namespace OrchardCore.Tests.Scripting;
public class ScriptFunctionsTest
{
[Fact]
public async Task TheScriptingEngineShouldBeAbleToHandleJsonObject()
{
using var context = new SiteContext();
await context.InitializeAsync();
await context.UsingTenantScopeAsync(scope =>
{
var findUser = new GlobalMethod
{
Name = "tryAccessJsonObject",
Method = sp => () =>
{
const string jsonData = """
{
"age":33,
"falseValue":false,
"trueValue":true,
"stringValue":"stringTest",
"employees": {
"type": "array",
"value": [
{
"firstName": "John",
"lastName": "Doe"
},
{
"firstName": "Jane",
"lastName": "Doe"
}
]
}
}
""";
return JObject.Parse(jsonData);
}
};
var scriptingEngine = scope.ServiceProvider.GetRequiredService<IScriptingEngine>();
var scriptingScope = scriptingEngine.CreateScope([findUser], scope.ServiceProvider, null, null);
var result = (bool)scriptingEngine.Evaluate(scriptingScope,
@"var jobj = tryAccessJsonObject();
return jobj.age == 33;
");
Assert.True(result);
result = (bool)scriptingEngine.Evaluate(scriptingScope,
@"var jobj = tryAccessJsonObject();
return jobj.stringValue == ""stringTest"";
");
Assert.True(result);
result = (bool)scriptingEngine.Evaluate(scriptingScope,
@"var jobj = tryAccessJsonObject();
return jobj.employees.type == ""array"" &&
jobj.employees.value[0].firstName == ""John"";
");
Assert.True(result);
var result1 = scriptingEngine.Evaluate(scriptingScope,
@"var jobj = tryAccessJsonObject();
var steps = [];
if(!jobj.falseValue) steps.push(1);
if(jobj.trueValue) steps.push(2);
// falseValue should be false
if(jobj.falseValue == false) steps.push(3);
if(jobj.trueValue == true) steps.push(4);
if(!!jobj.trueValue) steps.push(5);
steps.push(jobj.falseValue);
steps.push(jobj.falseValue.toString());
return steps.join(',')
");
Assert.Equal("1,2,3,4,5,false,false", result1);
return Task.CompletedTask;
});
}
}

0 comments on commit b83e2dc

Please sign in to comment.