summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2022-01-19 10:26:38 +0100
committerLinus Groh <mail@linusgroh.de>2022-01-22 01:21:18 +0000
commit986ad3ccf0c7135ac82d25c17c560250dd0f79dd (patch)
treefcde491f322fc04955b51770be8e26e0349d1d34 /Userland/Libraries
parent91b3e5b31f3da01fad73c94a281fe926a2ae890c (diff)
downloadserenity-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')
-rw-r--r--Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp30
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/ShadowRealm.prototype.importValue.js52
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/async-module.mjs11
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/ShadowRealm/external-module.mjs5
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";