public void JsModuleCanBeImportedAndExecuted() { var mainModuleName = ""; var mainModuleSource = @" import cube from 'foo'; const global = (new Function('return this;'))(); global.$EXPORTS = cube(3); "; var fooModuleSource = @" export default function cube(x) { return x * x * x; } "; var mainModuleReady = false; JavaScriptModuleRecord childModuleHandle = JavaScriptModuleRecord.Invalid; JavaScriptFetchImportedModuleCallback fetchCallback = (IntPtr referencingModule, IntPtr specifier, out IntPtr dependentModuleRecord) => { var moduleName = Engine.GetStringUtf8(new JavaScriptValueSafeHandle(specifier)); if (string.IsNullOrWhiteSpace(moduleName)) { dependentModuleRecord = referencingModule; return(false); } Assert.True(moduleName == "foo"); var moduleRecord = Engine.JsInitializeModuleRecord(new JavaScriptModuleRecord(referencingModule), new JavaScriptValueSafeHandle(specifier)); dependentModuleRecord = moduleRecord.DangerousGetHandle(); childModuleHandle = moduleRecord; return(false); }; JavaScriptFetchImportedModuleFromScriptCallback fetchFromScriptCallback = (IntPtr referencingModule, IntPtr specifier, out IntPtr dependentModuleRecord) => { var moduleName = Engine.GetStringUtf8(new JavaScriptValueSafeHandle(specifier)); if (string.IsNullOrWhiteSpace(moduleName)) { dependentModuleRecord = referencingModule; return(false); } Assert.True(moduleName == "foo"); var moduleRecord = Engine.JsInitializeModuleRecord(new JavaScriptModuleRecord(referencingModule), new JavaScriptValueSafeHandle((IntPtr)specifier)); dependentModuleRecord = moduleRecord.DangerousGetHandle(); childModuleHandle = moduleRecord; return(false); }; JavaScriptNotifyModuleReadyCallback notifyCallback = (IntPtr referencingModule, IntPtr exceptionVar) => { Assert.Equal(IntPtr.Zero, exceptionVar); mainModuleReady = true; return(false); }; using (var runtimeHandle = Engine.JsCreateRuntime(JavaScriptRuntimeAttributes.None, null)) { using (var contextHandle = Engine.JsCreateContext(runtimeHandle)) { Engine.JsSetCurrentContext(contextHandle); //Initialize the "main" module (Empty-string specifier). var moduleNameHandle = Engine.JsCreateString(mainModuleName, (ulong)mainModuleName.Length); var mainModuleHandle = Engine.JsInitializeModuleRecord(JavaScriptModuleRecord.Invalid, moduleNameHandle); Assert.True(mainModuleHandle != JavaScriptModuleRecord.Invalid); //Set the fetch callback. var fetchCallbackDelegateHandle = GCHandle.Alloc(fetchCallback); IntPtr fetchCallbackPtr = Marshal.GetFunctionPointerForDelegate(fetchCallback); Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.FetchImportedModuleCallback, fetchCallbackPtr); //Ensure the callback was set properly. var moduleHostPtr = Engine.JsGetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.FetchImportedModuleCallback); Assert.Equal(fetchCallbackPtr, moduleHostPtr); //Set the fetchScript callback var fetchFromScriptCallbackDelegateHandle = GCHandle.Alloc(fetchCallback); IntPtr fetchFromScriptCallbackPtr = Marshal.GetFunctionPointerForDelegate(fetchFromScriptCallback); Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.FetchImportedModuleFromScriptCallback, fetchFromScriptCallbackPtr); //Ensure the callback was set properly. moduleHostPtr = Engine.JsGetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.FetchImportedModuleFromScriptCallback); Assert.Equal(fetchFromScriptCallbackPtr, moduleHostPtr); //Set the notify callback var notifyCallbackDelegateHandle = GCHandle.Alloc(fetchCallback); IntPtr notifyCallbackPtr = Marshal.GetFunctionPointerForDelegate(notifyCallback); Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.NotifyModuleReadyCallback, notifyCallbackPtr); //Ensure the callback was set properly. moduleHostPtr = Engine.JsGetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.NotifyModuleReadyCallback); Assert.Equal(notifyCallbackPtr, moduleHostPtr); //Indicate the host-defined, main module. Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.HostDefined, moduleNameHandle.DangerousGetHandle()); //Ensure the callback was set properly. moduleHostPtr = Engine.JsGetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.HostDefined); Assert.Equal(moduleNameHandle.DangerousGetHandle(), moduleHostPtr); // ParseModuleSource is sync, while additional fetch & evaluation are async. var scriptBuffer = Encoding.UTF8.GetBytes(mainModuleSource); var errorHandle = Engine.JsParseModuleSource(mainModuleHandle, JavaScriptSourceContext.GetNextSourceContext(), scriptBuffer, (uint)mainModuleSource.Length, JavaScriptParseModuleSourceFlags.DataIsUTF8); Assert.True(errorHandle == JavaScriptValueSafeHandle.Invalid); Assert.True(childModuleHandle != JavaScriptModuleRecord.Invalid); Assert.False(mainModuleReady); //Parse the foo now. scriptBuffer = Encoding.UTF8.GetBytes(fooModuleSource); errorHandle = Engine.JsParseModuleSource(childModuleHandle, JavaScriptSourceContext.GetNextSourceContext(), scriptBuffer, (uint)fooModuleSource.Length, JavaScriptParseModuleSourceFlags.DataIsUTF8); Assert.True(errorHandle == JavaScriptValueSafeHandle.Invalid); Assert.True(mainModuleReady); //Now we're ready, evaluate the main module. var evalResultHandle = Engine.JsModuleEvaluation(mainModuleHandle); Assert.True(evalResultHandle != JavaScriptValueSafeHandle.Invalid); //Result type of a module is always undefined per spec. var evalResultType = Engine.JsGetValueType(evalResultHandle); Assert.True(evalResultType == JsValueType.Undefined); var resultHandle = Engine.GetGlobalVariable("$EXPORTS"); var handleType = Engine.JsGetValueType(resultHandle); Assert.True(handleType == JsValueType.Number); var result = Engine.JsNumberToInt(resultHandle); Assert.Equal(27, result); //Cleanup Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.FetchImportedModuleCallback, IntPtr.Zero); fetchCallbackDelegateHandle.Free(); Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.FetchImportedModuleFromScriptCallback, IntPtr.Zero); fetchFromScriptCallbackDelegateHandle.Free(); Engine.JsSetModuleHostInfo(mainModuleHandle, JavaScriptModuleHostInfoKind.NotifyModuleReadyCallback, IntPtr.Zero); notifyCallbackDelegateHandle.Free(); } } }