summaryrefslogtreecommitdiffstats
path: root/js/public/Modules.h
blob: 4a8d45acb07dee2985e701c3c21bc7ab997da242 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/* -*- 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 <stdint.h>  // uint32_t

#include "jstypes.h"  // JS_PUBLIC_API

#include "js/AllocPolicy.h"     // js::SystemAllocPolicy
#include "js/ColumnNumber.h"    // JS::ColumnNumberOneOrigin
#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 <typename UnitT>
class SourceText;
}  // namespace JS

namespace mozilla {
union Utf8Unit;
}

namespace JS {

enum class ModuleType : uint32_t { Unknown = 0, JavaScript, JSON };

/**
 * 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<Value> referencingPrivate,
                                        Handle<JSObject*> 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<Value> privateValue,
                                    Handle<JSObject*> 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<Value> referencingPrivate,
                                         Handle<JSObject*> moduleRequest,
                                         Handle<JSObject*> 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<JSObject*> evaluationPromise,
    Handle<Value> referencingPrivate, Handle<JSObject*> moduleRequest,
    Handle<JSObject*> 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<char16_t>& 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<mozilla::Utf8Unit>& srcBuf);

/**
 * Parse the given source buffer as a JSON module in the scope of the current
 * global of cx and return a synthetic module record.
 */
extern JS_PUBLIC_API JSObject* CompileJsonModule(
    JSContext* cx, const ReadOnlyCompileOptions& options,
    SourceText<char16_t>& 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<JSObject*> 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<JSObject*> 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<JSObject*> 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<JSObject*> moduleRecord);

extern JS_PUBLIC_API JSString* GetRequestedModuleSpecifier(
    JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index);

/*
 * Get the position of a requested module's name in the source.
 */
extern JS_PUBLIC_API void GetRequestedModuleSourcePos(
    JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index,
    uint32_t* lineNumber, JS::ColumnNumberOneOrigin* columnNumber);

/*
 * Get the top-level script for a module which has not yet been executed.
 */
extern JS_PUBLIC_API JSScript* GetModuleScript(Handle<JSObject*> moduleRecord);

extern JS_PUBLIC_API JSObject* CreateModuleRequest(
    JSContext* cx, Handle<JSString*> specifierArg);
extern JS_PUBLIC_API JSString* GetModuleRequestSpecifier(
    JSContext* cx, Handle<JSObject*> moduleRequestArg);

/*
 * Get the module record for a module script.
 */
extern JS_PUBLIC_API JSObject* GetModuleObject(Handle<JSScript*> moduleScript);

/*
 * Get the namespace object for a module.
 */
extern JS_PUBLIC_API JSObject* GetModuleNamespace(
    JSContext* cx, Handle<JSObject*> moduleRecord);

extern JS_PUBLIC_API JSObject* GetModuleForNamespace(
    JSContext* cx, Handle<JSObject*> moduleNamespace);

extern JS_PUBLIC_API JSObject* GetModuleEnvironment(
    JSContext* cx, Handle<JSObject*> moduleObj);

/*
 * Clear all bindings in a module's environment. Used during shutdown.
 */
extern JS_PUBLIC_API void ClearModuleEnvironment(JSObject* moduleObj);

extern JS_PUBLIC_API bool ModuleIsLinked(JSObject* moduleObj);

}  // namespace JS

#endif  // js_Modules_h