Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsFunction set as property on JsObject is undefined when introspecting, but callable #59

Open
JesperTreetop opened this issue Mar 9, 2018 · 2 comments

Comments

@JesperTreetop
Copy link

I'm trying to get started with BaristaCore and it is a bumpy ride due to the lack of documentation. I could file a few issues, but I'm starting with this.

I created a new .NET Core 2.0 command line project, added the reference to the BaristaCore package (version 1.0.2-beta03) and used the following:

using System;
using BaristaLabs.BaristaCore;
using BaristaLabs.BaristaCore.Extensions;
using BaristaLabs.BaristaCore.ModuleLoaders;
using Microsoft.Extensions.DependencyInjection;

namespace TestBaristaRepro
{
    class Program
    {
        static void Main(string[] args)
        {
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddBaristaCore();
            var moduleLoader = new InMemoryModuleLoader();
            moduleLoader.RegisterModule(new Test1Module());
            moduleLoader.RegisterModule(new Test2Module());
            serviceCollection.AddSingleton<IBaristaModuleLoader>(moduleLoader);

            var provider = serviceCollection.BuildServiceProvider();
            var baristaRuntimeFactory = provider.GetRequiredService<IBaristaRuntimeFactory>();

            using (var rt = baristaRuntimeFactory.CreateRuntime())
            using (var ctx = rt.CreateContext()) {
                var script = @"var objs = [{ name: 'm1', obj: m1 }, { name: 'm2', obj: m2 }];

var summary = """";
summary += ""result of manually running m1.test(1, 2): "" + m1.test(1, 2) + ""\n"";
//summary += ""result of manually running m2.test(1, 2): "" + m2.test(1, 2) + ""\n"";
for (let obj of objs) {
    var x = obj.obj;
    var name = obj.name;
    summary += ""#"" + name + ""#\n"" + ""= (toString: "" + (x === null ? ""NULL"" : (x === undefined ? ""UNDEFINED"" : ""'"" + x.toString() + ""'"")) + "" (JSON: "" + JSON.stringify(x) + "")\n"";
    for (var key in x) {
        summary += ""  "" + key + "": "" + global[key] + ""\n"";
    }
}
return summary;";

                using (ctx.Scope()) {
                    var moduleResult = ctx.EvaluateModule("import m1 from 'first-module'; import m2 from 'second-module'; export default function() {" + script + "}");
                    if (moduleResult is JsFunction fun) {
                        var resultOfCalling = fun.Call();
                        if (resultOfCalling is JsString str) {
                            var res = str.ToString();
                            Console.WriteLine("result is: ");
                            Console.WriteLine(res);
                        }
                    }
                }
            }

        }

        [BaristaModule("first-module", "Module one")]
        public class Test1Module : IBaristaModule
        {
            public JsValue ExportDefault(BaristaContext context, BaristaModuleRecord referencingModule) {
                var obj = context.CreateObject();
                var fnAdd = context.CreateFunction(new Func<JsObject, int, int, int>((thisObj, a, b) =>
                {
                    return a + b;
                }));
                obj.SetProperty("test", fnAdd);
                return obj;
            }
        }

        [BaristaModule("second-module", "Module two")]
        public class Test2Module : IBaristaModule
        {
            public JsValue ExportDefault(BaristaContext context, BaristaModuleRecord referencingModule) {
                return context.CreateExternalObject(new Test2());
            }
        }

        [BaristaObject("test2")]
        public class Test2 {
            [BaristaProperty("test", Configurable = false, Enumerable = true)]
            public int Test(int a, int b) {
                return a + b;
            }
        }
    }
}

This uses two different modules to make two different functions available. The code outputs the following:

result is:
result of manually running m1.test(1, 2): 3
#m1#
= (toString: '[object Object]' (JSON: {})
  test: undefined
#m2#
= (toString: '[object Object]' (JSON: {})

In other words, on the first module, test is callable, and it is visible as a property (so enumerable), but its value is undefined instead of a function. On the second module, test is neither callable nor visible.

So the question being: is there a way for the real value to be visible in case of the first module, and what do I need to do to make the second module work?

(Additionally, outside the scope of this issue, some background: I am trying to use BaristaCore to provide Javascript execution to make a small piece of business logic an interchangeable script. It would have a number of either modules or objects available that would return domain-specific information or allow it to perform the purpose of the script.

I try to follow along as well as I can in how to put this together, but the documentation is slim and differs from the code (in the documentation, the IBaristaModule interface is asynchronous and in the code it's not, and I don't even know which behavior is the outdated one and will be going away). I have been working with Jurassic previously and am weighing BaristaCore and using the C# wrappers for ChakraCore directly.

I don't quite understand how you're meant to just evaluate code without wrapping it inside a module which exports a default function that you then call. That you had to use Scope() took a while to figure out as well.)

@JesperTreetop
Copy link
Author

I am sorry, I am a complete idiot - I forgot to change one variable of my test script - global[key] instead of x[key] will of course not return anything. (Welcome to JavaScript! 😅)

So the issue as defined is invalid, but I wouldn't mind your thoughts on the other things mentioned, like the second module.

@Oceanswave
Copy link
Member

Oceanswave commented May 11, 2018

Sorry for the lack of response -- on a bit of a hiatus from this project until .net core 2.1 and ChakraCore 1.9.x is released in order to get some of the improvements in runtime performance out of both those platforms.

I think the difference in the 2nd module is that you're returning a JsObject that has a function property named 'test' that the code isn't calling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants