The GetBindingValue concrete method of a Module Environment RecordenvRec takes arguments name (a String) and strict (a Boolean) and returns either a normal completion containing an ECMAScript language value or a throw completion. It returns the value of its bound identifier whose name is name. However, if the binding is an indirect binding the value of the target binding is returned. If the binding exists but is uninitialized a ReferenceError is thrown. It performs the following steps when called:
The abstract operation CreateDeferredInitializationBinding takes arguments envRec (a Module Environment Record), name (a String), and initializationSteps (an Abstract Closure that takes no arguments and returns an ECMAScript language value) and returns unused. It creates a deferred initialization binding (a binding that is automatically initialized on first access) for the name name. A binding must not already exist in envRec for name. It performs the following steps when called:
Assert: envRec does not already have a binding for name.
Create an imutable deferred initialization binding in envRec for name whose deferred initialization steps is initializationSteps, and record that the binding is uninitialized and that it is a strict binding.
Return unused.
10 Ordinary and Exotic Objects Behaviours
10.4 Built-in Exotic Object Internal Methods and Slots
This specification defines several kinds of built-in exotic objects. These objects generally behave similar to ordinary objects except for a few specific situations. The following exotic objects use the ordinary object internal methods except where it is explicitly specified otherwise below:
10.4.6 Module Namespace Exotic Objects
A module namespace exotic object is an exotic object that exposes the bindings exported from an ECMAScript Module (See 16.2.3). There is a one-to-one correspondence between the String-keyed own properties of a module namespace exotic object and the binding names exported by the Module. The exported bindings include any bindings that are indirectly exported using export * export items. Each String-valued own property key is the StringValue of the corresponding exported binding name. These are the only String-keyed properties of a module namespace exotic object. Each such property has the attributes { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: false }. Module namespace exotic objects are not extensible.
An object is a module namespace exotic object if its [[GetPrototypeOf]], [[SetPrototypeOf]], [[IsExtensible]], [[PreventExtensions]], [[GetOwnProperty]], [[DefineOwnProperty]], [[HasProperty]], [[Get]], [[Set]], [[Delete]], and [[OwnPropertyKeys]] internal methods use the definitions in this section, and its other essential internal methods use the definitions found in 10.1. These methods are installed by ModuleNamespaceCreate.
ResolveExport is side-effect free. Each time this operation is called with a specific exportName, resolveSet pair as arguments it must return the same result. An implementation might choose to pre-compute or cache the ResolveExport results for the [[Exports]] of each module namespace exotic object.
The abstract operation ModuleNamespaceCreate takes arguments module (a Module Record), exports (a List of Strings), and phase (defer or evaluation) and returns a module namespace exotic object. It is used to specify the creation of new module namespace exotic objects. It performs the following steps when called:
Let internalSlotsList be the internal slots listed in Table 1.
Create an own data property of M named %Symbol.toStringTag% whose [[Value]] is toStringTag and whose [[Writable]], [[Enumerable]], and [[Configurable]] attributes are false.
Return M.
13 ECMAScript Language: Expressions
13.3 Left-Hand-Side Expressions
13.3.10 Import Calls
13.3.10.1 EvaluateImportCall ( arguments, phase )
The abstract operation EvaluateImportCall takes arguments arguments (a Parse Node) and phase (defer or evaluation) and returns either a normal completion containing a Promise or an abrupt completion. It performs the following steps when called:
Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
Return promiseCapability.[[Promise]].
Sort attributes according to the lexicographic order of their [[Key]] field, treating the value of each such field as a sequence of UTF-16 code unit values. NOTE: This sorting is observable only in that hosts are prohibited from changing behaviour based on the order in which attributes are enumerated.
Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Attributes]]: attributes, [[Phase]]: phase, [[ImportedNames]]: all }.
The abstract operation ContinueDynamicImport takes arguments promiseCapability (a PromiseCapability Record), moduleCompletion (either a normal completion containing a Module Record or a throw completion), and phase (defer or evaluation) and returns unused. It completes the process of a dynamic import originally started by an import() call, resolving or rejecting the promise returned by that call as appropriate. It performs the following steps when called:
Let linkAndEvaluateClosure be a new Abstract Closure with no parameters that captures module, promiseCapability, phase and onRejected and performs the following steps when called:
Let fulfilledClosure be a new Abstract Closure with no parameters that captures module, phase, and promiseCapability and performs the following steps when called:
Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « », [[Phase]]: evaluation, [[ImportedNames]]: importedNames }.
Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: evaluation, [[ImportedNames]]: importedNames }.
Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « », [[Phase]]: defer, [[ImportedNames]]: importedNames }.
Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: defer, [[ImportedNames]]: importedNames }.
Return the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: evaluation, [[ImportedNames]]: importedNames }.
16.2.1.5 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 2. 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.
The abstract method LoadRequestedModules takes optional arguments importedNames (all, all-but-default, or a List of Strings) and hostDefined (anything) and returns a Promise.
It prepares the module for linking by recursively loading all its dependencies.
The abstract method ResolveExport takes argument exportName (a String) and optional arguments resolveSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)) and deferNamespaceExportSet (a List of Module Records) and returns a ResolvedBinding Record, null, or ambiguous.
It returns the binding of a name exported by this module. Bindings are represented by ResolvedBinding Recordsa ResolvedBinding Record, of the form { [[Module]]: Module Record, [[BindingName]]: String | namespace| ~deferred-namespace~ }. If the export is a Module Namespace Object without a direct binding in any module, [[BindingName]] will be set to ~namespace~ or ~deferred-namespace~ (depending on whether the binding comes from a deferred import or not). It returns null if the name cannot be resolved, or ambiguous if multiple bindings were found.
Each time this operation is called with a specific exportName, resolveSet pair as arguments it must return the same result.
LoadRequestedModules must have completed successfully prior to invoking this method.
Within this specification it has definitions in the following types; hosts may provide additional types with their own definitions:
LoadRequestedModules must have completed successfully prior to invoking this method, with an importNames list that includes at least the importedNames passed to Link.
Within this specification it has definitions in the following types; hosts may provide additional types with their own definitions:
The abstract method Evaluate takes optional argument importedNames (all, all-but-default, or a List of Strings) and returns a Promise.
It 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. Unless this module is a Cyclic Module Record, the returned promise must be already settled.
Link must have completed successfully prior to invoking this method, with an importNames list that includes at least the importedNames passed to Evaluate.
Within this specification it has definitions in the following types; hosts may provide additional types with their own definitions:
The abstract operation EvaluateModuleSync takes argument module (a Module Record) and optional argument importedNames (all, all-but-default, or a List of Strings) and returns either a normal completion containingunused or a throw completion. It synchronously evaluates module, provided that the caller guarantees that module's evaluation will return an already settled promise. It performs the following steps when called:
If importedNames is not present, set importedNames to « ».
If ReadyForSyncExecution(module, importedNames) is false, throw a TypeError exception.
16.2.1.5.1.1 ReadyForSyncExecution ( module, importedNames [ , seen ] )
The abstract operation ReadyForSyncExecution takes arguments module (a Module Record) and importedNames (all, all-but-default, or a List of Strings) and optional argument seen (a List of Module Records) and returns a Boolean. It tests whether a given (module, importedNames) pair can be safely evaluated through EvaluateModuleSync. It performs the following steps when called:
If ReadyForSyncExecution(requiredModule, request.[[ImportedNames]], seen) is false, then
Return false.
Return true.
16.2.1.6 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 new. 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.
Auxiliary field used during Link and Evaluate only. If [[Status]] is either linking or evaluating, this is either the module's depth-first traversal index or that of an "earlier" module in the same strongly connected component.
A map from the specifier strings used by the module represented by this record to request the importation of a module with the relative import attributes to the resolved Module Record. The list does not contain two different Recordsr1 and r2 such that ModuleRequestsKeyEqual(r1, r2) is true.
The first visited module of the cycle, the root DFS ancestor of the strongly connected component. For a module not in a cycle, this would be the module itself. Once Evaluate has completed, a module's [[DFSAncestorIndex]] is the depth-first traversal index of its [[CycleRoot]].
[[HasTLA]]
a Boolean
Whether this module is individually asynchronous (for example, if it's a Source Text Module Record containing a top-level await). Having an asynchronous dependency does not mean this field is true. This field must not change after the module is parsed.
This field is initially set to unset, and remains unset for fully synchronous modules. For modules that are either themselves asynchronous or have an asynchronous dependency, it is set to an integer that determines the order in which execution of pending modules is queued by 16.2.1.6.1.3.4. Once the pending module is executed, the field is set to done.
If this module is the [[CycleRoot]] of some cycle, and Evaluate() was called on some module in that cycle, this field contains the PromiseCapability Record for that entire evaluation. It is used to settle the Promise object that is returned from the Evaluate() abstract method. This field will be empty for any dependencies of that module, unless a top-level Evaluate() has been initiated for some of those dependencies.
If this module or a dependency has [[HasTLA]]true, and execution is in progress, this tracks the parent importers of this module for the top-level execution job. These parent modules will not start executing before this module has successfully completed execution.
If this module has any asynchronous dependencies, this tracks the number of asynchronous dependency modules remaining to execute for this module. A module with asynchronous dependencies will be executed when this field reaches 0 and there are no execution errors.
It evaluates the module's code within its execution context. If this module has true in [[HasTLA]], then a PromiseCapability Record is passed as an argument, and the method is expected to resolve or reject the given capability. In this case, the method must not throw an exception, but instead reject the PromiseCapability Record if necessary.
Within this specification it has definitions in the following types; hosts may provide additional types with their own definitions:
The abstract method GetOptionalIndirectExportsModuleRequests takes optional argument importedNames (all, all-but-default, or a List of Strings) and returns a List of ModuleRequest Records.
It computes the Module Requests for the additional dependencies (not already listed in this module's [[RequestedModules]]) needed to be able to import importedNames from this module. In case of a Source Text Module Record, these would be the dependencies specified through export defer.
This abstract method has the following default implementation:
A GraphLoadingState 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 GraphLoadingState Record has the fields defined in Table 7:
It is a list of the Cyclic Module Records that have been already loaded by the current loading process, together with the list of bindings that have already been imported from them, to avoid infinite loops with circular dependencies.
The LoadRequestedModules concrete method of a Cyclic Module Recordmodule takes optional arguments importedNames (all, all-but-default, or a List of Strings) and hostDefined (anything) and returns a Promise. It populates the [[LoadedModules]] of all the Module 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 importedNames is not present, set importedNames to all.
If hostDefined is not present, set hostDefined to empty.
Let state be the GraphLoadingState Record { [[IsLoading]]: true, [[PendingModulesCount]]: 1, [[Visited]]: « », [[PromiseCapability]]: pc, [[HostDefined]]: hostDefined }.
When the exports of the module are not observed, such as in <script type="module" src="./file.js"> tags, the host should set the importedNames parameter to « ».
Note 2
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.
import() expressions never set the hostDefined parameter.
The abstract operation InnerModuleLoading takes arguments state (a GraphLoadingState Record), module (a Module Record), and importedNames (all, all-but-default, or a List of Strings) 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 optional argument importedNames (all, all-but-default, or a List of Strings) 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 one of unlinked, linked, evaluating-async, or evaluated.
If importedNames is not present, set importedNames to all.
Assert: requiredModule.[[Status]] is one of unlinked, linked, evaluating-async, or evaluated.
If requiredModule.[[Status]] is unlinked, perform ? requiredModule.Link(request.[[ImportedNames]]).
Return unused.
16.2.1.6.2.1 InnerModuleLinking ( module, stack, index )
The abstract operation InnerModuleLinking takes arguments module (a Module Record), stack (a List of Cyclic Module Records), 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 [[DFSAncestorIndex]] field, 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:
The abstract operation BuildLinkingList takes arguments linkingList (a List of Module Records), referrer (a Cyclic Module Record), moduleRequests (a List of ModuleRequest Records), and previouslyImportedNames (a List of Records with fields [[Module]] (a Cyclic Module Record) and [[ImportedNames]] (all, all-but-default, or a List of Strings)) and returns unused. It performs the following steps when called:
The Evaluate concrete method of a Cyclic Module Recordmodule takes optional argument importedNames (all, all-but-default, or a List of Strings) and returns a Promise. Evaluate transitions this module's [[Status]] from linked to either evaluating-async or evaluated. The first time it is called on a module in a given strongly connected component, Evaluate creates and returns a Promise which resolves when the module has finished evaluating. This Promise is stored in the [[TopLevelCapability]] field of the [[CycleRoot]] for the component. Future invocations of Evaluate on any module in the component return the same Promise. (Most of the work is done by the auxiliary function InnerModuleEvaluation.) It performs the following steps when called:
Assert: None of module or any of its recursive dependencies have [[Status]] set to evaluating, linking, unlinked, or new.
Assert: module.[[Status]] is one of linked, evaluating-async, or evaluated.
If importedNames is not present, set importedNames to « ».
If module.[[Status]] is either evaluating-async or evaluated, set module to module.[[CycleRoot]].
If module.[[TopLevelCapability]] is not empty, then
Return module.[[TopLevelCapability]].[[Promise]].
If module.[[Status]] is either evaluating-async or evaluated, then
Assert: module.[[CycleRoot]].[[TopLevelCapability]] is not empty.
Let topLevelPromise be module.[[CycleRoot]].[[TopLevelCapability]].[[Promise]].
Else,
Assert: module.[[CycleRoot]] and module.[[TopLevelCapability]] are empty.
Assert: requiredModule.[[Status]] is one of linked, evaluating-async, or evaluated.
Let innerPromise be requiredModule.Evaluate(request.[[ImportedNames]]).
If innerPromise.[[PromiseState]] is rejected, return innerPromise.
Append innerPromise to promises.
If promises contains a Promise P such that P.[[PromiseState]] is pending, then
NOTE: If all modules in the graph are synchronous, the usage of promises is an internal specification detail. In that case, we do not use SafePerformPromiseAll to keep returning an already settled promise.
16.2.1.6.3.1 InnerModuleEvaluation ( module, stack, index )
The abstract operation InnerModuleEvaluation takes arguments module (a Module Record), stack (a List of Cyclic Module Records), 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 [[DFSAncestorIndex]] field, are used the same way as in InnerModuleLinking. It performs the following steps when called:
Assert: requiredModule.[[AsyncEvaluationOrder]] is either an integer or unset.
If requiredModule.[[AsyncEvaluationOrder]] is unset, set requiredModule.[[Status]] to evaluated.
Otherwise, set requiredModule.[[Status]] to evaluating-async.
If requiredModule and module are the same Module Record, set done to true.
Set requiredModule.[[CycleRoot]] to module.
Return index.
Note 1
A module is evaluating while it is being traversed by InnerModuleEvaluation. A module is evaluated on execution completion or evaluating-async during execution if its [[HasTLA]] field is true or if it has asynchronous dependencies.
Note 2
Any modules depending on a module of an asynchronous cycle when that cycle is not evaluating will instead depend on the execution of the root of the cycle via [[CycleRoot]]. This ensures that the cycle state can be treated as a single strongly connected component through its root module state.
The abstract operation BuildEvaluationList takes arguments evaluationList (a list of Module Records), referrer (a Cyclic Module Record), and moduleRequests (a List of ModuleRequest Records) and returns unused. It performs the following steps when called:
Step 1.d.ii is true when there's import *. For such case, only asynchronous transitive dependencies of modules loaded through export defer are evaluated at this point, while synchronous dependecies should not be evaluated. They will be evaluated by the module namespace exotic object[[Get]] internal method, upon access of the corresponding binding.
Note 2
Unlike BuildLinkingList, this operation does not need to keep track of which names have already been imported from a given module. Module graphs where two modules have a recursive export defer between each other that would cause an infinite loop already fail when linking.
16.2.1.6.3.2.1 ListAppendUnique ( list1, list2 )
The abstract operation ListAppendUnique takes arguments list1 (a List of Records) and list2 (a List of Records) and returns unused. It performs the following steps when called:
16.2.1.6.3.3 GatherAsynchronousTransitiveDependencies ( module [ , seen ] )
The abstract operation GatherAsynchronousTransitiveDependencies takes argument module (a Module Record) and optional argument seen (a List of Module Records) and returns a List of Module Records. Collects the direct post-order list of asynchronous unexecuted transitive dependencies, stopping the depth-first search for a branch when an asynchronous dependency is found. It performs the following steps when called:
If seen is not present, set seen to a new empty List.
16.2.1.6.3.3.1 GatherAsynchronousTransitiveDependenciesForRequests ( referrer, moduleRequests, seen )
The abstract operation GatherAsynchronousTransitiveDependenciesForRequests takes arguments referrer (a Cyclic Module Record), moduleRequests (a List of ModuleRequest Records), and seen (a List of Module Records) and returns a List of Module Records. Collects the direct post-order list of asynchronous unexecuted transitive dependencies, stopping the depth-first search for a branch when an asynchronous dependency is found. It performs the following steps when called:
The abstract operation GetNewOptionalIndirectExportsModuleRequests takes arguments module (a Cyclic Module Record), importedNames (all, all-but-default, or a List of Strings), and previouslyImportedNames (a List of Records with fields [[Module]] (a Cyclic Module Record) and [[ImportedNames]] (all, all-but-default, or a List of Strings)) and returns a List of ModuleRequest Records. It performs the following steps when called:
Assert: previouslyImportedNames contains a Record whose [[Module]] field is module.
Let previous be the Record in previouslyImportedNames whose [[Module]] field is module.
Let newImportedNames be ExcludeImportedNames(importedNames, previous.[[ImportedNames]]).
Set previous.[[ImportedNames]] to MergeImportedNames(previous.[[ImportedNames]], newImportedNames).
A Source Text Module Record is used to represent information about a module that was defined from ECMAScript source text (11) that was parsed using the goal symbolModule. Its fields contain digested information about the names that are imported and exported by the module, and its concrete methods use these digests to link and evaluate the module.
A List of ExportEntry records derived from the code of this module that correspond to reexported imports that occur within the module or exports from export * as namespace declarations.
A List of ExportEntry records derived from the code of this module that correspond to export * declarations that occur within the module, not including export * as namespace declarations.
A list of all the bindings re-exported through export defer { ... } from "...". The List is in source text occurrence order.
An ImportEntry Record is a Record that digests information about a single declarative import. Each ImportEntry Record has the fields defined in Table 9:
a String, namespace-object, or filtered-namespace-object
The name under which the desired binding is exported by the module identified by [[ModuleRequest]]. The value namespace-object indicates that the import request is for the target module's namespace object, and the value filtered-namespace-object indicates that the import request is for a filtered namespace created from the module.
[[LocalName]]
a String
The name that is used to locally access the imported value from within the importing module.
When [[ImportName]] is filtered-namespace-object, this field contains the list of export names to include in the namespace object. For all other values of [[ImportName]], this field is empty.
Note 1
Table 10 gives examples of ImportEntry records fields used to represent the syntactic import forms:
An ExportEntry Record is a Record that digests information about a single declarative export. Each ExportEntry Record has the fields defined in Table 11:
a String, null, namespace, filtered-namespace, or all-but-default
The name under which the desired binding is exported by the module identified by [[ModuleRequest]]. null if the ExportDeclaration does not have a ModuleSpecifier. namespace is used for export * as ns from "mod" declarations. all-but-default is used for export * from "mod" declarations. filtered-namespace is used for export {x, y} as ns from "mod" declarations where only selected exports are included in the namespace.
[[LocalName]]
a String or null
The name that is used to locally access the exported value from within the importing module. null if the exported value is not locally accessible from within the module.
When [[ImportName]] is filtered-namespace, this field contains the list of export names to include in the namespace object. For all other values of [[ImportName]], this field is empty.
Note 2
Table 12 gives examples of the ExportEntry record fields used to represent the syntactic export forms:
If importedBoundNames does not contain ee.[[LocalName]], then
Append ee to localExportEntries.
Else,
NOTE: When exporting a binding or namespace object which was originally imported from another module, the ExportEntry Record is rewritten to match the form it would have if the binding or namespace object had been re-exported directly from the original module rather than imported then exported. This allows conflicts which arise from exporting the same binding or namespace twice under the same name through export * from to be ignored rather than being treated as ambiguous in step 12.f.iii of the ResolveExport concrete method of Source Text Module Records.
Let ie be the element of importEntries whose [[LocalName]] is ee.[[LocalName]].
If ie.[[ImportName]] is namespace-object, then
NOTE: This is a re-export of an imported module namespace object.
Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: namespace, [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } to indirectExportEntries.
Else if ie.[[ImportName]] is filtered-namespace-object, then
NOTE: This is a re-export of an imported filtered namespace object.
Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: filtered-namespace, [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]], [[NamespaceNamesFilter]]: ie.[[NamespaceNamesFilter]] } to indirectExportEntries.
Let allNamedExportEntries be the list-concatenation of module.[[LocalExportEntries]], module.[[IndirectExportEntries]], and module.[[OptionalIndirectExportEntries]].
For each ExportEntry Recorde of module.[[LocalExportEntries]]allNamedExportEntries, do
Assert: module provides the direct binding for this export.
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, the request is found to be circular, or if it resolves to a deferred namespace declared through export defer * as ... whose corresponding module has a non-resolvable export defer declaration, null is returned.
If module.[[OptionalIndirectExportEntries]] contains e and NamespaceMemberIsUnresolvableOptional(deferNamespaceExportSet, module, exportName, importedModule, importedModule.GetExportedNames(), allow-ambiguous) is true, return null.
If e.[[ModuleRequest]].[[Phase]] is defer, then
Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: deferred-namespace }.
Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
Else if e.[[ImportName]] is filtered-namespace, then
Assert: e.[[NamespaceNamesFilter]] is a List of Strings.
If module.[[OptionalIndirectExportEntries]] contains e and NamespaceMemberIsUnresolvableOptional(deferNamespaceExportSet, module, exportName, importedModule, e.[[NamespaceNamesFilter]], disallow-ambiguous) is true, return null.
NOTE: export { ... } as ns from "mod" introduces a local internal binding in the module that contains the ExportDeclaration. That binding is created by InitializeEnvironment.
Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
Let resolution be importedModule.ResolveExport(exportName, resolveSet, deferNamespaceExportSet).
If resolution is ambiguous, return ambiguous.
NOTE: If resolution is null because of an export defer declaration that re-exports a non-resolvable binding, it causes a SyntaxError to be thrown while linking importedModule itself.
Assert: There is more than one * export that includes the requested name.
If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return ambiguous.
If resolution.[[BindingName]] is not starResolution.[[BindingName]] and either resolution.[[BindingName]] or starResolution.[[BindingName]] is namespace, return ambiguous.
If resolution.[[BindingName]]is a String, starResolution.[[BindingName]]is a String, and resolution.[[BindingName]] is not starResolution.[[BindingName]], return ambiguous.
The abstract operation ResolveSetContains takes arguments resolveSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)), module (a Module Record), and exportName (a String) and returns a Boolean. It checks whether resolveSet contains a Record whose [[Module]] is module and whose [[ExportName]] is exportName. It performs the following steps when called:
For each Record { [[Module]], [[ExportName]] } r of resolveSet, do
If r.[[Module]] is module and r.[[ExportName]] is exportName, then
The abstract operation NamespaceMemberIsUnresolvableOptional takes arguments deferNamespaceExportSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)), reexporterModule (a Module Record), exportName (a String), namespaceModule (a Module Record), namespaceNames (a List of Strings), and onAmbiguous (allow-ambiguous or disallow-ambiguous) and returns a Boolean. It performs the following steps when called:
If ResolveSetContains(deferNamespaceExportSet, reexporterModule, exportName) is true, return false.
Append the Record { [[Module]]: reexporterModule, [[ExportName]]: exportName } to deferNamespaceExportSet.
NOTE: All exports of importedModule other than export defer ones are also validated by the InitializeEnvironment call on importedModule itself, and it is not observable which of the two InitializeEnvironment calls throws the SyntaxError.
If name is not "default", perform ? EnsureResolvableBinding(importedModule, name, disallow-ambiguous).
Assert: All named exports from module are resolvable.
NOTE: All exports of importedModule other than export defer ones are also validated by the InitializeEnvironment call on importedModule itself, and it is not observable which of the two InitializeEnvironment calls throws the SyntaxError.
NOTE: The localName binding of export defer { ...} as ns from "mod" is initialized on first access, as whether the corresponding module is available or not depends on module's importers. If any of module's importers causes this binding to be imported, they will also validate it through EnsureResolvableBinding.
The abstract operation EnsureResolvableBinding takes arguments module (a Module Record), name (a String), and onAmbiguous (allow-ambiguous or disallow-ambiguous) and returns either a normal completion containingunused, or a throw completion. It throws an error if module does not have unabiguous exports for all names. It performs the following steps when called:
If existingRequest is empty and ModuleRequestsKeyEqual(r, nextRequest) is true and r.[[Phase]] is nextRequest.[[Phase]], then
Set existingRequest to r.
Let newImportedNames be all.
Assert: oie.[[ImportName]]is a String, filtered-namespace, or namespace.
If oie.[[ImportName]]is a String, set newImportedNames to « oie.[[ImportName]] ».
If oie.[[ImportName]] is filtered-namespace, set newImportedNames to oie.[[NamespaceNamesFilter]].
If existingRequest is empty, then
Let request be the ModuleRequest Record { [[Specifier]]: nextRequest.[[Specifier]], [[Attributes]]: nextRequest.[[Attributes]], [[Phase]]: nextRequest.[[Phase]], [[ImportedNames]]: newImportedNames }.
Append request to requests.
Else,
Set existingRequest.[[ImportedNames]] to MergeImportedNames(existingRequest.[[ImportedNames]], newImportedNames).
Return requests.
16.2.1.11 FinishLoadingImportedModule ( referrer, moduleRequest, payload, result )
Append the LoadedModuleRequest Record { [[Specifier]]: moduleRequest.[[Specifier]], [[Attributes]]: moduleRequest.[[Attributes]], [[Module]]: result.[[Value]] } to referrer.[[LoadedModules]].
The abstract operation GetModuleNamespace takes arguments module (an instance of a concrete subclass of Module Record), phase (defer or evaluation), and importedNames (all or a List of Strings) and returns a Module Namespace Object. It retrieves the Module Namespace Object representing module's exports, lazily creating it the first time it was requested, and if importedNames is all storing it in module.[[Namespace]] for future retrieval. It performs the following steps when called:
If phase is defer, set module.[[DeferredNamespace]] to namespace.
Else, set module.[[Namespace]] to namespace.
Return namespace.
Note
GetModuleNamespace never throws. Instead, unresolvable names are simply excluded from the namespace at this point. They will lead to a real linking error later unless they are all ambiguous star exports that are not explicitly requested anywhere.
Let defaultEntry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: "default", [[LocalName]]: localName, [[NamespaceNamesFilter]]: empty }.
Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace-object, [[LocalName]]: localName, [[NamespaceNamesFilter]]: empty }.
Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: filtered-namespace-object, [[LocalName]]: localName, [[NamespaceNamesFilter]]: importedNames }.
Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: localName, [[LocalName]]: localName, [[NamespaceNamesFilter]]: empty }.
Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[NamespaceNamesFilter]]: empty }.
Return « entry ».
16.2.2.4 Static Semantics: ImportedNames
The syntax-directed operation ImportedNames takes no arguments and returns all, all-but-default, or a List of unique Strings. It is defined piecewise over the following productions:
The abstract operation MergeImportedNames takes arguments a (all, all-but-default, or a List of Strings) and b (all, all-but-default, or a List of Strings) and returns all, all-but-default, or a List of Strings. It performs the following steps when called:
If a is all or b is all, return all.
If a is all-but-default and b is a List of Strings that contains "default", return all.
If b is all-but-default and a is a List of Strings that contains "default", return all.
If a is all-but-default or b is all-but-default, return all-but-default.
The abstract operation ExcludeImportedNames takes arguments a (all, all-but-default, or a List of Strings) and b (all, all-but-default, or a List of Strings) and returns all, all-but-default, or a List of Strings. It returns the minimal set of imported names that is guaranteed to include all the names present in a but not in b. It performs the following steps when called:
The syntax-directed operation FilteredNamespaceNames takes no arguments and returns a List of Strings. It is defined piecewise over the following productions:
Return a List whose sole element is a new ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default", [[NamespaceNamesFilter]]: empty }.
Return a List whose sole element is a new ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default", [[NamespaceNamesFilter]]: empty }.
Let entry be the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: "*default*", [[ExportName]]: "default", [[NamespaceNamesFilter]]: empty }.
Return « entry ».
Note
"*default*" is used within this specification as a synthetic name for anonymous default export values. See this note for more details.
Let entry be the ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: all-but-default, [[LocalName]]: null, [[ExportName]]: null, [[NamespaceNamesFilter]]: empty }.
Let entry be the ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: null, [[ExportName]]: exportName, [[NamespaceNamesFilter]]: empty }.
Let entry be the ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: filtered-namespace, [[LocalName]]: null, [[ExportName]]: exportName, [[NamespaceNamesFilter]]: importedNames }.
Return a List whose sole element is a new ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[ExportName]]: sourceName, [[NamespaceNamesFilter]]: empty }.
Return a List whose sole element is a new ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[ExportName]]: exportName, [[NamespaceNamesFilter]]: empty }.
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.