Javascript.NodeJS
Javascript.NodeJS copied to clipboard
Undefined type
Hello, Jeremy!
In Jering.Javascript.NodeJS values of null
and undefined
types are always returned as null
, that causes inconvenience. Most JS engines for .NET has a clearly separation for null
and undefined
types. As a rule, to represent undefined
in .NET is used a custom type (see as examples the ClearScript and Jurassic).
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
Invoke Methods with Generic Parameters
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.
Plan
Will this plan meet your needs?
- Create an
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 toINodeJSService
. Under the hood they returnExpandoObject
/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:
- I need to understand that the return value is
undefined
. - To be able to create a
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.