private JsObject EvaluateModuleInternal(string script, IBaristaModuleLoader moduleLoader = null)
        {
            var mainModule = m_moduleRecordFactory.CreateBaristaModuleRecord(this, "", null, true, moduleLoader);

            //Set the global value - this is akin to node.js's 'global' variable (https://nodejs.org/api/globals.html#globals_global)
            //It's preferable for barista not to use this, however, right now I don't see a way to actually 'Set' values dynamically in a module namespace
            Object.DefineProperty(GlobalObject, "global", new JsPropertyDescriptor()
            {
                Configurable = false, Enumerable = false, Writable = false, Value = GlobalObject
            });

            //Now start the parsing.
            try
            {
                //First, parse our main module script.
                mainModule.ParseModuleSource(script);

                //Now we're ready, evaluate the main module.
                Engine.JsModuleEvaluation(mainModule.Handle);

                //Evaluate any pending promises.
                CurrentScope.ResolvePendingPromises();

                //Retrieve the module namespace.
                var moduleNamespace = Engine.JsGetModuleNamespace(mainModule.Handle);

                //Return the module namespace as an object.
                return(new JsObject(Engine, this, moduleNamespace));
            }
            finally
            {
                mainModule.Dispose();
            }
        }
Exemple #2
0
        public BaristaModuleRecord(string name, JavaScriptValueSafeHandle moduleSpecifier, BaristaModuleRecord parentModule, IJavaScriptEngine engine, BaristaContext context, IBaristaModuleRecordFactory moduleRecordFactory, IBaristaModuleLoader moduleLoader, JavaScriptModuleRecord moduleRecord)
            : base(engine, moduleRecord)
        {
            m_name                = name ?? throw new ArgumentNullException(nameof(name));
            m_moduleSpecifier     = moduleSpecifier ?? throw new ArgumentNullException(nameof(moduleSpecifier));
            m_parentModule        = parentModule;
            m_context             = context ?? throw new ArgumentNullException(nameof(context));
            m_moduleRecordFactory = moduleRecordFactory ?? throw new ArgumentNullException(nameof(moduleRecordFactory));

            //Module loader is not required, but if not specified, imports will fail.
            m_moduleLoader = moduleLoader;

            //Associate functions that will handle module loading
            if (m_parentModule == null)
            {
                //Set the fetch module callback for the module.
                m_fetchImportedModuleCallbackHandle = InitFetchImportedModuleCallback(Handle);

                //Set the notify callback for the module.
                m_notifyCallbackHandle = InitNotifyModuleReadyCallback(Handle);
            }

            //Set the event that will be called prior to the engine collecting the context.
            JavaScriptObjectBeforeCollectCallback beforeCollectCallback = (IntPtr handle, IntPtr callbackState) =>
            {
                OnBeforeCollect(handle, callbackState);
            };

            m_beforeCollectCallbackDelegateHandle = GCHandle.Alloc(beforeCollectCallback);
            Engine.JsSetObjectBeforeCollectCallback(moduleRecord, IntPtr.Zero, beforeCollectCallback);
        }
        public IBaristaRuntimeFactory GetRuntimeFactory(IBaristaModuleLoader moduleLoader)
        {
            var serviceCollection = new ServiceCollection();

            serviceCollection.AddBaristaCore(moduleLoader: moduleLoader);

            var provider = serviceCollection.BuildServiceProvider();

            return(provider.GetRequiredService <IBaristaRuntimeFactory>());
        }
        /// <summary>
        /// Registers a module loader with the specified priority, optionally specifiying an initializer.
        /// </summary>
        /// <param name="priority"></param>
        /// <param name="moduleLoader"></param>
        /// <param name="moduleInitializer"></param>
        public void RegisterModuleLoader(IBaristaModuleLoader moduleLoader, int priority = 100, Func <string, int, IBaristaModuleLoader, Task <IBaristaModule> > moduleLoaderFactory = null)
        {
            if (moduleLoader == null)
            {
                throw new ArgumentNullException(nameof(moduleLoader));
            }

            if (moduleLoaderFactory == null)
            {
                moduleLoaderFactory = InitializeAndReturnModule;
            }

            m_moduleLoaders.Add(new ModuleLoaderRecord()
            {
                Priority            = priority,
                ModuleLoader        = moduleLoader,
                ModuleLoaderFactory = moduleLoaderFactory
            });
        }
Exemple #5
0
        /// <summary>
        /// Evaluates the specified script as a module, the default export will be the returned value.
        /// </summary>
        /// <param name="script">Script to evaluate.</param>
        /// <returns></returns>
        public JsValue EvaluateModule(string script, IBaristaModuleLoader moduleLoader = null)
        {
            //Create a scope if we're not currently in one.
            BaristaExecutionScope scope = null;

            if (!HasCurrentScope)
            {
                scope = Scope();
            }

            try
            {
                var globalName = EvaluateModuleInternal(script, moduleLoader);
                return(GlobalObject.GetProperty(globalName));
            }
            finally
            {
                if (scope != null)
                {
                    scope.Dispose();
                }
            }
        }
        /// <summary>
        /// Evaluates the specified script as a module, the default export will be the returned value.
        /// </summary>
        /// <param name="script">Script to evaluate.</param>
        /// <returns></returns>
        public T EvaluateModule <T>(string script, IBaristaModuleLoader moduleLoader = null)
            where T : JsValue
        {
            //Create a scope if we're not currently in one.
            BaristaExecutionScope scope = null;

            if (!HasCurrentScope)
            {
                scope = Scope();
            }

            try
            {
                var moduleNamespace = EvaluateModuleInternal(script, moduleLoader);
                return(moduleNamespace.GetProperty <T>("default"));
            }
            finally
            {
                if (scope != null)
                {
                    scope.Dispose();
                }
            }
        }
        /// <summary>
        /// Registers a module loader for the specified prefix, optionally specifiying an initializer.
        /// </summary>
        /// <param name="prefix"></param>
        /// <param name="moduleLoader"></param>
        /// <param name="moduleInitializer"></param>
        public void RegisterModuleLoader(string prefix, IBaristaModuleLoader moduleLoader, Func <string, string, IBaristaModuleLoader, Task <IBaristaModule> > moduleLoaderFactory = null)
        {
            if (string.IsNullOrWhiteSpace(prefix))
            {
                throw new ArgumentNullException(nameof(prefix));
            }

            if (m_moduleLoaders.ContainsKey(prefix))
            {
                throw new ArgumentException("A module loader with the specified prefix has already been registered.", nameof(prefix));
            }

            if (moduleLoader == null)
            {
                throw new ArgumentNullException(nameof(moduleLoader));
            }

            if (moduleLoaderFactory == null)
            {
                moduleLoaderFactory = InitializeAndReturnModule;
            }

            m_moduleLoaders.Add(prefix, new Tuple <IBaristaModuleLoader, Func <string, string, IBaristaModuleLoader, Task <IBaristaModule> > >(moduleLoader, moduleLoaderFactory));
        }
Exemple #8
0
        public static async Task Invoke(BrewOrder brewOrder, IBaristaRuntimeFactory baristaRuntimeFactory, IBaristaModuleLoader moduleLoader, Func <BaristaContext, JsValue, Task> processBrewResult)
        {
            //Brew:
            using (var rt = baristaRuntimeFactory.CreateRuntime())
                using (var ctx = rt.CreateContext())
                    using (var scope = ctx.Scope())
                    {
                        JsValue result = null;
                        switch (brewOrder.Language)
                        {
                        case ResourceKind.Tsx:
                        case ResourceKind.Jsx:
                            result = ctx.EvaluateTypeScriptModule(brewOrder.Code, moduleLoader, true);
                            break;

                        case ResourceKind.TypeScript:
                            result = ctx.EvaluateTypeScriptModule(brewOrder.Code, moduleLoader);
                            break;

                        case ResourceKind.Json:
                            result = ctx.JSON.Parse(ctx.CreateString(brewOrder.Code));
                            break;

                        case ResourceKind.JavaScript:
                            result = ctx.EvaluateModule(brewOrder.Code, moduleLoader);
                            break;
                        }

                        await processBrewResult?.Invoke(ctx, result);
                    }
        }
Exemple #9
0
        private string EvaluateModuleInternal(string script, IBaristaModuleLoader moduleLoader = null)
        {
            var subModuleId   = Guid.NewGuid();
            var subModuleName = subModuleId.ToString();

            //Define a shim script that will set a global to the result of the script run as a module.
            //This is because JsModuleEvaluation always returns undefined, and there is no other way
            //To obtain access to variables defined in the module's namespace.

            //If there is a promise task queue defined, have the script auto-resolve any promises.
            string mainModuleScript;

            if (m_promiseTaskQueue == null)
            {
                mainModuleScript = $@"
import child from '{subModuleName}';
global.$EXPORTS = child;
";
            }
            else
            {
                mainModuleScript = $@"
import child from '{subModuleName}';
(async () => await child)().then((result) => {{ global.$EXPORTS = result; }}, (reject) => {{ global.$ERROR = reject }});
";
            }

            var mainModule = m_moduleRecordFactory.CreateBaristaModuleRecord(this, "", null, true, moduleLoader);
            var subModule  = m_moduleRecordFactory.CreateBaristaModuleRecord(this, subModuleName, mainModule, false, moduleLoader);

            //Set the global value.
            Object.DefineProperty(GlobalObject, "global", new JsPropertyDescriptor()
            {
                Configurable = false, Enumerable = false, Writable = false, Value = GlobalObject
            });

            //Now start the parsing.
            try
            {
                //First, parse our main module script.
                mainModule.ParseModuleSource(mainModuleScript);

                //Now Parse the user-provided script.
                subModule.ParseModuleSource(script);

                //Now we're ready, evaluate the main module.
                Engine.JsModuleEvaluation(mainModule.Handle);

                //Evaluate any pending promises.
                CurrentScope.ResolvePendingPromises();

                if (m_promiseTaskQueue != null && GlobalObject.HasOwnProperty("$ERROR"))
                {
                    var errorValue = GlobalObject.GetProperty("$ERROR");
                    throw new JsScriptException(JsErrorCode.ScriptException, errorValue.Handle);
                }

                //Return the name of the global.
                return("$EXPORTS");
            }
            finally
            {
                mainModule.Dispose();
            }
        }
 /// <summary>
 /// Nominal implementation to retrieve a module.
 /// </summary>
 /// <param name="moduleName"></param>
 /// <param name="modulePriority"></param>
 /// <param name="moduleLoader"></param>
 /// <returns></returns>
 private Task <IBaristaModule> InitializeAndReturnModule(string moduleName, int modulePriority, IBaristaModuleLoader moduleLoader)
 {
     return(moduleLoader.GetModule(moduleName));
 }
        public static JsValue EvaluateTypeScriptModule(this BaristaContext context, string script, IBaristaModuleLoader moduleLoader = null, bool isTsx = false)
        {
            var transpileTask    = TypeScriptTranspiler.Default.Transpile(script, isTsx ? "main.tsx" : "main.ts");
            var transpilerOutput = transpileTask.GetAwaiter().GetResult();

            return(context.EvaluateModule(transpilerOutput.OutputText, moduleLoader));
        }
Exemple #12
0
        /// <summary>
        /// Register BaristaCore services with the specified ServiceCollection.
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddBaristaCore(this IServiceCollection services, IBaristaModuleLoader moduleLoader = null)
        {
            if (moduleLoader == null)
            {
                moduleLoader = new InMemoryModuleLoader();
            }

            services.AddSingleton <IJavaScriptEngineFactory, ChakraCoreFactory>();
            services.AddSingleton((provider) =>
            {
                var jsEngineFactory = provider.GetRequiredService <IJavaScriptEngineFactory>();
                return(jsEngineFactory.CreateJavaScriptEngine());
            });
            services.AddSingleton(moduleLoader);
            services.AddSingleton <IBaristaValueFactoryBuilder, BaristaValueFactoryBuilder>();
            services.AddSingleton <IBaristaRuntimeFactory, BaristaRuntimeFactory>();

            //Conversion strategies must be transient, as they create objects tied to the context.
            services.AddTransient <IBaristaConversionStrategy, BaristaConversionStrategy>();
            services.AddTransient <IBaristaTypeConversionStrategy, BaristaTypeConversionStrategy>();

            services.AddTransient <IBaristaContextFactory, BaristaContextFactory>();
            services.AddTransient <IBaristaModuleRecordFactory, BaristaModuleRecordFactory>();
            services.AddTransient <IPromiseTaskQueue, PromiseTaskQueue>();

            return(services);
        }
Exemple #13
0
        public HttpResponseMessage Brew(BrewOrder brewOrder, IBaristaRuntimeFactory baristaRuntimeFactory, IBaristaModuleLoader moduleLoader)
        {
            if (brewOrder == null)
            {
                throw new ArgumentNullException(nameof(brewOrder));
            }

            if (baristaRuntimeFactory == null)
            {
                throw new ArgumentNullException(nameof(baristaRuntimeFactory));
            }

            //Brew:
            HttpResponseMessage responseMessage = null;

            BrewMiddleware.Invoke(brewOrder, baristaRuntimeFactory, moduleLoader, (ctx, brewResult) =>
            {
                responseMessage = Serve(ctx, brewResult);
                return(Task.CompletedTask);
            }).GetAwaiter().GetResult();

            return(responseMessage);
        }
        private BaristaModuleRecord CreateBaristaModuleRecordInternal(BaristaContext context, string moduleName, JavaScriptValueSafeHandle specifier, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null)
        {
            JavaScriptModuleRecord moduleRecord = null;

            if (m_specifierModuleLookup.ContainsKey(specifier))
            {
                moduleRecord = m_specifierModuleLookup[specifier];
            }

            if (moduleRecord == null || moduleRecord.IsClosed || moduleRecord.IsInvalid)
            {
                if (m_specifierModuleLookup.ContainsKey(specifier))
                {
                    m_specifierModuleLookup.Remove(specifier);
                }

                moduleRecord = m_engine.JsInitializeModuleRecord(parentModule == null ? JavaScriptModuleRecord.Invalid : parentModule.Handle, specifier);
            }

            return(m_moduleReferencePool.GetOrAdd(moduleRecord, () =>
            {
                //If a module loader hasn't be specified in the parameters, obtain one from DI.
                if (moduleLoader == null)
                {
                    moduleLoader = m_serviceProvider.GetRequiredService <IBaristaModuleLoader>();
                }

                var module = new BaristaModuleRecord(moduleName.ToString(), specifier, parentModule, m_engine, context, this, moduleLoader, moduleRecord);
                m_specifierModuleLookup.Add(specifier, moduleRecord);

                //If specified, indicate as host module.
                if (setAsHost == true)
                {
                    m_engine.JsSetModuleHostInfo(moduleRecord, JavaScriptModuleHostInfoKind.HostDefined, specifier.DangerousGetHandle());
                }

                void beforeCollect(object sender, BaristaObjectBeforeCollectEventArgs args)
                {
                    context.BeforeCollect -= beforeCollect;
                    m_moduleReferencePool.RemoveHandle(new JavaScriptModuleRecord(args.Handle));
                    if (sender is BaristaModuleRecord baristaModuleRecord)
                    {
                        m_specifierModuleLookup.Remove(baristaModuleRecord.Specifier);
                    }
                }
                module.BeforeCollect += beforeCollect;
                return module;
            }));
        }
        public BaristaModuleRecord CreateBaristaModuleRecord(BaristaContext context, JavaScriptValueSafeHandle specifier, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (specifier == null || specifier.IsClosed || specifier.IsInvalid)
            {
                throw new ArgumentNullException(nameof(specifier));
            }

            var moduleNameValue = context.CreateValue <JsString>(specifier);

            if (moduleNameValue == null)
            {
                throw new InvalidOperationException("Specifier is expected to be a string value.");
            }

            return(CreateBaristaModuleRecordInternal(context, moduleNameValue.ToString(), specifier, parentModule, setAsHost, moduleLoader));
        }
        public BaristaModuleRecord CreateBaristaModuleRecord(BaristaContext context, string moduleName, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var moduleNameValue = context.CreateString(moduleName);

            return(CreateBaristaModuleRecordInternal(context, moduleName, moduleNameValue.Handle, parentModule, setAsHost, moduleLoader));
        }