Stage 2 Draft / August 7, 2025

Deferred re-exports

NOTE: The diff markers are on top of https://tc39.es/proposal-defer-import-eval/.

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.

Module namespace exotic objects have the internal slots defined in Table 1.

10.4.6.8 [[Get]] ( P, Receiver )

The [[Get]] internal method of a module namespace exotic object O takes arguments P (a property key) and Receiver (an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. If IsSymbolLikeNamespaceKey(P, O), return ! OrdinaryGet(O, P, Receiver).
  2. Let exports be ? GetModuleExportsList(O).
  3. If exports does not contain P, return undefined.
  4. Let m be O.[[Module]].
  5. Let binding be m.ResolveExport(P).
  6. TODO: The line above should also get a list of intermediate modules to evaluate.
  7. Assert: binding is a ResolvedBinding Record.
  8. Let targetModule be binding.[[Module]].
  9. Assert: targetModule is not undefined.
  10. If binding.[[BindingName]] is namespace, then
    1. Return GetModuleNamespace(targetModule, evaluation).
    2. NOTE: The phase here is always evaluation because in import defer * as x from "..."; export { x }, binding.[[BindingName]] is "x" and not namespace.
  11. Let targetEnv be targetModule.[[Environment]].
  12. If targetEnv is empty, throw a ReferenceError exception.
  13. Return ? targetEnv.GetBindingValue(binding.[[BindingName]], true).
Note

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.

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:

  1. Let referrer be GetActiveScriptOrModule().
  2. If referrer is null, set referrer to the current Realm Record.
  3. Let specifier be ? EvaluateImportCallSpecifier of arguments.
  4. Let options be ? EvaluateImportCallOptions of arguments.
  5. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  6. Let specifierString be Completion(ToString(specifier)).
  7. IfAbruptRejectPromise(specifierString, promiseCapability).
  8. Let attributes be a new empty List.
  9. If options is not undefined, then
    1. If options is not an Object, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    2. Let attributesObj be Completion(Get(options, "with")).
    3. IfAbruptRejectPromise(attributesObj, promiseCapability).
    4. If attributesObj is not undefined, then
      1. If attributesObj is not an Object, then
        1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
        2. Return promiseCapability.[[Promise]].
      2. Let entries be Completion(EnumerableOwnProperties(attributesObj, key+value)).
      3. IfAbruptRejectPromise(entries, promiseCapability).
      4. For each element entry of entries, do
        1. Let key be ! Get(entry, "0").
        2. Let value be ! Get(entry, "1").
        3. If key is a String, then
          1. If value is not a String, then
            1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
            2. Return promiseCapability.[[Promise]].
          2. Append the ImportAttribute Record { [[Key]]: key, [[Value]]: value } to attributes.
    5. If AllImportAttributesSupported(attributes) is false, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    6. 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.
  10. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Attributes]]: attributes, [[Phase]]: phase, [[ImportedNames]]: all }.
  11. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
  12. Return promiseCapability.[[Promise]].

13.3.10.1.1 ContinueDynamicImport ( promiseCapability, moduleCompletion, phase )

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:

  1. If moduleCompletion is an abrupt completion, then
    1. Perform ! Call(promiseCapability.[[Reject]], undefined, « moduleCompletion.[[Value]] »).
    2. Return unused.
  2. Let module be moduleCompletion.[[Value]].
  3. Let loadPromise be module.LoadRequestedModules(all).
  4. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures promiseCapability and performs the following steps when called:
    1. Perform ! Call(promiseCapability.[[Reject]], undefined, « reason »).
    2. Return unused.
  5. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
  6. Let linkAndEvaluateClosure be a new Abstract Closure with no parameters that captures module, promiseCapability, phase and onRejected and performs the following steps when called:
    1. Let link be Completion(module.Link(TODO: all?)).
    2. If link is an abrupt completion, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « link.[[Value]] »).
      2. Return unused.
    3. Let fulfilledClosure be a new Abstract Closure with no parameters that captures module, phase, and promiseCapability and performs the following steps when called:
      1. Let namespace be GetModuleNamespace(module, phase).
      2. Perform ! Call(promiseCapability.[[Resolve]], undefined, « namespace »).
      3. Return unused.
    4. If phase is defer, then
      1. Let evaluationList be GatherAsynchronousTransitiveDependencies(module).
      2. If evaluationList is empty, then
        1. Perform fulfilledClosure().
        2. Return unused.
      3. Let asyncDepsEvaluationPromises be a new empty List.
      4. For each Module Record dep of evaluationList, append dep.Evaluate() to asyncDepsEvaluationPromises.
      5. Let iterator be CreateListIteratorRecord(asyncDepsEvaluationPromises).
      6. Let pc be ! NewPromiseCapability(%Promise%).
      7. Let evaluatePromise be ! PerformPromiseAll(iterator, %Promise%, pc, %Promise.resolve%).
    5. Else,
      1. Assert: phase is evaluation.
      2. Let evaluatePromise be module.Evaluate().
    6. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, "", 0, « »).
    7. Perform PerformPromiseThen(evaluatePromise, onFulfilled, onRejected).
    8. Return unused.
  7. Let linkAndEvaluate be CreateBuiltinFunction(linkAndEvaluateClosure, "", 0, « »).
  8. Perform PerformPromiseThen(loadPromise, linkAndEvaluate, onRejected).
  9. Return unused.

16 ECMAScript Language: Scripts and Modules

16.2 Modules

Syntax

Module : ModuleBodyopt ModuleBody : ModuleItemList ModuleItemList : ModuleItem ModuleItemList ModuleItem ModuleItem : ImportDeclaration ExportDeclaration StatementListItem[~Yield, +Await, ~Return] ModuleExportName : IdentifierName StringLiteral

16.2.1 Module Semantics

16.2.1.1 ModuleRequest Records

A ModuleRequest Record represents the request to import a module with given import attributes and import phase. It consists of the following fields:

Table 1: ModuleRequest Record Fields
Field Name Value Type Meaning
[[Specifier]] a String The module specifier
[[Attributes]] a List of ImportAttribute Records The import attributes
[[Phase]] defer or evaluation The target import phase
[[ImportedNames]] all or a List of Strings The list of names imported from the requested module, used for filtering export defer declarations.

16.2.1.3 Static Semantics: ModuleRequests

The syntax-directed operation ModuleRequests takes no arguments and returns a List of ModuleRequest Records. It is defined piecewise over the following productions:

Module : [empty]
  1. Return a new empty List.
ModuleItemList : ModuleItem
  1. Return ModuleRequests of ModuleItem.
ModuleItemList : ModuleItemList ModuleItem
  1. Let requests be the ModuleRequests of ModuleItemList.
  2. Let additionalRequests be the ModuleRequests of ModuleItem.
  3. For each ModuleRequest Record mr of additionalRequests, do
    1. Let existingRequest be empty.
    2. For each ModuleRequests Record mr2 of additionalRequests, do
      1. If ModuleRequestsEqual(mr, mr2) is true and mr.[[Phase]] is mr2.[[Phase]], then
        1. Assert: existingRequest is empty.
        2. Set existingRequest to mr2.
    3. If requests does not contain a ModuleRequest Record mr2 such that ModuleRequestsEqual(mr, mr2) is true and mr.[[Phase]] is mr2.[[Phase]], then
    4. If existingRequest is empty, then
      1. Append mr to requests.
    5. Else,
      1. Set existingRequest.[[ImportedNames]] to MergeImportedNames(existingRequest.[[ImportedNames]], mr.[[ImportedNames]]).
  4. Return requests.
ModuleItem : StatementListItem
  1. Return a new empty List.
ImportDeclaration : import ImportClause FromClause ;
  1. Let specifier be the SV of FromClause.
  2. Let importedNames be ImportedNames of ImportClause.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « », [[Phase]]: evaluation, [[ImportedNames]]: importedNames }.
ImportDeclaration : import ImportClause FromClause WithClause ;
  1. Let specifier be the SV of FromClause.
  2. Let attributes be WithClauseToAttributes of WithClause.
  3. Let importedNames be ImportedNames of ImportClause.
  4. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: evaluation, [[ImportedNames]]: importedNames }.
ImportDeclaration : import defer NameSpaceImport FromClause ;
  1. Let specifier be SV of FromClause.
  2. Let importedNames be ImportedNames of NameSpaceImport.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « », [[Phase]]: defer, [[ImportedNames]]: importedNames }.
ImportDeclaration : import defer NameSpaceImport FromClause WithClause ;
  1. Let specifier be SV of FromClause.
  2. Let attributes be WithClauseToAttributes of WithClause.
  3. Let importedNames be ImportedNames of NameSpaceImport.
  4. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: defer, [[ImportedNames]]: importedNames }.
ExportDeclaration : export ExportFromClause FromClause ;
  1. Let specifier be SV of FromClause.
  2. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « », [[Phase]]: evaluation }.
  3. Return a List whose sole element is ExportFromDeclarationModuleRequest(ExportFromClause, FromClause).
ExportDeclaration : export ExportFromClause FromClause WithClause ;
  1. Let specifier be the SV of FromClause.
  2. Let attributes be WithClauseToAttributes of WithClause.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: evaluation }.
  4. Return a List whose sole element is ExportFromDeclarationModuleRequest(ExportFromClause, FromClause, WithClause).
ExportDeclaration : export defer ExportFromClause FromClause WithClauseopt ;
  1. Return a new empty List.
ExportDeclaration : export NamedExports ; export VariableStatement export Declaration export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. Return a new empty List.

16.2.1.3.1 ExportFromDeclarationModuleRequest ( exportFromClause, fromClause [ , withClause ] )

The abstract operation ExportFromDeclarationModuleRequest takes arguments exportFromClause (an ExportFromClause Parse Node) and fromClause (a FromClause Parse Node) and optional argument withClause (a WithClause Parse Node) and returns a ModuleRequest Record. It performs the following steps when called:

  1. Let importedNames be ImportedNames of exportFromClause.
  2. Let specifier be the SV of fromClause.
  3. If withClause is present, let attributes be WithClauseToAttributes of withClause.
  4. Else, let attributes be « ».
  5. Return the ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes, [[Phase]]: evaluation, [[ImportedNames]]: importedNames }.

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.

In addition to the fields defined in Table 3 Cyclic Module Records have the additional fields listed in Table 2

Table 2: Additional Fields of Cyclic Module Records
Field Name Value Type Meaning
[[Status]] 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.
[[EvaluationError]] a throw completion or empty A throw completion representing the exception that occurred during evaluation. undefined if no exception occurred or if [[Status]] is not evaluated.
[[DFSAncestorIndex]] an integer or empty 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.
[[RequestedModules]] a List of ModuleRequest Records A List of the ModuleRequest Records associated with the imports in this module. The List is in source text occurrence order of the imports.
[[LoadedModules]] a List of LoadedModuleRequest Records 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 Records r1 and r2 such that ModuleRequestsEqual(r1, r2) is true.
[[OptionalIndirectExportEntries]] a List of ExportEntry Records whose [[LocalName]] is null. A list of all the bindings re-exported through export defer { ... } from "...". The List is in source text occurrence order.
[[CycleRoot]] a Cyclic Module Record or empty 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.
[[AsyncEvaluationOrder]] unset, an integer, or done 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.
[[TopLevelCapability]] a PromiseCapability Record or empty 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.
[[AsyncParentModules]] a List of Cyclic Module Records 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.
[[PendingAsyncDependencies]] an integer or empty 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.

In addition to the methods defined in Table 44 Cyclic Module Records have the additional methods listed in Table 3

Table 3: Additional Abstract Methods of Cyclic Module Records
Method Purpose
InitializeEnvironment() Initialize the Environment Record of the module, including resolving all imported bindings, and create the module's execution context.
ExecuteModule( [ promiseCapability ] ) Evaluate 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.

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 4:

Table 4: GraphLoadingState Record Fields
Field Name Value Type Meaning
[[PromiseCapability]] a PromiseCapability Record The promise to resolve when the loading process finishes.
[[IsLoading]] a Boolean It is true if the loading process has not finished yet, neither successfully nor with an error.
[[PendingModulesCount]] a non-negative integer It tracks the number of pending HostLoadImportedModule calls.
[[Visited]] a List of Cyclic Module Records 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.
[[HostDefined]] anything (default value is empty) It contains host-defined data to pass from the LoadRequestedModules caller to HostLoadImportedModule.

16.2.1.6.1 LoadRequestedModules ( importedNames [ , hostDefined ] )

The LoadRequestedModules concrete method of a Cyclic Module Record module takes argument importedNames (all or a List of Strings) and optional argument 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:

  1. If hostDefined is not present, let hostDefined be empty.
  2. Let pc be ! NewPromiseCapability(%Promise%).
  3. Let state be the GraphLoadingState Record { [[IsLoading]]: true, [[PendingModulesCount]]: 1, [[Visited]]: « », [[PromiseCapability]]: pc, [[HostDefined]]: hostDefined }.
  4. Perform InnerModuleLoading(state, module, importedNames).
  5. Return pc.[[Promise]].
Note 1
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.

16.2.1.6.1.1 InnerModuleLoading ( state, module, importedNames )

The abstract operation InnerModuleLoading takes arguments state (a GraphLoadingState Record), module (a Module Record), and importedNames (all 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:

  1. Assert: state.[[IsLoading]] is true.
  2. If module is a Cyclic Module Record, module.[[Status]] is new, and state.[[Visited]] does not contain module, then
  3. If module is a Cyclic Module Record, then
    1. Let requestsToLoad be a new empty List.
    2. If module.[[Status]] is new, and state.[[Visited]] does not contain module, then
      1. Append module to state.[[Visited]].
      2. Set requestsToLoad to module.[[RequestedModules]].
    3. Let indirectRequests be GetOptionalIndirectExportsModuleRequests(module, importedNames).
    4. Set requestsToLoad to the list-concatenation of requestsToLoad and indirectRequests.
    5. Let requestedModulesCount be the number of elements in module.[[RequestedModules]]requestsToLoad.
    6. Set state.[[PendingModulesCount]] to state.[[PendingModulesCount]] + requestedModulesCount.
    7. For each ModuleRequest Record request of module.[[RequestedModules]]requestsToLoad, do
      1. If AllImportAttributesSupported(request.[[Attributes]]) is false, then
        1. Let error be ThrowCompletion(a newly created SyntaxError object).
        2. Perform ContinueModuleLoading(state, error, request.[[ImportedNames]]).
      2. Else if module.[[LoadedModules]] contains a LoadedModuleRequest Record record such that ModuleRequestsEqual(record, request) is true, then
        1. Perform InnerModuleLoading(state, record.[[Module]], request.[[ImportedNames]]).
      3. Else,
        1. Perform HostLoadImportedModule(module, request, state.[[HostDefined]], state).
        2. NOTE: HostLoadImportedModule will call FinishLoadingImportedModule, which re-enters the graph loading process through ContinueModuleLoading.
      4. If state.[[IsLoading]] is false, return unused.
  4. Assert: state.[[PendingModulesCount]] ≥ 1.
  5. Set state.[[PendingModulesCount]] to state.[[PendingModulesCount]] - 1.
  6. If state.[[PendingModulesCount]] = 0, then
    1. Set state.[[IsLoading]] to false.
    2. For each Cyclic Module Record loaded of state.[[Visited]], do
      1. If loaded.[[Status]] is new, set loaded.[[Status]] to unlinked.
    3. Perform ! Call(state.[[PromiseCapability]].[[Resolve]], undefined, « undefined »).
  7. Return unused.

16.2.1.6.1.2 ContinueModuleLoading ( state, moduleCompletion, importedNames )

The abstract operation ContinueModuleLoading takes arguments state (a GraphLoadingState Record), moduleCompletion (either a normal completion containing a Module Record or a throw completion), and importedNames (all or a List of Strings) and returns unused. It is used to re-enter the loading process after a call to HostLoadImportedModule. It performs the following steps when called:

  1. If state.[[IsLoading]] is false, return unused.
  2. If moduleCompletion is a normal completion, then
    1. Perform InnerModuleLoading(state, moduleCompletion.[[Value]], importedNames).
  3. Else,
    1. Set state.[[IsLoading]] to false.
    2. Perform ! Call(state.[[PromiseCapability]].[[Reject]], undefined, « moduleCompletion.[[Value]] »).
  4. Return unused.

16.2.1.6.2 Link ( )

The Link concrete method of a Cyclic Module Record module takes no arguments and returns either a normal completion containing unused 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.)

Editor's Note

TODO: Either we add an importedNames parameter, or dynamic import will have to be responsible for linking all the defrred reexports.

If we add that parameter, we must be careful because the used deferred re-exports of a module should be linked after calling InitializeEnvironment on the module itself.

It performs the following steps when called:

  1. Assert: module.[[Status]] is one of unlinked, linked, evaluating-async, or evaluated.
  2. Let stack be a new empty List.
  3. Let result be Completion(InnerModuleLinking(module, stack, 0)).
  4. If result is an abrupt completion, then
    1. For each Cyclic Module Record m of stack, do
      1. Assert: m.[[Status]] is linking.
      2. Set m.[[Status]] to unlinked.
    2. Assert: module.[[Status]] is unlinked.
    3. Return ? result.
  5. Assert: module.[[Status]] is one of linked, evaluating-async, or evaluated.
  6. Assert: stack is empty.
  7. 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:

  1. If module is not a Cyclic Module Record, then
    1. Perform ? module.Link().
    2. Return index.
  2. If module.[[Status]] is one of linking, linked, evaluating-async, or evaluated, then
    1. Return index.
  3. Assert: module.[[Status]] is unlinked.
  4. Set module.[[Status]] to linking.
  5. Let moduleIndex be index.
  6. Set module.[[DFSAncestorIndex]] to index.
  7. Set index to index + 1.
  8. Append module to stack.
  9. For each ModuleRequest Record request of module.[[RequestedModules]], do
    1. Let requiredModule be GetImportedModule(module, request).
  10. Let linkingList be BuildLinkingList(module, module.[[RequestedModules]]).
  11. For each Module Record requiredModule of linkingList, do
    1. Set index to ? InnerModuleLinking(requiredModule, stack, index).
    2. If requiredModule is a Cyclic Module Record, then
      1. Assert: requiredModule.[[Status]] is one of linking, linked, evaluating-async, or evaluated.
      2. Assert: requiredModule.[[Status]] is linking if and only if stack contains requiredModule.
      3. If requiredModule.[[Status]] is linking, then
        1. Set module.[[DFSAncestorIndex]] to min(module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
  12. Perform ? module.InitializeEnvironment().
  13. Assert: module occurs exactly once in stack.
  14. Assert: module.[[DFSAncestorIndex]]moduleIndex.
  15. If module.[[DFSAncestorIndex]] = moduleIndex, then
    1. Let done be false.
    2. Repeat, while done is false,
      1. Let requiredModule be the last element of stack.
      2. Remove the last element of stack.
      3. Assert: requiredModule is a Cyclic Module Record.
      4. Set requiredModule.[[Status]] to linked.
      5. If requiredModule and module are the same Module Record, set done to true.
  16. Return index.

16.2.1.6.2.2 BuildLinkingList ( referrer, moduleRequests )

The abstract operation BuildLinkingList takes arguments referrer (a Cyclic Module Record) and moduleRequests (a List of ModuleRequest Records) and returns a list of Module Records. It performs the following steps when called:

  1. Let linkingList be a new empty List.
  2. For each ModuleRequest Record request of moduleRequests, do
    1. Let requiredModule be GetImportedModule(referrer, request).
    2. If linkingList does not contain requiredModule, append requiredModule to linkingList.
    3. If requiredModule is a Cyclic Module Record, then
      1. Let indirectRequests be GetOptionalIndirectExportsModuleRequests(requiredModule, request.[[ImportedNames]]).
      2. Perform ListAppendUnique(linkingList, BuildLinkingList(requiredModule, indirectRequests)).
  3. Return linkingList.
Editor's Note
TODO: There is an infinite loop if two modules export defer from each other.

16.2.1.6.3 Evaluate ( )

The Evaluate concrete method of a Cyclic Module Record module takes no arguments 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:

  1. Assert: None of module or any of its recursive dependencies have [[Status]] set to evaluating, linking, unlinked, or new.
  2. Assert: module.[[Status]] is one of linked, evaluating-async, or evaluated.
  3. If module.[[Status]] is either evaluating-async or evaluated, set module to module.[[CycleRoot]].
  4. If module.[[TopLevelCapability]] is not empty, then
    1. Return module.[[TopLevelCapability]].[[Promise]].
  5. Let stack be a new empty List.
  6. Let capability be ! NewPromiseCapability(%Promise%).
  7. Set module.[[TopLevelCapability]] to capability.
  8. Let result be Completion(InnerModuleEvaluation(module, stack, 0)).
  9. If result is an abrupt completion, then
    1. For each Cyclic Module Record m of stack, do
      1. Assert: m.[[Status]] is evaluating.
      2. Set m.[[Status]] to evaluated.
      3. Set m.[[EvaluationError]] to result.
    2. Assert: module.[[Status]] is evaluated.
    3. Assert: module.[[EvaluationError]] is result.
    4. Perform ! Call(capability.[[Reject]], undefined, « result.[[Value]] »).
  10. Else,
    1. Assert: module.[[Status]] is either evaluating-async or evaluated.
    2. Assert: module.[[EvaluationError]] is empty.
    3. If module.[[Status]] is evaluated, then
      1. NOTE: This implies that evaluation of module completed synchronously.
      2. Assert: module.[[AsyncEvaluationOrder]] is unset.
      3. Perform ! Call(capability.[[Resolve]], undefined, « undefined »).
    4. Assert: stack is empty.
  11. Return capability.[[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:

  1. If module is not a Cyclic Module Record, then
    1. Perform ? EvaluateModuleSync(module).
    2. Return index.
  2. If module.[[Status]] is either evaluating-async or evaluated, then
    1. If module.[[EvaluationError]] is empty, return index.
    2. Otherwise, return ? module.[[EvaluationError]].
  3. If module.[[Status]] is evaluating, return index.
  4. Assert: module.[[Status]] is linked.
  5. Set module.[[Status]] to evaluating.
  6. Let moduleIndex be index.
  7. Set module.[[DFSAncestorIndex]] to index.
  8. Set module.[[PendingAsyncDependencies]] to 0.
  9. Set index to index + 1.
  10. Let evaluationList be a new empty List.
  11. For each ModuleRequest Record required of module.[[RequestedModules]], do
    1. Let requiredModule be GetImportedModule(module, required.[[Specifier]]).
    2. If required.[[Phase]] is defer, then
      1. Let additionalModules be GatherAsynchronousTransitiveDependencies(requiredModule).
      2. For each Module Record additionalModule of additionalModules, do
        1. If evaluationList does not contain additionalModule, then
          1. Append additionalModule to evaluationList.
    3. Else if evaluationList does not contain requiredModule, then
      1. Append requiredModule to evaluationList.
  12. Let evaluationList be BuildEvaluationList(module, module.[[RequestedModules]]).
  13. Append module to stack.
  14. For each Module Record requiredModule of evaluationList, do
    1. Set index to ? InnerModuleEvaluation(requiredModule, stack, index).
    2. If requiredModule is a Cyclic Module Record, then
      1. Assert: requiredModule.[[Status]] is one of evaluating, evaluating-async, or evaluated.
      2. Assert: requiredModule.[[Status]] is evaluating if and only if stack contains requiredModule.
      3. If requiredModule.[[Status]] is evaluating, then
        1. Set module.[[DFSAncestorIndex]] to min(module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]]).
      4. Else,
        1. Set requiredModule to requiredModule.[[CycleRoot]].
        2. Assert: requiredModule.[[Status]] is either evaluating-async or evaluated.
        3. If requiredModule.[[EvaluationError]] is not empty, return ? requiredModule.[[EvaluationError]].
      5. If requiredModule.[[AsyncEvaluationOrder]] is an integer, then
        1. Set module.[[PendingAsyncDependencies]] to module.[[PendingAsyncDependencies]] + 1.
        2. Append module to requiredModule.[[AsyncParentModules]].
  15. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is true, then
    1. Assert: module.[[AsyncEvaluationOrder]] is unset.
    2. Set module.[[AsyncEvaluationOrder]] to IncrementModuleAsyncEvaluationCount().
    3. If module.[[PendingAsyncDependencies]] = 0, perform ExecuteAsyncModule(module).
  16. Else,
    1. Perform ? module.ExecuteModule().
  17. Assert: module occurs exactly once in stack.
  18. Assert: module.[[DFSAncestorIndex]]moduleIndex.
  19. If module.[[DFSAncestorIndex]] = moduleIndex, then
    1. Let done be false.
    2. Repeat, while done is false,
      1. Let requiredModule be the last element of stack.
      2. Remove the last element of stack.
      3. Assert: requiredModule is a Cyclic Module Record.
      4. Assert: requiredModule.[[AsyncEvaluationOrder]] is either an integer or unset.
      5. If requiredModule.[[AsyncEvaluationOrder]] is unset, set requiredModule.[[Status]] to evaluated.
      6. Otherwise, set requiredModule.[[Status]] to evaluating-async.
      7. If requiredModule and module are the same Module Record, set done to true.
      8. Set requiredModule.[[CycleRoot]] to module.
  20. 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.

16.2.1.6.3.2 BuildEvaluationList ( referrer, moduleRequests )

The abstract operation BuildEvaluationList takes arguments referrer (a Cyclic Module Record) and moduleRequests (a List of ModuleRequest Records) and returns a list of Module Records. It performs the following steps when called:

  1. Let evaluationList be a new empty List.
  2. For each ModuleRequest Record request of moduleRequests, do
    1. Let requiredModule be GetImportedModule(referrer, request.[[Specifier]]).
    2. If request.[[Phase]] is defer, then
      1. Perform ListAppendUnique(evaluationList, GatherAsynchronousTransitiveDependencies(requiredModule)).
    3. Else if evaluationList does not contain requiredModule, then
      1. Append requiredModule to evaluationList.
    4. If requiredModule is a Cyclic Module Record, then
      1. Let indirectRequests be GetOptionalIndirectExportsModuleRequests(requiredModule, request.[[ImportedNames]]).
      2. Perform ListAppendUnique(evaluationList, BuildEvaluationList(requiredModule, indirectRequests)).
  3. Return evaluationList.
Editor's Note
TODO: There is an infinite loop if two modules export defer from each other.

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:

  1. For each Record r of list2, do
    1. If list1 does not contain r, append r to list1.
  2. Return unused.

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:

  1. If seen is not present, set seen to a new empty List.
  2. Let result be a new empty List.
  3. If seen contains module, return resulta new empty List.
  4. Append module to seen.
  5. If module is not a Cyclic Module Record, return resulta new empty List.
  6. If module.[[Status]] is either evaluating or evaluated, return resulta new empty List.
  7. If module.[[HasTLA]] is true, then
    1. Append module to result.
    2. Return result« module ».
  8. For each ModuleRequest Record required of module.[[RequestedModules]], do
    1. Let requiredModule be GetImportedModule(module, required).
    2. Let additionalModules be GatherAsynchronousTransitiveDependencies(requiredModule, seen).
    3. For each Module Record m of additionalModules, do
      1. If result does not contain m, append m to result.
  9. Return result.
  10. Return InnerGatherAsynchronousTransitiveDependencies(module, module.[[RequestedModules]], seen).

16.2.1.6.3.3.1 InnerGatherAsynchronousTransitiveDependencies ( referrer, moduleRequests, seen )

The abstract operation InnerGatherAsynchronousTransitiveDependencies 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:

  1. Let result be a new empty List.
  2. For each ModuleRequest Record request of moduleRequests, do
    1. Let requiredModule be GetImportedModule(referrer, request).
    2. Perform ListAppendUnique(result, GatherAsynchronousTransitiveDependencies(requiredModule, seen)).
    3. Let indirectRequests be GetOptionalIndirectExportsModuleRequests(requiredModule, request.[[ImportedNames]]).
    4. Perform ListAppendUnique(result, InnerGatherAsynchronousTransitiveDependencies(requiredModule, indirectRequests, seen)).
  3. Return result.

16.2.1.7 Source Text Module Records

16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined )

The abstract operation ParseModule takes arguments sourceText (ECMAScript source text), realm (a Realm Record), and hostDefined (anything) 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:

  1. Let body be ParseText(sourceText, Module).
  2. If body is a List of errors, return body.
  3. Let requestedModules be the ModuleRequests of body.
  4. Let importEntries be the ImportEntries of body.
  5. Let importedBoundNames be ImportedLocalNames(importEntries).
  6. Let indirectExportEntries be a new empty List.
  7. Let localExportEntries be a new empty List.
  8. Let starExportEntries be a new empty List.
  9. Let exportEntries be the ExportEntries of body.
  10. For each ExportEntry Record ee of exportEntries, do
    1. If ee.[[ModuleRequest]] is null, then
      1. If importedBoundNames does not contain ee.[[LocalName]], then
        1. Append ee to localExportEntries.
      2. Else,
        1. Let ie be the element of importEntries whose [[LocalName]] is ee.[[LocalName]].
        2. If ie.[[ImportName]] is namespace-object, then
          1. NOTE: This is a re-export of an imported module namespace object.
          2. Append ee to localExportEntries.
        3. Else,
          1. NOTE: This is a re-export of a single name.
          2. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } to indirectExportEntries.
    2. Else if ee.[[ImportName]] is all-but-default, then
      1. Assert: ee.[[ExportName]] is null.
      2. Append ee to starExportEntries.
    3. Else,
      1. Append ee to indirectExportEntries.
  11. Let optionalIndirectExportsEntries be OptionalIndirectExportEntries of body.
  12. Let async be body Contains await.
  13. Return Source Text Module Record { [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[CycleRoot]]: empty, [[HasTLA]]: async, [[AsyncEvaluationOrder]]: unset, [[TopLevelCapability]]: empty, [[AsyncParentModules]]: « », [[PendingAsyncDependencies]]: empty, [[Status]]: new, [[EvaluationError]]: empty, [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[ImportMeta]]: empty, [[RequestedModules]]: requestedModules, [[LoadedModules]]: « », [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries, [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[OptionalIndirectExportEntries]]: optionalIndirectExportsEntries, [[DFSAncestorIndex]]: empty }.

16.2.1.7.2 Implementation of Module Record Abstract Methods

The following are the concrete methods for Source Text Module Record that implement the corresponding Module Record abstract methods defined in Table 44.

16.2.1.7.2.1 GetExportedNames ( [ exportStarSet ] )

The GetExportedNames concrete method of a Source Text Module Record module takes optional argument exportStarSet (a List of Source Text Module Records) and returns a List of Strings. It performs the following steps when called:

  1. Assert: module.[[Status]] is not new.
  2. If exportStarSet is not present, set exportStarSet to a new empty List.
  3. If exportStarSet contains module, then
    1. Assert: We've reached the starting point of an export * circularity.
    2. Return a new empty List.
  4. Append module to exportStarSet.
  5. Let exportedNames be a new empty List.
  6. Let allNamedExportEntries be the list-concatenation of module.[[LocalExportEntries]], module.[[IndirectExportEntries]], and module.[[OptionalIndirectExportEntries]].
  7. For each ExportEntry Record e of module.[[LocalExportEntries]]allNamedExportEntries, do
    1. Assert: module provides the direct binding for this export.
    2. Assert: e.[[ExportName]] is not null.
    3. Append e.[[ExportName]] to exportedNames.
  8. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
    1. Assert: module imports a specific binding for this export.
    2. Assert: e.[[ExportName]] is not null.
    3. Append e.[[ExportName]] to exportedNames.
  9. For each ExportEntry Record e of module.[[StarExportEntries]], do
    1. Assert: e.[[ModuleRequest]] is not null.
    2. Let requestedModule be GetImportedModule(module, e.[[ModuleRequest]]).
    3. Let starNames be requestedModule.GetExportedNames(exportStarSet).
    4. For each element n of starNames, do
      1. If n is not "default", then
        1. If exportedNames does not contain n, then
          1. Append n to exportedNames.
  10. Return exportedNames.
Note

GetExportedNames does not filter out or throw an exception for names that have ambiguous star export bindings.

16.2.1.7.2.2 ResolveExport ( exportName [ , resolveSet ] )

The ResolveExport concrete method of a Source Text Module Record module takes argument exportName (a String) and optional argument resolveSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)) and returns a ResolvedBinding Record, null, or ambiguous.

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:

  1. Assert: module.[[Status]] is not new.
  2. If resolveSet is not present, set resolveSet to a new empty List.
  3. For each Record { [[Module]], [[ExportName]] } r of resolveSet, do
    1. If module and r.[[Module]] are the same Module Record and exportName is r.[[ExportName]], then
      1. Assert: This is a circular import request.
      2. Return null.
  4. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet.
  5. For each ExportEntry Record e of module.[[LocalExportEntries]], do
    1. If e.[[ExportName]] is exportName, then
      1. Assert: module provides the direct binding for this export.
      2. Return ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }.
  6. Let allIndirectEntries be the list-concatenation of module.[[IndirectExportEntries]] and module.[[OptionalIndirectExportEntries]].
  7. For each ExportEntry Record e of module.[[IndirectExportEntries]]allIndirectEntries, do
    1. If e.[[ExportName]] is exportName, then
      1. Assert: e.[[ModuleRequest]] is not null.
      2. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
      3. If e.[[ImportName]] is all, then
        1. Assert: module does not provide the direct binding for this export.
        2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
      4. Else,
        1. Assert: module imports a specific binding for this export.
        2. Assert: e.[[ImportName]] is a String.
        3. Return importedModule.ResolveExport(e.[[ImportName]], resolveSet).
  8. If exportName is "default", then
    1. Assert: A default export was not explicitly defined by this module.
    2. Return null.
    3. NOTE: A default export cannot be provided by an export * from "mod" declaration.
  9. Let starResolution be null.
  10. For each ExportEntry Record e of module.[[StarExportEntries]], do
    1. Assert: e.[[ModuleRequest]] is not null.
    2. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
    3. Let resolution be importedModule.ResolveExport(exportName, resolveSet).
    4. If resolution is ambiguous, return ambiguous.
    5. If resolution is not null, then
      1. Assert: resolution is a ResolvedBinding Record.
      2. If starResolution is null, then
        1. Set starResolution to resolution.
      3. Else,
        1. Assert: There is more than one * import that includes the requested name.
        2. If resolution.[[Module]] and starResolution.[[Module]] are not the same Module Record, return ambiguous.
        3. If resolution.[[BindingName]] is not starResolution.[[BindingName]] and either resolution.[[BindingName]] or starResolution.[[BindingName]] is namespace, return ambiguous.
        4. If resolution.[[BindingName]] is a String, starResolution.[[BindingName]] is a String, and resolution.[[BindingName]] is not starResolution.[[BindingName]], return ambiguous.
  11. Return starResolution.

16.2.1.11 FinishLoadingImportedModule ( referrer, moduleRequest, payload, result )

The abstract operation FinishLoadingImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), moduleRequest (a ModuleRequest Record), payload (a GraphLoadingState Record or a PromiseCapability Record), and result (either a normal completion containing a Module Record or a throw completion) and returns unused. It performs the following steps when called:

  1. If result is a normal completion, then
    1. If referrer.[[LoadedModules]] contains a LoadedModuleRequest Record record such that ModuleRequestsEqual(record, moduleRequest) is true, then
      1. Assert: record.[[Module]] and result.[[Value]] are the same Module Record.
    2. Else,
      1. Append the LoadedModuleRequest Record { [[Specifier]]: moduleRequest.[[Specifier]], [[Attributes]]: moduleRequest.[[Attributes]], [[Module]]: result.[[Value]] } to referrer.[[LoadedModules]].
  2. If payload is a GraphLoadingState Record, then
    1. Perform ContinueModuleLoading(payload, result, moduleRequest.[[ImportedNames]]).
  3. Else,
    1. Perform ContinueDynamicImport(payload, result, moduleRequest.[[Phase]]).
  4. Return unused.

16.2.1.100 GetOptionalIndirectExportsModuleRequests ( module, importedNames )

The abstract operation GetOptionalIndirectExportsModuleRequests takes arguments module (a Cyclic Module Record) and importedNames (all or a List of Strings) and returns a List of ModuleRequest Records. It performs the following steps when called:

  1. Let requests be a new empty List.
  2. For each ExportEntry Record oie of module.[[OptionalIndirectExportEntries]], do
    1. If importedNames is all or importedNames contains oie.[[ExportName]], then
      1. Let nextRequest be oie.[[ModuleRequest]].
      2. Let existingRequest be empty.
      3. For each ModuleRequest Record r in requests, do
        1. If existingRequest is empty and ModuleRequestsEqual(r, nextRequest) is true and r.[[Phase]] is nextRequest.[[Phase]], then
          1. Set existingRequest to r.
      4. Let newImportedNames be all.
      5. Assert: oie.[[ImportName]] is a String or all.
      6. If oie.[[ImportName]] is a String, set newImportedNames to « oie.[[ImportName]] ».
      7. If existingRequest is empty, then
        1. Let request be the ModuleRequest Record { [[Specifier]]: nextRequest.[[Specifier]], [[Attributes]]: nextRequest.[[Attributes]], [[Phase]]: nextRequest.[[Phase]], [[ImportedNames]]: newImportedNames }.
        2. Append request to requests.
      8. Else,
        1. Set existingRequest.[[ImportedNames]] to MergeImportedNames(existingRequest.[[ImportedNames]], newImportedNames).
  3. Return requests.

16.2.2 Imports

16.2.2.2 Static Semantics: ImportEntries

The syntax-directed operation ImportEntries takes no arguments and returns a List of ImportEntry Records. It is defined piecewise over the following productions:

Module : [empty]
  1. Return a new empty List.
ModuleItemList : ModuleItemList ModuleItem
  1. Let entries1 be the ImportEntries of ModuleItemList.
  2. Let entries2 be the ImportEntries of ModuleItem.
  3. Return the list-concatenation of entries1 and entries2.
ModuleItem : ExportDeclaration StatementListItem
  1. Return a new empty List.
ImportDeclaration : import ImportClause FromClause WithClauseopt ;
  1. Let module be the sole element of the ModuleRequests of ImportDeclaration.
  2. Return the ImportEntriesForModule of ImportClause with argument module.
ImportDeclaration : import ModuleSpecifier WithClauseopt ;
  1. Return a new empty List.

16.2.2.3 Static Semantics: ImportEntriesForModule

The syntax-directed operation ImportEntriesForModule takes argument module (a ModuleRequest Record) and returns a List of ImportEntry Records. It is defined piecewise over the following productions:

ImportClause : ImportedDefaultBinding , NameSpaceImport
  1. Let entries1 be the ImportEntriesForModule of ImportedDefaultBinding with argument module.
  2. Let entries2 be the ImportEntriesForModule of NameSpaceImport with argument module.
  3. Return the list-concatenation of entries1 and entries2.
ImportClause : ImportedDefaultBinding , NamedImports
  1. Let entries1 be the ImportEntriesForModule of ImportedDefaultBinding with argument module.
  2. Let entries2 be the ImportEntriesForModule of NamedImports with argument module.
  3. Return the list-concatenation of entries1 and entries2.
ImportedDefaultBinding : ImportedBinding
  1. Let localName be the sole element of the BoundNames of ImportedBinding.
  2. Let defaultEntry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: "default", [[LocalName]]: localName }.
  3. Return « defaultEntry ».
NameSpaceImport : * as ImportedBinding
  1. Let localName be the StringValue of ImportedBinding.
  2. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace-object, [[LocalName]]: localName }.
  3. Return « entry ».
NamedImports : { }
  1. Return a new empty List.
ImportsList : ImportsList , ImportSpecifier
  1. Let specs1 be the ImportEntriesForModule of ImportsList with argument module.
  2. Let specs2 be the ImportEntriesForModule of ImportSpecifier with argument module.
  3. Return the list-concatenation of specs1 and specs2.
ImportSpecifier : ImportedBinding
  1. Let localName be the sole element of the BoundNames of ImportedBinding.
  2. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: localName, [[LocalName]]: localName }.
  3. Return « entry ».
ImportSpecifier : ModuleExportName as ImportedBinding
  1. Let importName be the StringValue of ModuleExportName.
  2. Let localName be the StringValue of ImportedBinding.
  3. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName }.
  4. Return « entry ».

16.2.2.4 Static Semantics: ImportedNames

The syntax-directed operation ImportedNames takes no arguments and returns all or a List of Strings. It is defined piecewise over the following productions:

ImportClause : NameSpaceImport ImportedDefaultBinding , NameSpaceImport
  1. Return all.
ImportClause : ImportedDefaultBinding , NamedImports
  1. Let names1 be ImportedNames of ImportedDefaultBinding.
  2. Let names2 be ImportedNames of NamedImports.
  3. Return MergeImportedNames(names1, names2).
ImportedDefaultBinding : ImportedBinding
  1. Return « "default" ».
NamedImports : { }
  1. Return « ».
ImportsList : ImportsList , ImportSpecifier
  1. Let names1 be ImportedNames of ImportsList.
  2. Let names2 be ImportedNames of ImportSpecifier.
  3. Return MergeImportedNames(names1, names2).
ImportSpecifier : ImportedBinding
  1. Let importedName be the StringValue of ImportedBinding.
  2. Return « importedName ».
ImportSpecifier : ModuleExportName as ImportedBinding
  1. Let importedName be the StringValue of ModuleExportName.
  2. Return « importedName ».

16.2.2.4.1 MergeImportedNames ( a, b )

The abstract operation MergeImportedNames takes arguments a (all or a List of Strings) and b (all or a List of Strings) and returns all or a List of Strings. It performs the following steps when called:

  1. If a is all or b is all, return all.
  2. Return the list-concatenation of a and b.

16.2.3 Exports

Syntax

ExportDeclaration : export deferopt ExportFromClause FromClause WithClauseopt ; export NamedExports ; export VariableStatement[~Yield, +Await] export Declaration[~Yield, +Await] export default HoistableDeclaration[~Yield, +Await, +Default] export default ClassDeclaration[~Yield, +Await, +Default] export default [lookahead ∉ { function, async [no LineTerminator here] function, class }] AssignmentExpression[+In, ~Yield, +Await] ; ExportFromClause : * * as ModuleExportName NamedNamespaceExport NamedExports NamedNamespaceExport : * as ModuleExportName NamedExports : { } { ExportsList } { ExportsList , } ExportsList : ExportSpecifier ExportsList , ExportSpecifier ExportSpecifier : ModuleExportName ModuleExportName as ModuleExportName

16.2.3.1 Static Semantics: Early Errors

ExportDeclaration : export NamedExports ; Note

The above rule means that each ReferencedBindings of NamedExports is treated as an IdentifierReference.

ExportDeclaration : export defer ExportFromClause FromClause WithClauseopt ;

16.2.3.3 Static Semantics: ExportedNames

The syntax-directed operation ExportedNames takes no arguments and returns a List of Strings.

Note

ExportedNames are the externally visible names that a Module explicitly maps to one of its local name bindings.

It is defined piecewise over the following productions:

ModuleItemList : ModuleItemList ModuleItem
  1. Let names1 be ExportedNames of ModuleItemList.
  2. Let names2 be ExportedNames of ModuleItem.
  3. Return the list-concatenation of names1 and names2.
ModuleItem : ExportDeclaration
  1. Return the ExportedNames of ExportDeclaration.
ModuleItem : ImportDeclaration StatementListItem
  1. Return a new empty List.
ExportDeclaration : export deferopt ExportFromClause FromClause WithClauseopt ;
  1. Return the ExportedNames of ExportFromClause.
ExportFromClause : *
  1. Return a new empty List.
ExportFromClause : * as ModuleExportName
  1. Return a List whose sole element is the StringValue of ModuleExportName.
ExportFromClause : NamedExports
  1. Return the ExportedNames of NamedExports.
ExportDeclaration : export VariableStatement
  1. Return the BoundNames of VariableStatement.
ExportDeclaration : export Declaration
  1. Return the BoundNames of Declaration.
ExportDeclaration : export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. Return « "default" ».
NamedExports : { }
  1. Return a new empty List.
ExportsList : ExportsList , ExportSpecifier
  1. Let names1 be the ExportedNames of ExportsList.
  2. Let names2 be the ExportedNames of ExportSpecifier.
  3. Return the list-concatenation of names1 and names2.
ExportSpecifier : ModuleExportName
  1. Return a List whose sole element is the StringValue of ModuleExportName.
ExportSpecifier : ModuleExportName as ModuleExportName
  1. Return a List whose sole element is the StringValue of the second ModuleExportName.

16.2.3.4 Static Semantics: ExportEntries

The syntax-directed operation ExportEntries takes no arguments and returns a List of ExportEntry Records. It is defined piecewise over the following productions:

Module : [empty]
  1. Return a new empty List.
ModuleItemList : ModuleItemList ModuleItem
  1. Let entries1 be ExportEntries of ModuleItemList.
  2. Let entries2 be ExportEntries of ModuleItem.
  3. Return the list-concatenation of entries1 and entries2.
ModuleItem : ImportDeclaration StatementListItem
  1. Return a new empty List.
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. Let module be the sole element of ModuleRequests of FromClause.
  2. Return ExportEntriesForModule of ExportFromClause with argument module.
ExportDeclaration : export defer ExportFromClause FromClause WithClauseopt ;
  1. Return a new empty List.
ExportDeclaration : export NamedExports ;
  1. Return ExportEntriesForModule of NamedExports with argument null.
ExportDeclaration : export VariableStatement
  1. Let entries be a new empty List.
  2. Let names be the BoundNames of VariableStatement.
  3. For each element name of names, do
    1. Append the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } to entries.
  4. Return entries.
ExportDeclaration : export Declaration
  1. Let entries be a new empty List.
  2. Let names be the BoundNames of Declaration.
  3. For each element name of names, do
    1. Append the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } to entries.
  4. Return entries.
ExportDeclaration : export default HoistableDeclaration
  1. Let names be BoundNames of HoistableDeclaration.
  2. Let localName be the sole element of names.
  3. Return a List whose sole element is a new ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }.
ExportDeclaration : export default ClassDeclaration
  1. Let names be BoundNames of ClassDeclaration.
  2. Let localName be the sole element of names.
  3. Return a List whose sole element is a new ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }.
ExportDeclaration : export default AssignmentExpression ;
  1. Let entry be the ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: "*default*", [[ExportName]]: "default" }.
  2. Return « entry ».
Note

"*default*" is used within this specification as a synthetic name for anonymous default export values. See this note for more details.

16.2.3.5 Static Semantics: OptionalIndirectExportEntries

The syntax-directed operation OptionalIndirectExportEntries takes no arguments and returns a List of ExportEntry Records. It is defined piecewise over the following productions:

Module : [empty]
  1. Return a new empty List.
ModuleItemList : ModuleItemList ModuleItem
  1. Let entries1 be OptionalIndirectExportEntries of ModuleItemList.
  2. Let entries2 be OptionalIndirectExportEntries of ModuleItem.
  3. Return the list-concatenation of entries1 and entries2.
ModuleItem : ImportDeclaration StatementListItem ExportDeclaration : export ExportFromClause FromClause WithClauseopt ; export NamedExports ; export VariableStatement export Declaration export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. Return a new empty List.
ExportDeclaration : export defer ExportFromClause FromClause WithClauseopt ;
  1. If WithClause is present, let request be ExportFromDeclarationModuleRequest(ExportFromClause, FromClause, WithClause).
  2. Else, let request be ExportFromDeclarationModuleRequest(ExportFromClause, FromClause).
  3. Return ExportEntriesForModule of ExportFromClause with argument request.

Copyright & Software License

Software License

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:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. 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.
  3. 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.