I have a C# library. I am trying to write a nodejs addon using Microsoft.JavaScript.NodeApi. I have the following interface :
using ClassReflectionKit.Models;
namespace ClassReflectionKit.Helpers;
public interface IClassReflectionKitHelper
{
TemplateClassInfo? GetClassInfo(string ns, string className);
//TemplateClassInfo? GetClassInfo(string ns, string className, ProcessClassInfo procDelegate);
string[] GetNameSpaces();
IEnumerable<TemplateClassInfo> GetNSClasses(string ns);
IEnumerable<TemplateClassInfo> GetNSClasses(string ns, ProcessNSClasses procDelegate);
IEnumerable<TemplateClassInfo> GetNSClasses(string ns, ProcessNSClasses procDelegate, ProcessClassInfo procClassDelegate);
void InitializeFromCodeInputs(params string[] codeItems);
void InitializeFromFilePaths(params string[] filePaths);
bool IsCodeSnippetValid(string codeSnippet);
}
What it actually does, it to allow defining helper classes that can manipulate existing C# code and get metadata information.
I have a class that implements that interface
[JSExport]
public class ClassReflectionKitHelper : IClassReflectionKitHelper
{
private Dictionary<string, List<SyntaxTree>> NamespaceSyntaxTrees { get; set; } = new();
private SyntaxTree GetFileSyntaxTree(string filePath)
{
}
public void InitializeFromFilePaths(params string[] filePaths)
{
}
public void InitializeFromCodeInputs(params string[] codeItems)
{
}
public string[] GetNameSpaces()
{
}
public virtual TemplateClassInfo? GetClassInfo(string ns, string className)
{
}
public virtual TemplateClassInfo? GetClassInfo(string ns, string className, ProcessClassInfo procDelegate)
{
}
public virtual IEnumerable<TemplateClassInfo> GetNSClasses(string ns)
{
}
public virtual IEnumerable<TemplateClassInfo> GetNSClasses(string ns, ProcessNSClasses procDelegate)
{
}
public virtual IEnumerable<TemplateClassInfo> GetNSClasses(string ns, ProcessNSClasses procDelegate, ProcessClassInfo procClassDelegate)
{
}
bool IClassReflectionKitHelper.IsCodeSnippetValid(string codeSnippet)
{
}
}
(I have removed the actual implementation for my class and left just the schema)
So my Issue is this. Currently If i build the project , the typescript definitions for ClassReflectionKitHelper are correctly generated .
ProcessNSClasses and ProcessClassInfo are Delegates .
Here is their definition
namespace ClassReflectionKit.Models;
[JSExport("ProcessClassInfo")]
public delegate TemplateClassInfo? ProcessClassInfo(TemplateClassInfo? classInfo);
[JSExport("ProcessNSClasses")]
public delegate IEnumerable<TemplateClassInfo> ProcessNSClasses(IEnumerable<TemplateClassInfo> classes);
If I try to export the interface also using JSExport attribute I get the following error
ClassReflectionKit failed with 3 error(s) (0,8s)
Microsoft.JavaScript.NodeApi.Generator.ModuleGenerator\ClassReflectionKit.NodeApi.g.cs(693,80): error CS0103: The name 'from_ClassReflectionKit_Models_ProcessNSClasses' does not exist in the current context
Microsoft.JavaScript.NodeApi.Generator\Microsoft.JavaScript.NodeApi.Generator.ModuleGenerator\ClassReflectionKit.NodeApi.g.cs(706,80): error CS0103: The name 'from_ClassReflectionKit_Models_ProcessNSClasses' does not exist in the current context
error CS0103: The name 'from_ClassReflectionKit_Models_ProcessClassInfo' does not exist in the current context
Any ideas what am I missing ?
The root of the errors you’re seeing is that the Node-API code generator only knows how to emit marshaling support (the “from_” and “to_” helpers) for concrete types that it’s been told to export—and interfaces aren’t concrete, nor do they get their own generated glue code. In practice that means:
Don’t put [JSExport] on your interface.
Remove
[JSExport]
public interface IClassReflectionKitHelper { … }
The generator will never produce the necessary from_ClassReflectionKit_Models_ProcessNSClasses helpers for an interface.
Keep your delegates [JSExport]-ed and use them only on exported classes.
You already have this right:
namespace ClassReflectionKit.Models
{
[JSExport("ProcessClassInfo")]
public delegate TemplateClassInfo? ProcessClassInfo(TemplateClassInfo? classInfo);
[JSExport("ProcessNSClasses")]
public delegate IEnumerable<TemplateClassInfo> ProcessNSClasses(IEnumerable<TemplateClassInfo> classes);
}
Just make sure that both delegates actually appear as parameters or return types on your exported class.
Export only the concrete implementation
using Microsoft.JavaScript.NodeApi;
using ClassReflectionKit.Models;
[JSExport]
public class ClassReflectionKitHelper /*: IClassReflectionKitHelper — you can still implement the interface for your own code structure */
{
// … your existing implementation …
// Example exported methods that use your delegates:
[JSExport]
public TemplateClassInfo? GetClassInfo(string ns, string className)
=> /* … */;
[JSExport]
public TemplateClassInfo? GetClassInfo(string ns, string className, ProcessClassInfo proc)
=> proc(GetClassInfo(ns, className));
[JSExport]
public IEnumerable<TemplateClassInfo> GetNSClasses(string ns)
=> /* … */;
[JSExport]
public IEnumerable<TemplateClassInfo> GetNSClasses(string ns, ProcessNSClasses proc)
=> proc(GetNSClasses(ns));
// And so on…
}
By decorating only the class and its methods with [JSExport], and by using your delegates in those methods, the generator will emit the correct marshalling code (from_ProcessNSClasses, etc.) and you will avoid the “name ‘from_X’ does not exist” errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With