diff --git a/js/src/shell/ModuleLoader.js b/js/src/shell/ModuleLoader.js index 5246992c5644..2d770d233924 100644 --- a/js/src/shell/ModuleLoader.js +++ b/js/src/shell/ModuleLoader.js @@ -175,10 +175,11 @@ const ReflectLoader = new class { } }; +setModuleLoadHook((path) => ReflectLoader.importRoot(path)); + setModuleResolveHook((module, requestName) => { let path = ReflectLoader.resolve(requestName, module); return ReflectLoader.loadAndParse(path); }); -Reflect.Loader = ReflectLoader; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 99db98272dc9..30489654d3d0 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -134,7 +134,8 @@ enum JSShellExitCode { // Define use of application-specific slots on the shell's global object. enum GlobalAppSlot { - GlobalAppSlotModuleResolveHook, + GlobalAppSlotModuleLoadHook, // Shell-specific; load a module graph + GlobalAppSlotModuleResolveHook, // HostResolveImportedModule GlobalAppSlotCount }; static_assert(GlobalAppSlotCount <= JSCLASS_GLOBAL_APPLICATION_SLOTS, @@ -648,58 +649,33 @@ InitModuleLoader(JSContext* cx) } static bool -GetLoaderObject(JSContext* cx, MutableHandleObject resultOut) +GetModuleImportHook(JSContext* cx, MutableHandleFunction resultOut) { - // Look up the |Reflect.Loader| object that has been defined by the module - // loader. - - RootedObject object(cx, cx->global()); - RootedValue value(cx); - if (!JS_GetProperty(cx, object, "Reflect", &value) || !value.isObject()) - return false; - - object = &value.toObject(); - if (!JS_GetProperty(cx, object, "Loader", &value) || !value.isObject()) - return false; - - resultOut.set(&value.toObject()); - return true; -} - -static bool -GetImportRootMethod(JSContext* cx, HandleObject loader, MutableHandleFunction resultOut) -{ - // Look up the module loader's |importRoot| method. - - RootedValue value(cx); - if (!JS_GetProperty(cx, loader, "importRoot", &value) || !value.isObject()) + Handle global = cx->global(); + RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleLoadHook)); + if (hookValue.isUndefined()) { + JS_ReportErrorASCII(cx, "Module load hook not set"); return false; + } - RootedObject object(cx, &value.toObject()); - if (!object->is()) + if (!hookValue.isObject() || !hookValue.toObject().is()) { + JS_ReportErrorASCII(cx, "Module load hook is not a function"); return false; + } - resultOut.set(&object->as()); + resultOut.set(&hookValue.toObject().as()); return true; } static MOZ_MUST_USE bool RunModule(JSContext* cx, const char* filename, FILE* file, bool compileOnly) { - // Execute a module by calling Reflect.Loader.importRoot on the resolved - // filename. - - RootedObject loaderObj(cx); - if (!GetLoaderObject(cx, &loaderObj)) { - JS_ReportErrorASCII(cx, "Failed to get Reflect.Loader"); - return false; - } + // Execute a module by calling the module loader's import hook on the + // resolved filename. RootedFunction importFun(cx); - if (!GetImportRootMethod(cx, loaderObj, &importFun)) { - JS_ReportErrorASCII(cx, "Failed to get Reflect.Loader.importRoot method"); + if (!GetModuleImportHook(cx, &importFun)) return false; - } RootedString path(cx, JS_NewStringCopyZ(cx, filename)); if (!path) @@ -713,7 +689,7 @@ RunModule(JSContext* cx, const char* filename, FILE* file, bool compileOnly) args[0].setString(path); RootedValue value(cx); - return JS_CallFunction(cx, loaderObj, importFun, args, &value); + return JS_CallFunction(cx, nullptr, importFun, args, &value); } static bool @@ -3895,6 +3871,29 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +SetModuleLoadHook(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (args.length() != 1) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, + "setModuleLoadHook", "0", "s"); + return false; + } + + if (!args[0].isObject() || !args[0].toObject().is()) { + const char* typeName = InformalValueTypeName(args[0]); + JS_ReportErrorASCII(cx, "expected hook function, got %s", typeName); + return false; + } + + Handle global = cx->global(); + global->setReservedSlot(GlobalAppSlotModuleLoadHook, args[0]); + + args.rval().setUndefined(); + return true; +} + static bool SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp) { @@ -6098,6 +6097,12 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "parseModule(code)", " Parses source text as a module and returns a Module object."), + JS_FN_HELP("setModuleLoadHook", SetModuleLoadHook, 1, 0, +"setModuleLoadHook(function(path))", +" Set the shell specific module load hook to |function|.\n" +" This hook is used to load a module graph. It should be implemented by the\n" +" module loader."), + JS_FN_HELP("setModuleResolveHook", SetModuleResolveHook, 1, 0, "setModuleResolveHook(function(module, specifier) {})", " Set the HostResolveImportedModule hook to |function|.\n"