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(); } }
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 }); }
/// <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)); }
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); } }
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)); }
/// <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); }
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)); }