@@ -1058,12 +1058,13 @@ template <class Num>
10581058 requires std::is_integral_v<Num>
10591059struct value_trans <Num> {
10601060 static Value from (JSContext* ctx, Num value) noexcept {
1061- if constexpr (std::is_unsigned_v<Num> && sizeof (Num) <= sizeof (uint32_t )) {
1062- return Value{ctx, JS_NewUint32 (ctx, static_cast <uint32_t >(value))};
1063- } else if constexpr (std::is_signed_v<Num>) {
1064- return Value{ctx, JS_NewInt64 (ctx, static_cast <int64_t >(value))};
1061+ static_assert (sizeof (Num) <= sizeof (uint64_t ),
1062+ " Integral type is too large to be represented in JavaScript" );
1063+
1064+ if constexpr (std::is_unsigned_v<Num>) {
1065+ return Value{ctx, JS_NewUint64 (ctx, static_cast <uint64_t >(value))};
10651066 } else {
1066- static_assert (kota::dependent_false<Num>, " Unsupported integral type for value" ) ;
1067+ return Value{ctx, JS_NewInt64 (ctx, static_cast < int64_t >( value))} ;
10671068 }
10681069 }
10691070
@@ -1416,15 +1417,50 @@ class Context {
14161417 Value eval (std::string_view input, const char * filename, int eval_flags) const ;
14171418
14181419 /* *
1419- * Evaluate a JavaScript module, it will automatically add flag JS_EVAL_TYPE_MODULE to
1420- * eval_flags.
1420+ * Evaluate a strict-mode classic script synchronously in this context's global scope.
1421+ * The returned value is the script's completion value.
1422+ */
1423+ Value eval_script (const char * input, size_t input_len, const char * filename) const {
1424+ return this ->eval (input, input_len, filename, JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRICT );
1425+ }
1426+
1427+ /* * String-view overload of eval_script(). */
1428+ Value eval_script (std::string_view input, const char * filename) const {
1429+ return this ->eval_script (input.data (), input.size (), filename);
1430+ }
1431+
1432+ /* *
1433+ * Evaluate a strict-mode classic script with top-level await support.
1434+ * The returned promise settles when the script and all of its top-level awaits complete.
1435+ */
1436+ Promise async_eval_script (const char * input, size_t input_len, const char * filename) const {
1437+ return this
1438+ ->eval (input,
1439+ input_len,
1440+ filename,
1441+ JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_ASYNC | JS_EVAL_FLAG_STRICT )
1442+ .as <Promise>();
1443+ }
1444+
1445+ /* * String-view overload of async_eval_script(). */
1446+ Promise async_eval_script (std::string_view input, const char * filename) const {
1447+ return this ->async_eval_script (input.data (), input.size (), filename);
1448+ }
1449+
1450+ /* *
1451+ * Evaluate a strict-mode ECMAScript module.
1452+ * Imports are resolved through the Runtime module loader, and the returned promise settles
1453+ * after module evaluation, including top-level awaits, has completed.
14211454 */
1422- Promise eval_module (const char * input,
1423- size_t input_len,
1424- const char * filename,
1425- int eval_flags) const ;
1455+ Promise eval_module (const char * input, size_t input_len, const char * filename) const {
1456+ return this -> eval (input, input_len, filename, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_STRICT )
1457+ . as <Promise>();
1458+ }
14261459
1427- Promise eval_module (std::string_view input, const char * filename, int eval_flags) const ;
1460+ /* * String-view overload of eval_module(). */
1461+ Promise eval_module (std::string_view input, const char * filename) const {
1462+ return this ->eval_module (input.data (), input.size (), filename);
1463+ }
14281464
14291465 Object global_this () const noexcept ;
14301466
@@ -1480,6 +1516,17 @@ class Runtime {
14801516 Runtime& operator = (Runtime&&) = default ;
14811517 ~Runtime () = default ;
14821518
1519+ /* * Callbacks used to resolve and load JavaScript source modules. */
1520+ struct ModuleLoader {
1521+ /* * Resolve module_name relative to referrer_name and return its canonical module name. */
1522+ virtual std::string normalizer (const char * referrer_name, const char * module_name) = 0;
1523+
1524+ /* * Return the JavaScript source bytes for a canonical module name. */
1525+ virtual std::string loader (const char * module_name) = 0;
1526+
1527+ virtual ~ModuleLoader () = default ;
1528+ };
1529+
14831530 static Runtime create ();
14841531
14851532 // Get or create a context with the given name
@@ -1488,6 +1535,61 @@ class Runtime {
14881535
14891536 JSRuntime* js_runtime () const noexcept ;
14901537
1538+ /* *
1539+ * Install or replace this runtime's JavaScript module loader.
1540+ * The callbacks are retained by the runtime and used by subsequent module evaluations.
1541+ */
1542+ void set_module_loader (std::unique_ptr<ModuleLoader> loader) const noexcept {
1543+ this ->raw ->module_loader = std::move (loader);
1544+
1545+ return JS_SetModuleLoaderFunc (
1546+ this ->js_runtime (),
1547+ [](JSContext* ctx, const char * module_base_name, const char * module_name, void * opaque)
1548+ -> char * {
1549+ auto raw = static_cast <Raw*>(opaque);
1550+ assert (raw && raw->module_loader && " Module loader is not set" );
1551+ try {
1552+ auto normalized_name =
1553+ raw->module_loader ->normalizer (module_base_name, module_name);
1554+
1555+ return js_strdup (ctx, normalized_name.c_str ());
1556+ } catch (const std::exception& e) {
1557+ JS_ThrowInternalError (ctx, " Exception in module normalizer: %s" , e.what ());
1558+ return nullptr ;
1559+ } catch (...) {
1560+ JS_ThrowInternalError (ctx, " Unknown exception in module normalizer" );
1561+ return nullptr ;
1562+ }
1563+ },
1564+ [](JSContext* ctx, const char * module_name, void * opaque) -> JSModuleDef* {
1565+ auto raw = static_cast <Raw*>(opaque);
1566+ assert (raw && raw->module_loader && " Module loader is not set" );
1567+
1568+ try {
1569+ auto source = raw->module_loader ->loader (module_name);
1570+ auto module_value =
1571+ Value{ctx,
1572+ JS_Eval (ctx,
1573+ source.data (),
1574+ source.size (),
1575+ module_name,
1576+ JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY )};
1577+
1578+ if (module_value.is_exception ())
1579+ return NULL ;
1580+
1581+ return (JSModuleDef*)JS_VALUE_GET_PTR (module_value.value ());
1582+ } catch (const std::exception& e) {
1583+ JS_ThrowInternalError (ctx, " Exception in module loader: %s" , e.what ());
1584+ return nullptr ;
1585+ } catch (...) {
1586+ JS_ThrowInternalError (ctx, " Unknown exception in module loader" );
1587+ return nullptr ;
1588+ }
1589+ },
1590+ this ->raw .get ());
1591+ }
1592+
14911593 bool has_job_pending () const noexcept {
14921594 return JS_IsJobPending (this ->js_runtime ());
14931595 }
@@ -1533,6 +1635,7 @@ class Runtime {
15331635 void operator () (JSRuntime* rt) const noexcept ;
15341636 };
15351637
1638+ std::unique_ptr<ModuleLoader> module_loader = nullptr ;
15361639 std::unique_ptr<JSRuntime, JSRuntimeDeleter> rt = nullptr ;
15371640 std::unordered_map<std::string, Context> ctxs{};
15381641 };
0 commit comments