/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* JavaScript module (as in, the syntactic construct) operations. */ #ifndef js_Modules_h #define js_Modules_h #include // uint32_t #include "jstypes.h" // JS_PUBLIC_API #include "js/AllocPolicy.h" // js::SystemAllocPolicy #include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions #include "js/RootingAPI.h" // JS::{Mutable,}Handle #include "js/Value.h" // JS::Value #include "js/Vector.h" // js::Vector struct JS_PUBLIC_API JSContext; class JS_PUBLIC_API JSObject; struct JS_PUBLIC_API JSRuntime; class JS_PUBLIC_API JSString; namespace JS { template class SourceText; } // namespace JS namespace mozilla { union Utf8Unit; } namespace JS { enum class ImportAssertion { Type }; using ImportAssertionVector = js::Vector; /** * Set the supported assertions for the runtime to the given vector. * * See: * https://tc39.es/proposal-import-assertions/#sec-hostgetsupportedimportassertions */ extern JS_PUBLIC_API void SetSupportedImportAssertions( JSRuntime* rt, const ImportAssertionVector& assertions); /** * The HostResolveImportedModule hook. * * See: https://tc39.es/ecma262/#sec-hostresolveimportedmodule * * This embedding-defined hook is used to implement module loading. It is called * to get or create a module object corresponding to |moduleRequest| occurring * in the context of the script or module with private value * |referencingPrivate|. * * The module specifier string for the request can be obtained by calling * JS::GetModuleRequestSpecifier. * * The private value for a script or module is set with JS::SetScriptPrivate or * JS::SetModulePrivate. It's assumed that the embedding can handle receiving * either here. * * This hook must obey the restrictions defined in the spec: * - Each time the hook is called with the same arguemnts, the same module must * be returned. * - If a module cannot be created for the given arguments, an exception must * be thrown. * * This is a synchronous operation. */ using ModuleResolveHook = JSObject* (*)(JSContext* cx, Handle referencingPrivate, Handle moduleRequest); /** * Get the HostResolveImportedModule hook for the runtime. */ extern JS_PUBLIC_API ModuleResolveHook GetModuleResolveHook(JSRuntime* rt); /** * Set the HostResolveImportedModule hook for the runtime to the given function. */ extern JS_PUBLIC_API void SetModuleResolveHook(JSRuntime* rt, ModuleResolveHook func); /** * The module metadata hook. * * See: https://tc39.es/ecma262/#sec-hostgetimportmetaproperties * * Populate the |metaObject| object returned when import.meta is evaluated in * the context of the script or module with private value |privateValue|. * * This is based on the spec's HostGetImportMetaProperties hook but defines * properties on the meta object directly rather than returning a list. */ using ModuleMetadataHook = bool (*)(JSContext* cx, Handle privateValue, Handle metaObject); /** * Get the hook for populating the import.meta metadata object. */ extern JS_PUBLIC_API ModuleMetadataHook GetModuleMetadataHook(JSRuntime* rt); /** * Set the hook for populating the import.meta metadata object to the given * function. */ extern JS_PUBLIC_API void SetModuleMetadataHook(JSRuntime* rt, ModuleMetadataHook func); /** * The HostImportModuleDynamically hook. * * See https://tc39.es/ecma262/#sec-hostimportmoduledynamically * * Used to implement dynamic module import. Called when evaluating import() * expressions. * * This starts an asynchronous operation. Some time after this hook is called * the embedding must call JS::FinishDynamicModuleImport() passing the * |referencingPrivate|, |moduleRequest| and |promise| arguments from the * call. This must happen for both success and failure cases. * * In the meantime the embedding can take whatever steps it needs to make the * module available. If successful, after calling FinishDynamicModuleImport() * the module should be returned by the resolve hook when passed * |referencingPrivate| and |moduleRequest|. */ using ModuleDynamicImportHook = bool (*)(JSContext* cx, Handle referencingPrivate, Handle moduleRequest, Handle promise); /** * Get the HostImportModuleDynamically hook for the runtime. */ extern JS_PUBLIC_API ModuleDynamicImportHook GetModuleDynamicImportHook(JSRuntime* rt); /** * Set the HostImportModuleDynamically hook for the runtime to the given * function. * * If this hook is not set (or set to nullptr) then the JS engine will throw an * exception if dynamic module import is attempted. */ extern JS_PUBLIC_API void SetModuleDynamicImportHook( JSRuntime* rt, ModuleDynamicImportHook func); /** * This must be called after a dynamic import operation is complete. * * If |evaluationPromise| is rejected, the rejection reason will be used to * complete the user's promise. */ extern JS_PUBLIC_API bool FinishDynamicModuleImport( JSContext* cx, Handle evaluationPromise, Handle referencingPrivate, Handle moduleRequest, Handle promise); /** * Parse the given source buffer as a module in the scope of the current global * of cx and return a source text module record. */ extern JS_PUBLIC_API JSObject* CompileModule( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf); /** * Parse the given source buffer as a module in the scope of the current global * of cx and return a source text module record. An error is reported if a * UTF-8 encoding error is encountered. */ extern JS_PUBLIC_API JSObject* CompileModule( JSContext* cx, const ReadOnlyCompileOptions& options, SourceText& srcBuf); /** * Set a private value associated with a source text module record. */ extern JS_PUBLIC_API void SetModulePrivate(JSObject* module, const Value& value); /** * Clear the private value associated with a source text module record. * * This is used during unlinking and can be called on a gray module, skipping * the usual checks. */ extern JS_PUBLIC_API void ClearModulePrivate(JSObject* module); /** * Get the private value associated with a source text module record. */ extern JS_PUBLIC_API Value GetModulePrivate(JSObject* module); /* * Perform the ModuleLink operation on the given source text module record. * * This transitively resolves all module dependencies (calling the * HostResolveImportedModule hook) and initializes the environment record for * the module. */ extern JS_PUBLIC_API bool ModuleLink(JSContext* cx, Handle moduleRecord); /* * Perform the ModuleEvaluate operation on the given source text module record * and returns a bool. A result value is returned in result and is either * undefined (and ignored) or a promise (if Top Level Await is enabled). * * If this module has already been evaluated, it returns the evaluation * promise. Otherwise, it transitively evaluates all dependences of this module * and then evaluates this module. * * ModuleLink must have completed prior to calling this. */ extern JS_PUBLIC_API bool ModuleEvaluate(JSContext* cx, Handle moduleRecord, MutableHandleValue rval); enum ModuleErrorBehaviour { // Report module evaluation errors asynchronously when the evaluation promise // is rejected. This is used for web content. ReportModuleErrorsAsync, // Throw module evaluation errors synchronously by setting an exception on the // context. Does not support modules that use top-level await. ThrowModuleErrorsSync }; /* * If a module evaluation fails, unwrap the resulting evaluation promise * and rethrow. * * This does nothing if this module succeeds in evaluation. Otherwise, it * takes the reason for the module throwing, unwraps it and throws it as a * regular error rather than as an uncaught promise. * * ModuleEvaluate must have completed prior to calling this. */ extern JS_PUBLIC_API bool ThrowOnModuleEvaluationFailure( JSContext* cx, Handle evaluationPromise, ModuleErrorBehaviour errorBehaviour = ReportModuleErrorsAsync); /* * Functions to access the module specifiers of a source text module record used * to request module imports. * * Clients can use GetRequestedModulesCount() to get the number of specifiers * and GetRequestedModuleSpecifier() / GetRequestedModuleSourcePos() to get the * individual elements. */ extern JS_PUBLIC_API uint32_t GetRequestedModulesCount(JSContext* cx, Handle moduleRecord); extern JS_PUBLIC_API JSString* GetRequestedModuleSpecifier( JSContext* cx, Handle moduleRecord, uint32_t index); extern JS_PUBLIC_API void GetRequestedModuleSourcePos( JSContext* cx, Handle moduleRecord, uint32_t index, uint32_t* lineNumber, uint32_t* columnNumber); /* * Get the top-level script for a module which has not yet been executed. */ extern JS_PUBLIC_API JSScript* GetModuleScript(Handle moduleRecord); extern JS_PUBLIC_API JSObject* CreateModuleRequest( JSContext* cx, Handle specifierArg); extern JS_PUBLIC_API JSString* GetModuleRequestSpecifier( JSContext* cx, Handle moduleRequestArg); /* * Get the module record for a module script. */ extern JS_PUBLIC_API JSObject* GetModuleObject(Handle moduleScript); /* * Get the namespace object for a module. */ extern JS_PUBLIC_API JSObject* GetModuleNamespace( JSContext* cx, Handle moduleRecord); extern JS_PUBLIC_API JSObject* GetModuleForNamespace( JSContext* cx, Handle moduleNamespace); extern JS_PUBLIC_API JSObject* GetModuleEnvironment( JSContext* cx, Handle moduleObj); /* * Clear all bindings in a module's environment. Used during shutdown. */ extern JS_PUBLIC_API void ClearModuleEnvironment(JSObject* moduleObj); } // namespace JS #endif // js_Modules_h