Open Taritsyn opened 4 years ago
Hey! Interesting point. I've just taken a look at Jurassic's API, in particular ScriptEngine
:
/// <summary>
/// Executes the given source code. Execution is bound to the global scope.
/// </summary>
/// <param name="code"> The javascript source code to execute. </param>
/// <returns> The result of executing the source code. </returns>
/// <exception cref="ArgumentNullException"> <paramref name="code"/> is a <c>null</c> reference. </exception>
public object Evaluate(string code)
{
return Evaluate(new StringScriptSource(code));
}
/// <summary>
/// Executes the given source code. Execution is bound to the global scope.
/// </summary>
/// <typeparam name="T"> The type to convert the result to. </typeparam>
/// <param name="code"> The javascript source code to execute. </param>
/// <returns> The result of executing the source code. </returns>
/// <exception cref="ArgumentNullException"> <paramref name="code"/> is a <c>null</c> reference. </exception>
public T Evaluate<T>(string code)
{
return TypeConverter.ConvertTo<T>(this, Evaluate(code));
}
To support returning an instance of a custom type Undefined
, we'd need INodeJSService.InvokeFrom*
methods without type parameters.
For example, at present, T InvokeFromString<T>
can only return an instance of type T
or default(T)
. So we'd need object InvokeFromString
which under the hood would return ExpandoObject
/null
/Undefined
.
Would that be enough? Anything I missed out?
For example, at present,
T InvokeFromString<T>
can only return an instance of typeT
ordefault(T)
.
For this case, you can implement the Undefined
type as a structure. Main thing is that the host has a type responsible for working with undefined
.
As an example of how I work with a Undefined
type, you can see the source code of V8JsEngine
class.
Thanks for the extra info
For this case, you can implement the Undefined type as a structure.
I'm not sure if I understood you right on this point.
I've looked through V8JsEngine
, T InnerEvaluate<T>
calls object InnerEvaluate
, then converts the result to an instance of type T
:
protected override T InnerEvaluate<T>(string expression, string documentName)
{
object result = InnerEvaluate(expression, documentName);
return TypeConverter.ConvertToType<T>(result);
}
It seems to me that T InnerEvaluate<T>
can only return T
or default(T)
, even if Undefined
is a struct.
Will this plan meet your needs?
Undefined
custom type, like Clearscripts:public class Undefined
{
internal static readonly Undefined Value = new Undefined();
private Undefined()
{
}
#region Object overrides
/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns>A string that represents the current object.</returns>
/// <remarks>
/// The <see cref="Undefined"/> version of this method returns "[undefined]".
/// </remarks>
public override string ToString()
{
return "[undefined]";
}
#endregion
}
Add object InvokeFrom*
methods to INodeJSService
. Under the hood they return ExpandoObject
/null
/Undefined
. Similar to Clearscript's evaluate methods - https://microsoft.github.io/ClearScript/Reference/html/M_Microsoft_ClearScript_ScriptEngine_Evaluate_1.htm.
Also, within the ExpandoObject
, any field that was undefined
in the Javascript result must be a reference to an instance of the Undefined
type.
I've looked through
V8JsEngine
,T InnerEvaluate<T>
calls objectInnerEvaluate
, then converts the result to an instance of typeT
:
Microsoft ClearScript.V8 always returns a value of object
type, therefore, in this case, the InnerEvaluate<T>
method is only responsible for casting to the specified type. In this case, you need to look at the object InnerEvaluate(string expression, string documentName)
method.
- Create an
Undefined
custom type, like Clearscripts:
The implementation details of this type are not particularly important to me. If a structure is more suitable for you, then implement this type as a structure.
Only two things are important to me:
undefined
.undefined
value on the host and pass it to your library.I.e. that there was an opportunity to create the MapToScriptType
and MapToHostType
methods.
- Add
object InvokeFrom*
methods toINodeJSService
.
Non-generic versions of the InvokeFrom*
methods would be very helpful.
Okay, I believe we're on the same page. This will be a useful addition for those who want to return dynamic objects. Will tag you when I create the PR!
OK.
Hello, Jeremy!
In Jering.Javascript.NodeJS values of
null
andundefined
types are always returned asnull
, that causes inconvenience. Most JS engines for .NET has a clearly separation fornull
andundefined
types. As a rule, to representundefined
in .NET is used a custom type (see as examples the ClearScript and Jurassic).