Closed gjvdkamp closed 1 year ago
Hi @gjvdkamp,
I asked ChatGPT and got all excited ðŸ˜
Wow, ChatGPT is very impressive... yet very wrong in this case 🤣
Often the best way to deal with a script object is to use the script engine. Consider the following:
dynamic isFunctionImpl = engine.Evaluate("obj => obj instanceof Function");
bool IsFunction(object value) => value is ScriptObject obj && isFunctionImpl(obj);
Now you have an easy way to perform the test:
Console.WriteLine(IsFunction(engine.Evaluate("Math"))); // output: False
Console.WriteLine(IsFunction(engine.Evaluate("Math.sqrt"))); // output: True
Good luck!
Ah very clever to only go to the engine to verify for ScriptObjects that should speed it up considerably. Thanks so much!
Ah very clever to only go to the engine to verify for ScriptObjects that should speed it up considerably.
Actually, you can perform several checks without invoking the engine at all. For example, some V8 script objects, when brought over to the host, implement managed interfaces such as IArrayBuffer
, IDataView
, and ITypedArray<T>
. Normal V8 script arrays similarly implement IList
. And there are internal ways to quickly identify promises and other things. Not so for functions, unfortunately, and there's currently no consistent, comprehensive public API for such tests 😔
Hi, in the end I went for this approach where I first check if it's an array, then distinguish between object and function. Reason being that I don't easily know the name of engine variables as the code is user generated.
switch (hostRefToScriptObj ) {
case IList ar:
// array
case ScriptObject so:
if (so.PropertyNames.Any()) {
// object
}
else {
// function
}
default: // value
}
However, now I have another issue..
If I know I have a reference to a ScriptObject hostRefToScriptObj
that is a function, how I can see the source? In javascript I'd call engineObject.toString()
to get and parse the function source, but now I'm in C# with a host reference to a script object...
Can I pass that back to the engine somehow to toString?
If I call hostRefToScriptObj.ToString()
in C# I just get "Microsoft.ClearScript.V8.V8ScriptItem"
Should I work out the whole path towards that object from engine.Global
and call engine.Evaluate(wholePath + ".toString()")
? Or can I pass these refs back to the engine somehow?
Hi @gjvdkamp,
if (so.PropertyNames.Any())
Script functions, like other script objects, can have arbitrary user-defined properties, so this test is fragile. The instanceof Function
test is more reliable, but even that could break if a script clobbered the built-in Function
object.
The best way would be to save off Function
before running any untrusted script code, then use that saved value for the instanceof
test. We'll add a more convenient alternative in a future release.
Can I pass that back to the engine somehow to toString?
Of course:
var value = engine.Evaluate("(function (x) { return 1 / Math.sqrt(x) })");
if (value is ScriptObject scriptObject) {
Console.WriteLine(scriptObject.InvokeMethod("toString"));
}
Or, alternatively:
dynamic value = engine.Evaluate("(function (x) { return 1 / Math.sqrt(x) })");
if (value is ScriptObject) {
Console.WriteLine(value.toString());
}
Cheers!
That worked!! This stuff with dynamic is so elegant.. learning so much thanks!
And yes, did think of functions having properties (silly javascript..) thought it would be ok for now.. will take a new swing at it with my newfound prowess and after reading it again.
Hi,
The way we use V8 has user type code pretty freely, so I don't know what variables they're going to declare and if they'll write functions etc. I want to dump what they're making into a window, and cerate extra functionality for that, for that I need to be able to tell the types of what they have created. Right now I convert things to NewtonSoft Json but then then functions end up as empty objects {}..
I asked ChatGPT and got all excited ðŸ˜
Hoping you still know better :)