@@ -43,6 +43,322 @@ console.log(x); // 1; y is not defined.
43
43
* Note* : The vm module is not a security mechanism.
44
44
** Do not use it to run untrusted code** .
45
45
46
+ ## Class: vm.Module
47
+ <!-- YAML
48
+ added: REPLACEME
49
+ -->
50
+
51
+ > Stability: 1 - Experimental
52
+
53
+ * This feature is only available with the ` --experimental-vm-modules ` command
54
+ flag enabled.*
55
+
56
+ The ` vm.Module ` class provides a low-level interface for using ECMAScript
57
+ modules in VM contexts. It is the counterpart of the ` vm.Script ` class that
58
+ closely mirrors [ Source Text Module Record] [ ] s as defined in the ECMAScript
59
+ specification.
60
+
61
+ Unlike ` vm.Script ` however, every ` vm.Module ` object is bound to a context from
62
+ its creation. Operations on ` vm.Module ` objects are intrinsically asynchronous,
63
+ in contrast with the synchronous nature of ` vm.Script ` objects. With the help
64
+ of async functions, however, manipulating ` vm.Module ` objects is fairly
65
+ straightforward.
66
+
67
+ Using a ` vm.Module ` object requires four distinct steps: creation/parsing,
68
+ linking, instantiation, and evaluation. These four steps are illustrated in the
69
+ following example.
70
+
71
+ * Note* : This implementation lies at a lower level than the [ ECMAScript Module
72
+ loader] [ ] . There is also currently no way to interact with the Loader, though
73
+ support is planned.
74
+
75
+ ``` js
76
+ const vm = require (' vm' );
77
+
78
+ const contextifiedSandbox = vm .createContext ({ secret: 42 });
79
+
80
+ (async () => {
81
+ // Step 1
82
+ //
83
+ // Create a Module by constructing a new `vm.Module` object. This parses the
84
+ // provided source text, throwing a `SyntaxError` if anything goes wrong. By
85
+ // default, a Module is created in the top context. But here, we specify
86
+ // `contextifiedSandbox` as the context this Module belongs to.
87
+ //
88
+ // Here, we attempt to obtain the default export from the module "foo", and
89
+ // put it into local binding "secret".
90
+
Has a conversation. Original line has a conversation.
91
+ const bar = new vm.Module (`
92
+ import s from 'foo';
93
+ s;
94
+ ` , { context: contextifiedSandbox });
95
+
96
+
97
+ // Step 2
98
+ //
99
+ // "Link" the imported dependencies of this Module to it.
100
+ //
101
+ // The provided linking callback (the "linker") accepts two arguments: the
102
+ // parent module (`bar` in this case) and the string that is the specifier of
103
+ // the imported module. The callback is expected to return a Module that
104
+ // corresponds to the provided specifier, with certain requirements documented
105
+ // in `module.link()`.
106
+ //
107
+ // If linking has not started for the returned Module, the same linker
108
+ // callback will be called on the returned Module.
109
+ //
110
+ // Even top-level Modules without dependencies must be explicitly linked. The
111
+ // callback provided would never be called, however.
112
+ //
113
+ // The link() method returns a Promise that will be resolved when all the
114
+ // Promises returned by the linker resolve.
115
+ //
116
+ // Note: This is a contrived example in that the linker function creates a new
117
+ // "foo" module every time it is called. In a full-fledged module system, a
118
+ // cache would probably be used to avoid duplicated modules.
119
+
120
+ async function linker (referencingModule , specifier ) {
121
+ if (specifier === ' foo' ) {
122
+ return new vm.Module (`
123
+ // The "secret" variable refers to the global variable we added to
124
+ // "contextifiedSandbox" when creating the context.
125
+ export default secret;
126
+ ` , { context: referencingModule .context });
127
+
128
+ // Using `contextifiedSandbox` instead of `referencingModule.context`
129
+ // here would work as well.
130
+ }
131
+ throw new Error (` Unable to resolve dependency: ${ specifier} ` );
132
+ }
133
+ await bar .link (linker);
134
+
135
+
136
+ // Step 3
137
+ //
138
+ // Instantiate the top-level Module.
139
+ //
140
+ // Only the top-level Module needs to be explicitly instantiated; its
141
+ // dependencies will be recursively instantiated by instantiate().
142
+
143
+ bar .instantiate ();
144
+
145
+
146
+ // Step 4
147
+ //
148
+ // Evaluate the Module. The evaluate() method returns a Promise with a single
149
+ // property "result" that contains the result of the very last statement
150
+ // executed in the Module. In the case of `bar`, it is `s;`, which refers to
151
+ // the default export of the `foo` module, the `secret` we set in the
152
+ // beginning to 42.
153
+
154
+ const { result } = await bar .evaluate ();
155
+
156
+ console .log (result);
157
+ // Prints 42.
158
+ })();
159
+ ```
160
+
161
+ ### Constructor: new vm.Module(code[ , options] )
162
+
163
+ * ` code ` {string} JavaScript Module code to parse
164
+ * ` options `
165
+ * ` url ` {string} URL used in module resolution and stack traces. ** Default** :
166
+ ` 'vm:module(i)' ` where ` i ` is a context-specific ascending index.
167
+ * ` context ` {Object} The [ contextified] [ ] object as returned by the
168
+ ` vm.createContext() ` method, to compile and evaluate this Module in.
169
+ * ` lineOffset ` {integer} Specifies the line number offset that is displayed
170
+ in stack traces produced by this Module.
171
+ * ` columnOffset ` {integer} Spcifies the column number offset that is displayed
172
+ in stack traces produced by this Module.
173
+
174
+ Creates a new ES ` Module ` object.
175
+
176
+ ### module.dependencySpecifiers
177
+
178
+ * {string[ ] }
179
+
180
+ The specifiers of all dependencies of this module. The returned array is frozen
181
+ to disallow any changes to it.
182
+
183
+ Corresponds to the [[ RequestedModules]] field of [ Source Text Module Record] [ ] s
184
+ in the ECMAScript specification.
185
+
186
+ ### module.error
187
+
188
+ * {any}
189
+
190
+ If the ` module.status ` is ` 'errored' ` , this property contains the exception thrown
191
+ by the module during evaluation. If the status is anything else, accessing this
192
+ property will result in a thrown exception.
193
+
194
+ * Note* : ` undefined ` cannot be used for cases where there is not a thrown
195
+ exception due to possible ambiguity with ` throw undefined; ` .
196
+
197
+ Corresponds to the [[ EvaluationError]] field of [ Source Text Module Record] [ ] s
198
+ in the ECMAScript specification.
199
+
200
+ ### module.linkingStatus
201
+
202
+ * {string}
203
+
204
+ The current linking status of ` module ` . It will be one of the following values:
205
+
206
+ - ` 'unlinked' ` : ` module.link() ` has not yet been called.
207
+ - ` 'linking' ` : ` module.link() ` has been called, but not all Promises returned by
208
+ the linker function have been resolved yet.
209
+ - ` 'linked' ` : ` module.link() ` has been called, and all its dependencies have
210
+ been successfully linked.
211
+ - ` 'errored' ` : ` module.link() ` has been called, but at least one of its
212
+ dependencies failed to link, either because the callback returned a Promise
213
+ that is rejected, or because the Module the callback returned is invalid.
214
+
215
+ ### module.namespace
216
+
217
+ * {Object}
218
+
219
+ The namespace object of the module. This is only available after instantiation
220
+ (` module.instantiate() ` ) has completed.
221
+
222
+ Corresponds to the [ GetModuleNamespace] [ ] abstract operation in the ECMAScript
223
+ specification.
224
+
225
+ ### module.status
226
+
227
+ * {string}
228
+
229
+ The current status of the module. Will be one of:
230
+
231
+ - ` 'uninstantiated' ` : The module is not instantiated. It may because of any of
232
+ the following reasons:
233
+
234
+ - The module was just created.
235
+ - ` module.instantiate() ` has been called on this module, but it failed for
236
+ some reason.
237
+
238
+ This status does not convey any information regarding if ` module.link() ` has
239
+ been called. See ` module.linkingStatus ` for that.
240
+
241
+ - ` 'instantiating' ` : The module is currently being instantiated through a
242
+ ` module.instantiate() ` call on itself or a parent module.
243
+
244
+ - ` 'instantiated' ` : The module has been instantiated successfully, but
245
+ ` module.evaluate() ` has not yet been called.
246
+
247
+ - ` 'evaluating' ` : The module is being evaluated through a ` module.evaluate() ` on
248
+ itself or a parent module.
249
+
250
+ - ` 'evaluated' ` : The module has been successfully evaluated.
251
+
252
+ - ` 'errored' ` : The module has been evaluated, but an exception was thrown.
253
+
254
+ Other than ` 'errored' ` , this status string corresponds to the specification's
255
+ [ Source Text Module Record] [ ] 's [[ Status]] field. ` 'errored' ` corresponds to
256
+ ` 'evaluated' ` in the specification, but with [[ EvaluationError]] set to a value
257
+ that is not ` undefined ` .
258
+
259
+ ### module.url
260
+
261
+ * {string}
262
+
263
+ The URL of the current module, as set in the constructor.
264
+
265
+ ### module.evaluate([ options] )
266
+
267
+ * ` options ` {Object}
268
+ * ` timeout ` {number} Specifies the number of milliseconds to evaluate
269
+ before terminating execution. If execution is interrupted, an [ ` Error ` ] [ ]
270
+ will be thrown.
271
+ * ` breakOnSigint ` {boolean} If ` true ` , the execution will be terminated when
272
+ ` SIGINT ` (Ctrl+C) is received. Existing handlers for the event that have
273
+ been attached via ` process.on("SIGINT") ` will be disabled during script
274
+ execution, but will continue to work after that. If execution is
275
+ interrupted, an [ ` Error ` ] [ ] will be thrown.
276
+ * Returns: {Promise}
277
+
278
+ Evaluate the module.
279
+
280
+ This must be called after the module has been instantiated; otherwise it will
281
+ throw an error. It could be called also when the module has already been
282
+ evaluated, in which case it will do one of the following two things:
283
+
284
+ - return ` undefined ` if the initial evaluation ended in success (` module.status `
285
+ is ` 'evaluated' ` )
286
+ - rethrow the same exception the initial evaluation threw if the initial
287
+ evaluation ended in an error (` module.status ` is ` 'errored' ` )
288
+
289
+ This method cannot be called while the module is being evaluated
290
+ (` module.status ` is ` 'evaluating' ` ) to prevent infinite recursion.
291
+
292
+ Corresponds to the [ Evaluate() concrete method] [ ] field of [ Source Text Module
293
+ Record] [ ] s in the ECMAScript specification.
294
+
295
+ ### module.instantiate()
296
+
297
+ Instantiate the module. This must be called after linking has completed
298
+ (` linkingStatus ` is ` 'linked' ` ); otherwise it will throw an error. It may also
299
+ throw an exception if one of the dependencies does not provide an export the
300
+ parent module requires.
301
+
302
+ However, if this function succeeded, further calls to this function after the
303
+ initial instantiation will be no-ops, to be consistent with the ECMAScript
304
+ specification.
305
+
306
+ Unlike other methods operating on ` Module ` , this function completes
307
+ synchronously and returns nothing.
308
+
309
+ Corresponds to the [ Instantiate() concrete method] [ ] field of [ Source Text
310
+ Module Record] [ ] s in the ECMAScript specification.
311
+
312
+ ### module.link(linker)
313
+
314
+ * ` linker ` {Function}
315
+ * Returns: {Promise}
316
+
317
+ Link module dependencies. This method must be called before instantiation, and
318
+ can only be called once per module.
319
+
320
+ Two parameters will be passed to the ` linker ` function:
321
+
322
+ - ` referencingModule ` The ` Module ` object ` link() ` is called on.
323
+ - ` specifier ` The specifier of the requested module:
324
+
325
+ <!-- eslint-skip -->
326
+ ``` js
327
+ import foo from ' foo' ;
328
+ // ^^^^^ the module specifier
329
+ ```
330
+
331
+ The function is expected to return a ` Module ` object or a ` Promise ` that
332
+ eventually resolves to a ` Module ` object. The returned ` Module ` must satisfy the
333
+ following two invariants:
334
+
335
+ - It must belong to the same context as the parent ` Module ` .
336
+ - Its ` linkingStatus ` must not be ` 'errored' ` .
337
+
338
+ If the returned ` Module ` 's ` linkingStatus ` is ` 'unlinked' ` , this method will be
339
+ recursively called on the returned ` Module ` with the same provided ` linker `
340
+ function.
341
+
342
+ ` link() ` returns a ` Promise ` that will either get resolved when all linking
343
+ instances resolve to a valid ` Module ` , or rejected if the linker function either
344
+ throws an exception or returns an invalid ` Module ` .
345
+
346
+ The linker function roughly corresponds to the implementation-defined
347
+ [ HostResolveImportedModule] [ ] abstract operation in the ECMAScript
348
+ specification, with a few key differences:
349
+
350
+ - The linker function is allowed to be asynchronous while
351
+ [ HostResolveImportedModule] [ ] is synchronous.
352
+ - The linker function is executed during linking, a Node.js-specific stage
353
+ before instantiation, while [ HostResolveImportedModule] [ ] is called during
354
+ instantiation.
355
+
356
+ The actual [ HostResolveImportedModule] [ ] implementation used during module
357
+ instantiation is one that returns the modules linked during linking. Since at
358
+ that point all modules would have been fully linked already, the
359
+ [ HostResolveImportedModule] [ ] implementation is fully synchronous per
360
+ specification.
361
+
46
362
## Class: vm.Script
47
363
<!-- YAML
48
364
added: v0.3.1
@@ -518,8 +834,14 @@ associating it with the `sandbox` object is what this document refers to as
518
834
[ `vm.createContext()` ] : #vm_vm_createcontext_sandbox_options
519
835
[ `vm.runInContext()` ] : #vm_vm_runincontext_code_contextifiedsandbox_options
520
836
[ `vm.runInThisContext()` ] : #vm_vm_runinthiscontext_code_options
837
+ [ GetModuleNamespace ] : https://tc39.github.io/ecma262/#sec-getmodulenamespace
838
+ [ ECMAScript Module Loader ] : esm.html#esm_ecmascript_modules
839
+ [ Evaluate() concrete method ] : https://tc39.github.io/ecma262/#sec-moduleevaluation
840
+ [ HostResolveImportedModule ] : https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule
841
+ [ Instantiate() concrete method ] : https://tc39.github.io/ecma262/#sec-moduledeclarationinstantiation
521
842
[ V8 Embedder's Guide ] : https://github.com/v8/v8/wiki/Embedder's%20Guide#contexts
522
843
[ contextified ] : #vm_what_does_it_mean_to_contextify_an_object
523
844
[ global object ] : https://es5.github.io/#x15.1
524
845
[ indirect `eval()` call ] : https://es5.github.io/#x10.4.2
525
846
[ origin ] : https://developer.mozilla.org/en-US/docs/Glossary/Origin
847
+ [ Source Text Module Record ] : https://tc39.github.io/ecma262/#sec-source-text-module-records