diff options
author | davidot <davidot@serenityos.org> | 2022-01-19 10:26:38 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-01-22 01:21:18 +0000 |
commit | 986ad3ccf0c7135ac82d25c17c560250dd0f79dd (patch) | |
tree | fcde491f322fc04955b51770be8e26e0349d1d34 /Userland/Libraries | |
parent | 91b3e5b31f3da01fad73c94a281fe926a2ae890c (diff) | |
download | serenity-986ad3ccf0c7135ac82d25c17c560250dd0f79dd.zip |
LibJS: Use HostImportModuleDynamically in ShadowRealmImportValue
Now that module loading is implemented this just works :^).
Since ShadowRealm explicitly passed a null ScriptOrModule we attempt to
get the top most ScriptOrModule in HostImportModuleDynamically.
This won't work in general as the web specifies other behavior but for
LibJS there must always be an active script to call
HostImportModuleDynamically.
Diffstat (limited to 'Userland/Libraries')
4 files changed, 69 insertions, 29 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp index ed9086a572..fc21f4bb17 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp @@ -8,6 +8,7 @@ #include <LibJS/Parser.h> #include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/DeclarativeEnvironment.h> +#include <LibJS/Runtime/ModuleNamespaceObject.h> #include <LibJS/Runtime/NativeFunction.h> #include <LibJS/Runtime/PromiseConstructor.h> #include <LibJS/Runtime/PromiseReaction.h> @@ -164,32 +165,7 @@ ThrowCompletionOr<Value> shadow_realm_import_value(GlobalObject& global_object, TRY(vm.push_execution_context(eval_context, eval_realm.global_object())); // 10. Perform ! HostImportModuleDynamically(null, specifierString, innerCapability). - // FIXME: We don't have this yet. We generally have very little support for modules and imports. - // So, in the meantime we just do the "Failure path" step, and pretend to call FinishDynamicImport - // with the rejected promise. This should be easy to complete once those missing module AOs are added. - - // HostImportModuleDynamically: At some future time, the host environment must perform - // FinishDynamicImport(referencingScriptOrModule, specifier, promiseCapability, promise), - // where promise is a Promise rejected with an error representing the cause of failure. - auto* promise = Promise::create(global_object); - promise->reject(Error::create(global_object, String::formatted("Import of '{}' from '{}' failed", export_name_string, specifier_string))); - - // FinishDynamicImport, 5. Perform ! PerformPromiseThen(innerPromise, onFulfilled, onRejected). - promise->perform_then( - NativeFunction::create(global_object, "", [](auto&, auto&) -> ThrowCompletionOr<Value> { - // Not called because we hardcoded a rejection above. - TODO(); - }), - NativeFunction::create(global_object, "", [reject = make_handle(inner_capability.reject)](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> { - auto error = vm.argument(0); - - // a. Perform ! Call(promiseCapability.[[Reject]], undefined, ยซ error ยป). - MUST(call(global_object, reject.cell(), js_undefined(), error)); - - // b. Return undefined. - return js_undefined(); - }), - {}); + vm.host_import_module_dynamically(Empty {}, ModuleRequest { move(specifier_string) }, inner_capability); // 11. Suspend evalContext and remove it from the execution context stack. // NOTE: We don't support this concept yet. @@ -208,7 +184,9 @@ ThrowCompletionOr<Value> shadow_realm_import_value(GlobalObject& global_object, "", [string = move(export_name_string)](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> { // 1. Assert: exports is a module namespace exotic object. + VERIFY(vm.argument(0).is_object()); auto& exports = vm.argument(0).as_object(); + VERIFY(is<ModuleNamespaceObject>(exports)); // 2. Let f be the active function object. auto* function = vm.running_execution_context().function; diff --git a/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/ShadowRealm.prototype.importValue.js b/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/ShadowRealm.prototype.importValue.js index d79c9bc1b7..8b1efef9f2 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/ShadowRealm.prototype.importValue.js +++ b/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/ShadowRealm.prototype.importValue.js @@ -3,10 +3,10 @@ describe("normal behavior", () => { expect(ShadowRealm.prototype.importValue).toHaveLength(2); }); - test("basic functionality", () => { + test("fails if module cannot be loaded", () => { // NOTE: The actual import is currently not implemented and always pretends to fail for now. const shadowRealm = new ShadowRealm(); - const promise = shadowRealm.importValue("./myModule.js", "foo"); + const promise = shadowRealm.importValue("./file_should_not_exist.js", "foo"); let error; promise.catch(value => { error = value; @@ -14,7 +14,53 @@ describe("normal behavior", () => { expect(promise).toBeInstanceOf(Promise); runQueuedPromiseJobs(); expect(error).toBeInstanceOf(TypeError); - expect(error.message).toBe("Import of 'foo' from './myModule.js' failed"); + expect(error.message).toBe("Cannot find/open module: './file_should_not_exist.js'"); + }); + + test("basic functionality", () => { + const shadowRealm = new ShadowRealm(); + const promise = shadowRealm.importValue("./external-module.mjs", "foo"); + expect(promise).toBeInstanceOf(Promise); + let error = null; + let passed = false; + promise + .then(value => { + expect(value).toBe("Well hello shadows"); + expect(typeof value).toBe("string"); + + expect(value).not.toHaveProperty("default", null); + expect(value).not.toHaveProperty("bar", null); + passed = true; + }) + .catch(value => { + error = value; + }); + runQueuedPromiseJobs(); + expect(error).toBeNull(); + expect(passed).toBeTrue(); + }); + + test("value from async module", () => { + const shadowRealm = new ShadowRealm(); + const promise = shadowRealm.importValue("./async-module.mjs", "foo"); + expect(promise).toBeInstanceOf(Promise); + let error = null; + let passed = false; + promise + .then(value => { + expect(value).toBe("Well hello async shadows"); + expect(typeof value).toBe("string"); + + expect(value).not.toHaveProperty("default", null); + expect(value).not.toHaveProperty("bar", null); + passed = true; + }) + .catch(value => { + error = value; + }); + runQueuedPromiseJobs(); + expect(error).toBeNull(); + expect(passed).toBeTrue(); }); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/async-module.mjs b/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/async-module.mjs new file mode 100644 index 0000000000..a95ab095aa --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/async-module.mjs @@ -0,0 +1,11 @@ +await Promise.resolve(0); + +export const foo = "Well hello async shadows"; + +await 1; + +export default "Default export"; + +await Promise.resolve(2); + +export const bar = "'bar' export"; diff --git a/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/external-module.mjs b/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/external-module.mjs new file mode 100644 index 0000000000..faa59c3841 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/external-module.mjs @@ -0,0 +1,5 @@ +export const foo = "Well hello shadows"; + +export default "Default export"; + +export const bar = "'bar' export"; |