mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 03:06:29 +00:00
Support dynamic import
The static `import` should be prefered over the dynamic but it might be usefull when loading an object from a json file.
This commit is contained in:
@@ -65,6 +65,18 @@ namespace
|
||||
return std::get<1>(*std::get<0>(insertResult)).m_ModuleObject;
|
||||
}
|
||||
|
||||
[[nodiscard]] JSObject* Resolve(const ScriptRequest& rq,
|
||||
ModuleLoader::RegistryType& registry, JS::HandleObject moduleRequest)
|
||||
{
|
||||
std::string includeString;
|
||||
const JS::RootedValue pathValue{rq.cx,
|
||||
JS::StringValue(JS::GetModuleRequestSpecifier(rq.cx, moduleRequest))};
|
||||
if (!Script::FromJSVal(rq, pathValue, includeString))
|
||||
throw std::logic_error{"The module-name to import isn't a string."};
|
||||
|
||||
return CompileModule(rq, registry, includeString);
|
||||
}
|
||||
|
||||
[[nodiscard]] JSObject* Evaluate(const ScriptRequest& rq, JS::HandleObject mod)
|
||||
{
|
||||
if (!JS::ModuleLink(rq.cx, mod))
|
||||
@@ -230,13 +242,7 @@ void ModuleLoader::Future::SetReservedSlot(JS::Value privateValue) noexcept
|
||||
try
|
||||
{
|
||||
const ScriptRequest rq{cx};
|
||||
std::string includeString;
|
||||
const JS::RootedValue pathValue{rq.cx,
|
||||
JS::StringValue(JS::GetModuleRequestSpecifier(rq.cx, moduleRequest))};
|
||||
if (!Script::FromJSVal(rq, pathValue, includeString))
|
||||
throw std::logic_error{"The module-name to import isn't a string."};
|
||||
|
||||
return CompileModule(rq, rq.GetScriptInterface().GetModuleLoader().m_Registry, includeString);
|
||||
return Resolve(rq, rq.GetScriptInterface().GetModuleLoader().m_Registry, moduleRequest);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@@ -249,4 +255,29 @@ void ModuleLoader::Future::SetReservedSlot(JS::Value privateValue) noexcept
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool ModuleLoader::DynamicImportHook(JSContext* cx, JS::HandleValue referencingPrivate,
|
||||
JS::HandleObject moduleRequest, JS::HandleObject promise) noexcept
|
||||
{
|
||||
const ScriptRequest rq{cx};
|
||||
try
|
||||
{
|
||||
JS::RootedObject mod{rq.cx, Resolve(rq, rq.GetScriptInterface().GetModuleLoader().m_Registry,
|
||||
moduleRequest)};
|
||||
JS::RootedObject evaluationPromise{rq.cx, Evaluate(rq, mod)};
|
||||
return JS::FinishDynamicModuleImport(rq.cx, evaluationPromise, referencingPrivate,
|
||||
moduleRequest, promise);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOGERROR("%s", e.what());
|
||||
return JS::FinishDynamicModuleImport(rq.cx, nullptr, referencingPrivate, moduleRequest,
|
||||
promise);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return JS::FinishDynamicModuleImport(rq.cx, nullptr, referencingPrivate, moduleRequest,
|
||||
promise);
|
||||
}
|
||||
}
|
||||
} // namespace Script
|
||||
|
||||
@@ -102,6 +102,8 @@ private:
|
||||
// Functions used by the `ScriptContext`.
|
||||
[[nodiscard]] static JSObject* ResolveHook(JSContext* cx, JS::HandleValue,
|
||||
JS::HandleObject moduleRequest) noexcept;
|
||||
[[nodiscard]] static bool DynamicImportHook(JSContext* cx, JS::HandleValue referencingPrivate,
|
||||
JS::HandleObject moduleRequest, JS::HandleObject promise) noexcept;
|
||||
|
||||
RegistryType m_Registry;
|
||||
};
|
||||
|
||||
@@ -154,14 +154,18 @@ ScriptContext::ScriptContext(int contextSize, uint32_t heapGrowthBytesGCTrigger)
|
||||
JS::SetJobQueue(m_cx, m_JobQueue.get());
|
||||
JS::SetPromiseRejectionTrackerCallback(m_cx, &Script::UnhandledRejectedPromise);
|
||||
|
||||
JS::SetModuleResolveHook(JS_GetRuntime(m_cx), &Script::ModuleLoader::ResolveHook);
|
||||
JSRuntime* runtime{JS_GetRuntime(m_cx)};
|
||||
JS::SetModuleResolveHook(runtime, &Script::ModuleLoader::ResolveHook);
|
||||
JS::SetModuleDynamicImportHook(runtime, &Script::ModuleLoader::DynamicImportHook);
|
||||
}
|
||||
|
||||
ScriptContext::~ScriptContext()
|
||||
{
|
||||
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initialized and not yet shut down) when destroying a ScriptContext!");
|
||||
|
||||
JS::SetModuleResolveHook(JS_GetRuntime(m_cx), nullptr);
|
||||
JSRuntime* runtime{JS_GetRuntime(m_cx)};
|
||||
JS::SetModuleDynamicImportHook(runtime, nullptr);
|
||||
JS::SetModuleResolveHook(runtime, nullptr);
|
||||
|
||||
// Switch back to normal performance mode to avoid assertion in debug mode.
|
||||
js::gc::SetPerformanceHint(m_cx, js::gc::PerformanceHint::Normal);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "scriptinterface/FunctionWrapper.h"
|
||||
#include "scriptinterface/ModuleLoader.h"
|
||||
#include "scriptinterface/Object.h"
|
||||
#include "scriptinterface/Promises.h"
|
||||
#include "scriptinterface/ScriptContext.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
@@ -369,4 +370,35 @@ public:
|
||||
TS_ASSERT(Script::GetProperty(rq, moduleValue, "value", value));
|
||||
TS_ASSERT_EQUALS(value, 6);
|
||||
}
|
||||
|
||||
void test_DynamicImport()
|
||||
{
|
||||
ScriptInterface script{"Test", "Test", g_ScriptContext};
|
||||
const ScriptRequest rq{script};
|
||||
|
||||
auto future = script.GetModuleLoader().LoadModule(rq, "dynamic_import.js");
|
||||
|
||||
g_ScriptContext->RunJobs();
|
||||
|
||||
JS::RootedObject ns{rq.cx, future.Get()};
|
||||
JS::RootedValue moduleValue{rq.cx, JS::ObjectValue(*ns)};
|
||||
|
||||
JS::RootedValue promise{rq.cx};
|
||||
TS_ASSERT(ScriptFunction::Call(rq, moduleValue, "default", &promise));
|
||||
TS_ASSERT(promise.isObject());
|
||||
JS::RootedObject promiseObject{rq.cx, &promise.toObject()};
|
||||
TS_ASSERT(JS::IsPromiseObject(promiseObject));
|
||||
|
||||
TS_ASSERT_EQUALS(JS::GetPromiseState(promiseObject), JS::PromiseState::Pending);
|
||||
g_ScriptContext->RunJobs();
|
||||
TS_ASSERT_EQUALS(JS::GetPromiseState(promiseObject), JS::PromiseState::Fulfilled);
|
||||
|
||||
JS::RootedValue piModule{rq.cx, JS::GetPromiseResult(promiseObject)};
|
||||
|
||||
double pi{0.0};
|
||||
TS_ASSERT(Script::FromJSProperty(rq, piModule, "default", pi));
|
||||
|
||||
TS_ASSERT_LESS_THAN(pi, 3.1416);
|
||||
TS_ASSERT_LESS_THAN(3.1415, pi);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user