From 5e7946fe79193633e9a78aae48548635cbc11023 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Mon, 9 Sep 2019 12:20:16 -0500 Subject: vm: refactor SourceTextModule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Removes redundant `instantiate` method - Refactors `link` to match the spec linking steps more accurately - Removes URL validation from SourceTextModule specifiers - DRYs some dynamic import logic Closes: https://github.com/nodejs/node/issues/29030 Co-Authored-By: Michaël Zasso PR-URL: https://github.com/nodejs/node/pull/29776 Reviewed-By: James M Snell Reviewed-By: Michaël Zasso Reviewed-By: Minwoo Jung --- doc/api/vm.md | 103 +++++++++++++++------------------------------------------- 1 file changed, 27 insertions(+), 76 deletions(-) (limited to 'doc/api/vm.md') diff --git a/doc/api/vm.md b/doc/api/vm.md index 18ebd10a63..601b8c3052 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -322,9 +322,9 @@ intrinsically asynchronous, in contrast with the synchronous nature of `vm.Script` objects. With the help of async functions, however, manipulating `vm.SourceTextModule` objects is fairly straightforward. -Using a `vm.SourceTextModule` object requires four distinct steps: -creation/parsing, linking, instantiation, and evaluation. These four steps are -illustrated in the following example. +Using a `vm.SourceTextModule` object requires three distinct steps: +creation/parsing, linking, and evaluation. These three steps are illustrated in +the following example. This implementation lies at a lower level than the [ECMAScript Module loader][]. There is also currently no way to interact with the Loader, though @@ -391,15 +391,6 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); // Step 3 // - // Instantiate the top-level Module. - // - // Only the top-level Module needs to be explicitly instantiated; its - // dependencies will be recursively instantiated by instantiate(). - - bar.instantiate(); - - // Step 4 - // // Evaluate the Module. The evaluate() method returns a Promise with a single // property "result" that contains the result of the very last statement // executed in the Module. In the case of `bar`, it is `s;`, which refers to @@ -417,8 +408,9 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); * `code` {string} JavaScript Module code to parse * `options` - * `url` {string} URL used in module resolution and stack traces. **Default:** - `'vm:module(i)'` where `i` is a context-specific ascending index. + * `identifier` {string} String used in stack traces. + **Default:** `'vm:module(i)'` where `i` is a context-specific ascending + index. * `context` {Object} The [contextified][] object as returned by the `vm.createContext()` method, to compile and evaluate this `Module` in. * `lineOffset` {integer} Specifies the line number offset that is displayed @@ -465,7 +457,6 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); }); // Since module has no dependencies, the linker function will never be called. await module.link(() => {}); - module.instantiate(); await module.evaluate(); // Now, Object.prototype.secret will be equal to 42. @@ -516,7 +507,7 @@ in the ECMAScript specification. Evaluate the module. -This must be called after the module has been instantiated; otherwise it will +This must be called after the module has been linked; otherwise it will throw an error. It could be called also when the module has already been evaluated, in which case it will do one of the following two things: @@ -531,23 +522,6 @@ This method cannot be called while the module is being evaluated Corresponds to the [Evaluate() concrete method][] field of [Source Text Module Record][]s in the ECMAScript specification. -### module.instantiate() - -Instantiate the module. This must be called after linking has completed -(`linkingStatus` is `'linked'`); otherwise it will throw an error. It may also -throw an exception if one of the dependencies does not provide an export the -parent module requires. - -However, if this function succeeded, further calls to this function after the -initial instantiation will be no-ops, to be consistent with the ECMAScript -specification. - -Unlike other methods operating on `Module`, this function completes -synchronously and returns nothing. - -Corresponds to the [Instantiate() concrete method][] field of [Source Text -Module Record][]s in the ECMAScript specification. - ### module.link(linker) * `linker` {Function} @@ -563,7 +537,7 @@ Module Record][]s in the ECMAScript specification. * Returns: {vm.SourceTextModule|Promise} * Returns: {Promise} -Link module dependencies. This method must be called before instantiation, and +Link module dependencies. This method must be called before evaluation, and can only be called once per module. The function is expected to return a `Module` object or a `Promise` that @@ -571,9 +545,9 @@ eventually resolves to a `Module` object. The returned `Module` must satisfy the following two invariants: * It must belong to the same context as the parent `Module`. -* Its `linkingStatus` must not be `'errored'`. +* Its `status` must not be `'errored'`. -If the returned `Module`'s `linkingStatus` is `'unlinked'`, this method will be +If the returned `Module`'s `status` is `'unlinked'`, this method will be recursively called on the returned `Module` with the same provided `linker` function. @@ -587,37 +561,22 @@ specification, with a few key differences: * The linker function is allowed to be asynchronous while [HostResolveImportedModule][] is synchronous. -* The linker function is executed during linking, a Node.js-specific stage - before instantiation, while [HostResolveImportedModule][] is called during - instantiation. The actual [HostResolveImportedModule][] implementation used during module -instantiation is one that returns the modules linked during linking. Since at +linking is one that returns the modules linked during linking. Since at that point all modules would have been fully linked already, the [HostResolveImportedModule][] implementation is fully synchronous per specification. -### module.linkingStatus - -* {string} - -The current linking status of `module`. It will be one of the following values: - -* `'unlinked'`: `module.link()` has not yet been called. -* `'linking'`: `module.link()` has been called, but not all Promises returned by - the linker function have been resolved yet. -* `'linked'`: `module.link()` has been called, and all its dependencies have - been successfully linked. -* `'errored'`: `module.link()` has been called, but at least one of its - dependencies failed to link, either because the callback returned a `Promise` - that is rejected, or because the `Module` the callback returned is invalid. +Corresponds to the [Link() concrete method][] field of [Source Text Module +Record][]s in the ECMAScript specification. ### module.namespace * {Object} -The namespace object of the module. This is only available after instantiation -(`module.instantiate()`) has completed. +The namespace object of the module. This is only available after linking +(`module.link()`) has completed. Corresponds to the [GetModuleNamespace][] abstract operation in the ECMAScript specification. @@ -628,21 +587,13 @@ specification. The current status of the module. Will be one of: -* `'uninstantiated'`: The module is not instantiated. It may because of any of - the following reasons: - - * The module was just created. - * `module.instantiate()` has been called on this module, but it failed for - some reason. - - This status does not convey any information regarding if `module.link()` has - been called. See `module.linkingStatus` for that. +* `'unlinked'`: `module.link()` has not yet been called. -* `'instantiating'`: The module is currently being instantiated through a - `module.instantiate()` call on itself or a parent module. +* `'linking'`: `module.link()` has been called, but not all Promises returned + by the linker function have been resolved yet. -* `'instantiated'`: The module has been instantiated successfully, but - `module.evaluate()` has not yet been called. +* `'linked'`: The module has been linked successfully, and all of its + dependencies are linked, but `module.evaluate()` has not yet been called. * `'evaluating'`: The module is being evaluated through a `module.evaluate()` on itself or a parent module. @@ -656,11 +607,11 @@ Other than `'errored'`, this status string corresponds to the specification's `'evaluated'` in the specification, but with `[[EvaluationError]]` set to a value that is not `undefined`. -### module.url +### module.identifier * {string} -The URL of the current module, as set in the constructor. +The identifier of the current module, as set in the constructor. ## vm.compileFunction(code[, params[, options]])