示例#1
0
        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();
                }
            }
        }