@@ -43,6 +43,322 @@ console.log(x); // 1; y is not defined.
4343* Note* : The vm module is not a security mechanism.
4444** Do not use it to run untrusted code** .
4545
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+
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+
46362## Class: vm.Script
47363<!-- YAML
48364added: v0.3.1
@@ -548,9 +864,15 @@ associating it with the `sandbox` object is what this document refers to as
548864[ `vm.createContext()` ] : #vm_vm_createcontext_sandbox_options
549865[ `vm.runInContext()` ] : #vm_vm_runincontext_code_contextifiedsandbox_options
550866[ `vm.runInThisContext()` ] : #vm_vm_runinthiscontext_code_options
867+ [ GetModuleNamespace ] : https://tc39.github.io/ecma262/#sec-getmodulenamespace
868+ [ ECMAScript Module Loader ] : esm.html#esm_ecmascript_modules
869+ [ Evaluate() concrete method ] : https://tc39.github.io/ecma262/#sec-moduleevaluation
870+ [ HostResolveImportedModule ] : https://tc39.github.io/ecma262/#sec-hostresolveimportedmodule
871+ [ Instantiate() concrete method ] : https://tc39.github.io/ecma262/#sec-moduledeclarationinstantiation
551872[ V8 Embedder's Guide ] : https://github.com/v8/v8/wiki/Embedder's%20Guide#contexts
552873[ command line option ] : cli.html
553874[ contextified ] : #vm_what_does_it_mean_to_contextify_an_object
554875[ global object ] : https://es5.github.io/#x15.1
555876[ indirect `eval()` call ] : https://es5.github.io/#x10.4.2
556877[ origin ] : https://developer.mozilla.org/en-US/docs/Glossary/Origin
878+ [ Source Text Module Record ] : https://tc39.github.io/ecma262/#sec-source-text-module-records
0 commit comments