Before it is evaluated, all ECMAScript code must be associated with a realm. Conceptually, a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.
A realm is represented in this specification as a Realm Record with the fields specified in Table 1:
A map from the specifier strings imported by this realm to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]].
Note
The abstract operation ContinueDynamicImport takes arguments state (a ModuleLoadState Record whose [[Action]] is dynamic-import) and module (either a normal completion containing a Module Record or a throw completion) and returns unused. ContinueDynamicImport completes the process of a dynamic import originally started by an import() call, resolving or rejecting the promise returned by that call as appropriate according to innerPromise's resolution. It performs the following steps when called:
Let promiseCapability be state.[[PromiseCapability]].
Let linkAndEvaluateClosure be a new Abstract Closure with no parameters that captures module, promiseCapability, and onRejected and performs the following steps when called:
Let fulfilledClosure be a new Abstract Closure with no parameters that captures module and promiseCapability and performs the following steps when called:
A map from the specifier strings imported by this script to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]].
The abstract operation ParseScript takes arguments sourceText (ECMAScript source text), realm, and hostDefined and returns a Script Record or a non-empty List of SyntaxError objects. It creates a Script Record based upon the result of parsing sourceText as a Script. It performs the following steps when called:
Return Script Record { [[Realm]]: realm, [[ECMAScriptCode]]: script, [[LoadedModules]]: a new empty List, [[HostDefined]]: hostDefined }.
16.2 Modules
16.2.1 Module Semantics
16.2.1.4 Abstract Module Records
A Module Record encapsulates structural information about the imports and exports of a single module. This information is used to link the imports and exports of sets of connected modules. A Module Record includes four fields that are only used when evaluating a module.
For specification purposes Module Record values are values of the Record specification type and can be thought of as existing in a simple object-oriented hierarchy where Module Record is an abstract class with both abstract and concrete subclasses. This specification defines the abstract subclass named Cyclic Module Record and its concrete subclass named Source Text Module Record. Other specifications and implementations may define additional Module Record subclasses corresponding to alternative module definition facilities that they defined.
Module Record defines the fields listed in Table 44. All Module Definition subclasses include at least those fields. Module Record also defines the abstract method list in Table 3. All Module definition subclasses must provide concrete implementations of these abstract methods.
Prepares the module for linking by recursively loading all its dependencies, and returns a promise.
Link()
Prepare the module for evaluation by transitively resolving all module dependencies and creating a module Environment Record.
LoadRequestedModules must have completed successfully prior to invoking this method.
Evaluate()
Returns a promise for the evaluation of this module and its dependencies, resolving on successful evaluation or if it has already been evaluated successfully, and rejecting for an evaluation error or if it has already been evaluated unsuccessfully. If the promise is rejected, hosts are expected to handle the promise rejection and rethrow the evaluation error.
Link must have completed successfully prior to invoking this method.
16.2.1.5 Cyclic Module Records
A Cyclic Module Record is used to represent information about a module that can participate in dependency cycles with other modules that are subclasses of the Cyclic Module Record type. Module Records that are not subclasses of the Cyclic Module Record type must not participate in dependency cycles with Source Text Module Records.
new, unlinked, linking, linked, evaluating, evaluating-async, or evaluated
Initially unlinkednew. Transitions to unlinked, linking, linked, evaluating, possibly evaluating-async, evaluated (in that order) as the module progresses throughout its lifecycle. evaluating-async indicates this module is queued to execute on completion of its asynchronous dependencies or it is a module whose [[HasTLA]] field is true that has been executed and is pending top-level completion.
A List of all the ModuleSpecifier strings used by the module represented by this record to request the importation of a module. The List is source text occurrence ordered.
A map from the specifier strings used by the module represented by this record to request the importation of a module to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]].
A ModuleLoadState Record is a Record that contains information about the loading process of a module graph. It's used to continue loading after a call to HostLoadImportedModule. Each ModuleLoadState Record has the fields defined in Table 6:
The action that caused the call to HostLoadImportedModule. It is graph-loading when loading the dependencies of a module; it is dynamic-import when loading a module that was requested by an import() call.
The promise to resolve when the loading process finishes.
[[IsLoading]]
a boolean
This field is only used if [[Action]] is graph-loading. It is true if the loading process has not finished yet, neither successfully nor with an error.
This field is only used if [[Action]] is graph-loading. It is a list of the Cyclic Module Records that have been already loaded by the current loading process, to avoid infinite loops with circular dependencies.
The LoadRequestedModules concrete method of a Cyclic Module Recordmodule takes optional argument hostDefined and returns a Promise object. It populates the [[LoadedModules]] of all the Modue Records in the dependency graph of module (most of the work is done by the auxiliary function InnerModuleLoading). It takes an optional hostDefined parameter, that is passed to the HostLoadImportedModule hook. It performs the following steps when called:
If hostDefined is not present, let hostDefined be undefined.
Let state be a new ModuleLoadState Record { [[Action]]: graph-loading, [[IsLoading]]: true, [[PendingModules]]: 1, [[Visited]]: a new empty List, [[PromiseCapability]]: pc, [[HostDefined]]: hostDefined }.
The hostDefined parameter can be used to pass additional information necessary to fetch the imported modules. It is used, for example, by HTML to set the correct fetch destination for <link rel="preload" as="..."> tags.
Note that import() expressions never set the hostDefined parameter.
16.2.1.5.1.1 InnerModuleLoading ( state, module )
The abstract operation InnerModuleLoading takes arguments state (a ModuleLoadState Record whose [[Action]] is graph-loading) and module (a Module Record) and returns unused. It is used by LoadRequestedModules to recursively perform the actual loading process for module's dependency graph. It performs the following steps when called:
The Link concrete method of a Cyclic Module Recordmodule takes no arguments and returns either a normal completion containingunused or a throw completion. On success, Link transitions this module's [[Status]] from unlinked to linked. On failure, an exception is thrown and this module's [[Status]] remains unlinked. (Most of the work is done by the auxiliary function InnerModuleLinking.) It performs the following steps when called:
Assert: module.[[Status]] is not linking or evaluatingunlinked, linked, evaluating-async, or evaluated.
16.2.1.5.2.1 InnerModuleLinking ( module, stack, index )
The abstract operation InnerModuleLinking takes arguments module (a Module Record), stack, and index (a non-negative integer) and returns either a normal completion containing a non-negative integer or a throw completion. It is used by Link to perform the actual linking process for module, as well as recursively on all other modules in the dependency graph. The stack and index parameters, as well as a module's [[DFSIndex]] and [[DFSAncestorIndex]] fields, keep track of the depth-first search (DFS) traversal. In particular, [[DFSAncestorIndex]] is used to discover strongly connected components (SCCs), such that all modules in an SCC transition to linked together. It performs the following steps when called:
If requiredModule and module are the same Module Record, set done to true.
Return index.
16.2.1.5.3 Evaluate ( )
16.2.1.5.3.1 InnerModuleEvaluation ( module, stack, index )
The abstract operation InnerModuleEvaluation takes arguments module (a Module Record), stack, and index (a non-negative integer) and returns either a normal completion containing a non-negative integer or a throw completion. It is used by Evaluate to perform the actual evaluation process for module, as well as recursively on all other modules in the dependency graph. The stack and index parameters, as well as module's [[DFSIndex]] and [[DFSAncestorIndex]] fields, are used the same way as in InnerModuleLinking. It performs the following steps when called:
The abstract operation ParseModule takes arguments sourceText (ECMAScript source text), realm, and hostDefined and returns a Source Text Module Record or a non-empty List of SyntaxError objects. It creates a Source Text Module Record based upon the result of parsing sourceText as a Module. It performs the following steps when called:
An implementation may parse module source text and analyse it for Early Error conditions prior to the evaluation of ParseModule for that module source text. However, the reporting of any errors must be deferred until the point where this specification actually performs ParseModule upon that source text.
ResolveExport attempts to resolve an imported binding to the actual defining module and local binding name. The defining module may be the module represented by the Module Record this method was invoked on or some other module that is imported by that module. The parameter resolveSet is used to detect unresolved circular import/export paths. If a pair consisting of specific Module Record and exportName is reached that is already in resolveSet, an import circularity has been encountered. Before recursively calling ResolveExport, a pair consisting of module and exportName is added to resolveSet.
If a defining module is found, a ResolvedBinding Record { [[Module]], [[BindingName]] } is returned. This record identifies the resolved binding of the originally requested export, unless this is the export of a namespace with no local binding. In this case, [[BindingName]] will be set to namespace. If no definition was found or the request is found to be circular, null is returned. If the request is found to be ambiguous, ambiguous is returned.
It performs the following steps when called:
If resolveSet is not present, set resolveSet to a new empty List.
For each Record { [[Module]], [[ExportName]] } r of resolveSet, do
If module and r.[[Module]] are the same Module Record and SameValue(exportName, r.[[ExportName]]) is true, then
If starResolution is null, set starResolution to resolution.
Else,
Assert: There is more than one * import that includes the requested name.
If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return ambiguous.
If resolution.[[BindingName]] is namespace and starResolution.[[BindingName]] is not namespace, or if resolution.[[BindingName]] is not namespace and starResolution.[[BindingName]] is namespace, return ambiguous.
If resolution.[[BindingName]] is a String, starResolution.[[BindingName]] is a String, and SameValue(resolution.[[BindingName]], starResolution.[[BindingName]]) is false, return ambiguous.
Assert: importedModule is not empty, because LoadRequestedModules must have completed successfully prior to invoking this method.
NOTE: The above call cannot fail because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.
The host-defined abstract operation HostResolveImportedModule takes arguments referencingScriptOrModule (a Script Record, a Module Record, or null) and specifier (a ModuleSpecifier String) and returns either a normal completion containing a Module Record or a throw completion. It provides the concrete Module Record subclass instance that corresponds to specifier occurring within the context of the script or module represented by referencingScriptOrModule. referencingScriptOrModule may be null if the resolution is being performed in the context of an import() expression and there is no active script or module at that time.
Note
An example of when referencingScriptOrModule can be null is in a web browser host. There, if a user clicks on a control given by
If a Module Record corresponding to the pair referencingScriptOrModule, specifier does not exist or cannot be created, an exception must be thrown.
Each time this operation is called with a specific referencingScriptOrModule, specifier pair as arguments it must return the same Module Record instance if it completes normally.
Multiple different referencingScriptOrModule, specifier pairs may map to the same Module Record instance. The actual mapping semantic is host-defined but typically a normalization process is applied to specifier as part of the mapping process. A typical normalization process would include actions such as alphabetic case folding and expansion of relative and abbreviated path specifiers.
The host-defined abstract operation HostImportModuleDynamically takes arguments referencingScriptOrModule (a Script Record, a Module Record, or null), specifier (a ModuleSpecifier String), and promiseCapability (a PromiseCapability Record) and returns unused. It performs any necessary setup work in order to make available the module corresponding to specifier occurring within the context of the script or module represented by referencingScriptOrModule. referencingScriptOrModule may be null if there is no active script or module when the import() expression occurs. It then performs FinishDynamicImport to finish the dynamic import process.
An implementation of HostImportModuleDynamically must conform to the following requirements:
It must return unused. Success or failure must instead be signaled as discussed below.
The host environment must conform to one of the two following sets of requirements:
Success path
At some future time, the host environment must perform FinishDynamicImport(referencingScriptOrModule, specifier, promiseCapability, promise), where promise is a Promise resolved with undefined.
At some future time, the host environment must perform FinishDynamicImport(referencingScriptOrModule, specifier, promiseCapability, promise), where promise is a Promise rejected with an error representing the cause of failure.
If the host environment takes the success path once for a given referencingScriptOrModule, specifier pair, it must always do so for subsequent calls.
The operation must not call promiseCapability.[[Resolve]] or promiseCapability.[[Reject]], but instead must treat promiseCapability as an opaque identifying value to be passed through to FinishDynamicImport.
The actual process performed is host-defined, but typically consists of performing whatever I/O operations are necessary to allow HostResolveImportedModule to synchronously retrieve the appropriate Module Record, and then calling its Evaluate concrete method. This might require performing similar normalization as HostResolveImportedModule does.
The abstract operation FinishDynamicImport takes arguments referencingScriptOrModule, specifier, promiseCapability (a PromiseCapability Record), and innerPromise and returns unused. FinishDynamicImport completes the process of a dynamic import originally started by an import() call, resolving or rejecting the promise returned by that call as appropriate according to innerPromise's resolution. It is performed by host environments as part of HostImportModuleDynamically. It performs the following steps when called:
Let fulfilledClosure be a new Abstract Closure with parameters (result) that captures referencingScriptOrModule, specifier, and promiseCapability and performs the following steps when called:
The abstract operation GetImportedModule takes arguments referrer (a Cyclic Module Record) and specifier (a String) and returns a Module Record or empty. It performs the following steps when called:
If referrer.[[LoadedModules]] contains a Recordrecord such that record.[[Specifier]] is specifier, then
If this operation is called multiple times with the same (referrer, specifier) pair and it performs FinishLoadImportedModule(referrer, specifier, payload, result) where result is a normal completion, then it must perform FinishLoadImportedModule(referrer, specifier, payload, result) with the same result each time.
The operation must treat payload as an opaque value to be passed through to FinishLoadImportedModule.
The actual process performed is host-defined, but typically consists of performing whatever I/O operations are necessary to load the appropriate Module Record. Multiple different (referrer, specifier) pairs may map to the same Module Record instance. The actual mapping semantic is host-defined but typically a normalization process is applied to specifier as part of the mapping process. A typical normalization process would include actions such as expansion of relative and abbreviated path specifiers.
16.2.1.12 FinishLoadImportedModule ( referrer, specifier, payload, result )
All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.