Stage 2 Draft / May 11, 2023

Source Phase Imports

13 ECMAScript Language: Expressions

13.3.10 Import Calls

13.3.10.1 Runtime Semantics: Evaluation

ImportCall : import ( AssignmentExpression )
  1. Let referrer be GetActiveScriptOrModule().
  2. If referrer is null, set referrer to the current Realm Record.
  3. Let argRef be ? Evaluation of AssignmentExpression.
  4. Let specifier be ? GetValue(argRef).
  5. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  6. Let specifierString be Completion(ToString(specifier)).
  7. IfAbruptRejectPromise(specifierString, promiseCapability).
  8. Perform HostLoadImportedModule(referrer, specifierString, empty, promiseCapability).
  9. Return promiseCapability.[[Promise]].
  10. Let specifierRef be the result of evaluating AssignmentExpression.
  11. Let specifier be ? GetValue(specifierRef).
  12. Return EvaluateImportCall(specifier, undefined).
ImportCall : import ( AssignmentExpression , AssignmentExpression )
  1. Let specifierRef be the result of evaluating the first AssignmentExpression.
  2. Let specifier be ? GetValue(specifierRef).
  3. Let optionsRef be the result of evaluating the second AssignmentExpression.
  4. Let options be ? GetValue(optionsRef).
  5. Return EvaluateImportCall(specifier, options).

13.3.10.1.1 EvaluateImportCall ( specifier, options )

The abstract operation EvaluateImportCall takes arguments specifier and options. 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 promiseCapability be ! NewPromiseCapability(%Promise%).
  4. Let specifierString be Completion(ToString(specifier)).
  5. IfAbruptRejectPromise(specifierString, promiseCapability).
  6. Let phase be evaluation.
  7. If options is not undefined, then
    1. If Type(options) is not Object,
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    2. Let phaseOption be Get(options, "phase").
    3. IfAbruptRejectPromise(phaseOption, promiseCapability).
    4. If phaseOption is not undefined,
      1. If Type(phaseOption) is not "source", then
        1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
        2. Return promiseCapability.[[Promise]].
      2. Set phase to source.
  8. Let state be the DynamicImportState Record { [[PromiseCapability]]: promiseCapability, [[Phase]]: phase }.
  9. Perform HostLoadImportedModule(referrer, specifierString, empty, state).
  10. Return promiseCapability.[[Promise]].

A DynamicImportState 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 DynamicImportState Record has the fields defined in Table 1:

Table 1: DynamicImportState Record Fields
Field Name Value Type Meaning
[[PromiseCapability]] a PromiseCapability Record The promise to resolve when the dynamic import finishes.
[[Phase]] source or evaluation The target import phase. It's source when using the phase: "source" option, and evaluation otherwise.

13.3.10.1.2 ContinueDynamicImport ( promiseCapability, state, moduleCompletion )

The abstract operation ContinueDynamicImport takes arguments promiseCapability (a PromiseCapability Record), state (a DynamicImportState Record), and moduleCompletion (either a normal completion containing a Module Record or a throw completion) 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. Let promiseCapability be state.[[PromiseCapability]].
  2. If moduleCompletion is an abrupt completion, then
    1. Perform ! Call(promiseCapability.[[Reject]], undefined, « moduleCompletion.[[Value]] »).
    2. Return unused.
  3. Let module be moduleCompletion.[[Value]].
  4. If state.[[Phase]] is source, then
    1. Let moduleSourceObject be Completion(module.GetModuleSource()).
    2. If moduleSourceObject is an abrupt completion, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « moduleSourceObject.[[Value]] »).
    3. Else,
      1. Perform ! Call(promiseCapability.[[Resolve]], undefined, « moduleSourceObject.[[Value]] »).
    4. Return unused.
  5. Let loadPromise be module.LoadRequestedModules().
  6. 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.
  7. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
  8. Let linkAndEvaluateClosure be a new Abstract Closure with no parameters that captures module, promiseCapability, and onRejected and performs the following steps when called:
    1. Let link be Completion(module.Link()).
    2. If link is an abrupt completion, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « link.[[Value]] »).
      2. Return unused.
    3. Let evaluatePromise be module.Evaluate().
    4. Let fulfilledClosure be a new Abstract Closure with no parameters that captures module and promiseCapability and performs the following steps when called:
      1. Let namespace be GetModuleNamespace(module).
      2. Perform ! Call(promiseCapability.[[Resolve]], undefined, « namespace »).
      3. Return unused.
    5. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, "", 0, « »).
    6. Perform PerformPromiseThen(evaluatePromise, onFulfilled, onRejected).
  9. Let linkAndEvaluate be CreateBuiltinFunction(linkAndEvaluateClosure, "", 0, « »).
  10. Perform PerformPromiseThen(loadPromise, linkAndEvaluate, onRejected).
  11. Return unused.

16 ECMAScript Language: Scripts and Modules

16.1 Modules

16.1.1 Module Semantics

16.1.1.1 ModuleRequest Records

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

Table 2: ModuleRequest Record fields
Field Name Value Type Meaning
[[Specifier]] String The module specifier
[[Phase]] source or evaluation The target import phase
Editor's Note
In general, this proposal replaces places where module specifiers are passed around with ModuleRequest Records. For example, several syntax-directed operations, such as ModuleRequests produce Lists of ModuleRequest Records rather than Lists of Strings which are interpreted as module specifiers. Some algorithms like ImportEntries and ImportEntriesForModule pass around ModuleRequest Records rather than Strings, in a way which doesn't require any particular textual change. Additionally, record fields in Cyclic Module Records and Source Text Module Records which contained Lists of Strings are replaced by Lists of ModuleRequest Records, as indicated above.

16.1.1.3 Static Semantics: ModuleRequests

The syntax-directed operation ModuleRequests takes no arguments and returns a List of StringsModuleRequest 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 moduleNamesrequests be ModuleRequests of ModuleItemList.
  2. Let additionalNamesadditionalRequests be ModuleRequests of ModuleItem.
  3. For each String name of additionalNames, do
  4. For each ModuleRequest Record mr of additionalRequests, do
    1. Let found be false.
    2. For each ModuleRequest Record mr2 of requests, do
      1. If mr.[[Specifer]] is mr2.[[Specifer]] and mr.[[Phase]] is mr2.[[Phase]], then
        1. Assert: found is false.
        2. Set found to true.
    3. If moduleNames does not contain name, then
    4. If found is false, then
      1. Append namemr to moduleNamesrequests.
  5. Return moduleNamesrequests.
ModuleItem : StatementListItem
  1. Return a new empty List.
ImportDeclaration : import ImportClause FromClause ;
  1. Return ModuleRequests of FromClause.
  2. Let specifier be SV of FromClause.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Phase]]: evaluation }.
ImportDeclaration : import source ImportedBinding FromClause ;
  1. Let specifier be SV of FromClause.
  2. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Phase]]: source }.
ModuleSpecifier : StringLiteral
  1. Return a List whose sole element is the SV of StringLiteral.
ExportDeclaration : export ExportFromClause FromClause ;
  1. Return ModuleRequests of FromClause.
  2. Let specifier be SV of FromClause.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Phase]]: evaluation }.
ExportDeclaration : export NamedExports ; export VariableStatement export Declaration export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. Return a new empty List.

16.1.1.4 ModuleSource Records

A ModuleSource Record represents the request to import a module up to a given phase. It consists of the following fields:

Table 3: ModuleSource Record fields
Field Name Value Type Meaning
[[SourceClassName]] String The unique source class name string used to represent this module source. Source Text Module Records are usually represented by the "ModuleSource" class.
[[HostDefined]] anything (default value is undefined) Field reserved for use by host environments to associate additional information with module sources.
Editor's Note
In general, this proposal replaces places where module specifiers are passed around with ModuleRequest Records. For example, several syntax-directed operations, such as ModuleRequests produce Lists of ModuleRequest Records rather than Lists of Strings which are interpreted as module specifiers. Some algorithms like ImportEntries and ImportEntriesForModule pass around ModuleRequest Records rather than Strings, in a way which doesn't require any particular textual change. Additionally, record fields in Cyclic Module Records and Source Text Module Records which contained Lists of Strings are replaced by Lists of ModuleRequest Records, as indicated above.

16.1.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 4. All Module Definition subclasses include at least those fields. Module Record also defines the abstract method list in Table 5. All Module definition subclasses must provide concrete implementations of these abstract methods.

Table 4: Module Record Fields
Field Name Value Type Meaning
[[Realm]] a Realm Record The Realm within which this module was created.
[[Environment]] a Module Environment Record or empty The Environment Record containing the top level bindings for this module. This field is set when the module is linked.
[[Namespace]] an Object or empty The Module Namespace Object (28.3) if one has been created for this module.
[[HostDefined]] anything (default value is undefined) Field reserved for use by host environments that need to associate additional information with a module.
Table 5: Abstract Methods of Module Records
Method Purpose
LoadRequestedModules( [ hostDefined ] )

Prepares the module for linking by recursively loading all its dependencies, and returns a promise.

GetExportedNames([exportStarSet])

Return a list of all names that are either directly or indirectly exported from this module.

LoadRequestedModules must have completed successfully prior to invoking this method.

ResolveExport(exportName [, resolveSet])

Return the binding of a name exported by this module. Bindings are represented by a ResolvedBinding Record, of the form { [[Module]]: Module Record, [[BindingName]]: String | namespace }. If the export is a Module Namespace Object without a direct binding in any module, [[BindingName]] will be set to namespace. Return 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.

Link()

Prepare the module for evaluation by transitively resolving all module dependencies and creating a Module Environment Record.

LoadRequestedModules must have completed successfully prior to invoking this method.

Evaluate()

Returns a promise for the evaluation of this module and its dependencies, resolving on successful evaluation or if it has already been evaluated successfully, and rejecting for an evaluation error or if it has already been evaluated unsuccessfully. If the promise is rejected, hosts are expected to handle the promise rejection and rethrow the evaluation error.

Link must have completed successfully prior to invoking this method.

GetModuleSource()

It returns either a normal completion completion for the ModuleSource Object corresponding to this source Module Record's source phase (28.1), or a throw completion.

When called multiple times on the same Module Record, if GetModuleSource() returns a normal completion it must always return a normal completion containing the same object. The returned object should be a subclass of %AbstractModuleSource%, and it must have an internal slot [[ModuleSourceRecord]].

16.1.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 4 Cyclic Module Records have the additional fields listed in Table 6

Table 6: Additional Fields of Cyclic Module Records
Field Name Value Type Meaning
[[Status]] unlinked, linking, linked, evaluating, evaluating-async, or evaluated Initially unlinked. Transitions to 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.
[[DFSIndex]] an integer or empty Auxiliary field used during Link and Evaluate only. If [[Status]] is linking or evaluating, this non-negative number records the point at which the module was first visited during the depth-first traversal of the dependency graph.
[[DFSAncestorIndex]] an integer or empty Auxiliary field used during Link and Evaluate only. If [[Status]] is linking or evaluating, this is either the module's own [[DFSIndex]] or that of an "earlier" module in the same strongly connected component.
[[RequestedModules]] a List of StringsModuleRequest Records A List of all the ModuleSpecifier strings used by the module represented by this record to request the importation of a module, along with their maximum associated phase (source or evaluation). 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 equal to the [[DFSIndex]] 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.
[[AsyncEvaluation]] a Boolean Whether this module is either itself asynchronous or has an asynchronous dependency. Note: The order in which this field is set is used to order queued executions, see 16.2.1.5.3.4.
[[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.

16.1.1.6.1 LoadRequestedModules ( [ hostDefined ] )

The LoadRequestedModules concrete method of a Cyclic Module Record module takes optional argument hostDefined (anything) and returns a Promise object. 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.

16.1.1.6.1.1 InnerModuleLoading ( state, module, phase )

The abstract operation InnerModuleLoading takes arguments state (a GraphLoadingState Record), module (a Module Record), and phase (source or evaluation) 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, and phase is evaluation, then
    1. Append module to state.[[Visited]].
    2. Let requestedModulesCount be the number of elements in module.[[RequestedModules]].
    3. Set state.[[PendingModulesCount]] to state.[[PendingModulesCount]] + requestedModulesCount.
    4. For each String required of module.[[RequestedModules]], do
    5. For each ModuleRequest Record required of module.[[RequestedModules]], do
      1. If module.[[LoadedModules]] contains a Record whose [[Specifier]] is required.[[Specifier]], then
        1. Let record be that Record.
        2. Perform InnerModuleLoading(state, record.[[Module]], required.[[Phase]]).
      2. Else,
        1. Perform HostLoadImportedModule(module, required.[[Specifier]], state.[[HostDefined]], state).
        2. NOTE: HostLoadImportedModule will call FinishLoadingImportedModule, which re-enters the graph loading process through ContinueModuleLoading.
      3. If state.[[IsLoading]] is false, return unused.
  3. Assert: state.[[PendingModulesCount]] ≥ 1.
  4. Set state.[[PendingModulesCount]] to state.[[PendingModulesCount]] - 1.
  5. 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 »).
  6. Return unused.

16.1.1.6.1.2 ContinueModuleLoading ( state, referrer, specifier, moduleCompletion )

The abstract operation ContinueModuleLoading takes arguments state (a GraphLoadingState Record), referrer (a Cyclic Module Record), specifier (a String), and moduleCompletion (either a normal completion containing a Module Record or a throw completion) 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. Let phase be source.
    2. If referrer.[[RequestedModules]] contains a ModuleRequest Record whose [[Specifer]] is specifier and whose [[Phase]] is evaluation, then
      1. Set phase to evaluation.
    3. Perform InnerModuleLoading(state, moduleCompletion.[[Value]], phase).
  3. Else,
    1. Set state.[[IsLoading]] to false.
    2. Perform ! Call(state.[[PromiseCapability]].[[Reject]], undefined, « moduleCompletion.[[Value]] »).
  4. Return unused.

16.1.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.)

16.1.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 [[DFSIndex]] and [[DFSAncestorIndex]] fields, keep track of the depth-first search (DFS) traversal. In particular, [[DFSAncestorIndex]] is used to discover strongly connected components (SCCs), such that all modules in an SCC transition to linked together. It performs the following steps when called:

  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. Set module.[[DFSIndex]] to index.
  6. Set module.[[DFSAncestorIndex]] to index.
  7. Set index to index + 1.
  8. Append module to stack.
  9. For each StringModuleRequest Record required of module.[[RequestedModules]], do
    1. If required.[[Phase]] is evaluation, then
      1. Let requiredModule be GetImportedModule(module, required.[[Specifier]]).
      2. Set index to ? InnerModuleLinking(requiredModule, stack, index).
      3. 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]]).
  10. Perform ? module.InitializeEnvironment().
  11. Assert: module occurs exactly once in stack.
  12. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]].
  13. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], 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.
  14. Return index.

16.1.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.)

16.1.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 [[DFSIndex]] and [[DFSAncestorIndex]] fields, 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. Let promise be ! module.Evaluate().
    2. Assert: promise.[[PromiseState]] is not pending.
    3. If promise.[[PromiseState]] is rejected, then
      1. Return ThrowCompletion(promise.[[PromiseResult]]).
    4. 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. Set module.[[DFSIndex]] to index.
  7. Set module.[[DFSAncestorIndex]] to index.
  8. Set module.[[PendingAsyncDependencies]] to 0.
  9. Set index to index + 1.
  10. Append module to stack.
  11. For each String required of module.[[RequestedModules]], do
  12. For each ModuleRequest Record required of module.[[RequestedModules]], do
    1. Let requiredModule be GetImportedModule(module, required.[[Specifier]]).
    2. If requiredModule.[[Phase]] is evaluation, then
      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.[[AsyncEvaluation]] is true, then
          1. Set module.[[PendingAsyncDependencies]] to module.[[PendingAsyncDependencies]] + 1.
          2. Append module to requiredModule.[[AsyncParentModules]].
  13. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is true, then
    1. Assert: module.[[AsyncEvaluation]] is false and was never previously set to true.
    2. Set module.[[AsyncEvaluation]] to true.
    3. NOTE: The order in which module records have their [[AsyncEvaluation]] fields transition to true is significant. (See 16.2.1.5.3.4.)
    4. If module.[[PendingAsyncDependencies]] = 0, perform ExecuteAsyncModule(module).
  14. Else,
    1. Perform ? module.ExecuteModule().
  15. Assert: module occurs exactly once in stack.
  16. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]].
  17. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], 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. If requiredModule.[[AsyncEvaluation]] is false, set requiredModule.[[Status]] to evaluated.
      5. Otherwise, set requiredModule.[[Status]] to evaluating-async.
      6. If requiredModule and module are the same Module Record, set done to true.
      7. Set requiredModule.[[CycleRoot]] to module.
  18. Return index.

16.1.1.6.4 GetModuleSource ( )

The GetModuleSource concrete method of a Cyclic Module Record module takes no arguments and returns either a normal completion containing an Object or a throw completion.

Cyclic Module Record provides a default GetModuleSource implementation with an abrupt completion to provide a standard reference error that a source phase import is not available.

It performs the following steps when called:

  1. Let error be a newly created ReferenceError object.
  2. Return ThrowCompletion(error).

16.1.1.7 Source Text Module Records

16.1.1.7.1 InitializeEnvironment ( )

The InitializeEnvironment concrete method of a Source Text Module Record module takes no arguments and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
    1. Let resolution be module.ResolveExport(e.[[ExportName]]).
    2. If resolution is either null or ambiguous, throw a SyntaxError exception.
    3. Assert: resolution is a ResolvedBinding Record.
  2. Assert: All named exports from module are resolvable.
  3. Let realm be module.[[Realm]].
  4. Assert: realm is not undefined.
  5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
  6. Set module.[[Environment]] to env.
  7. For each ImportEntry Record in of module.[[ImportEntries]], do
    1. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
    2. If in.[[ImportName]] is namespace-object, then
      1. Let namespace be GetModuleNamespace(importedModule).
      2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
      3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
    3. Else if in.[[ImportName]] is source, then
      1. Let moduleSourceObject be ? importedModule.GetModuleSource().
      2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
      3. Perform ! env.InitializeBinding(in.[[LocalName]], moduleSourceObject).
    4. Else,
      1. Let resolution be importedModule.ResolveExport(in.[[ImportName]]).
      2. If resolution is either null or ambiguous, throw a SyntaxError exception.
      3. If resolution.[[BindingName]] is namespace, then
        1. Let namespace be GetModuleNamespace(resolution.[[Module]]).
        2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
        3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
      4. Else,
        1. Perform env.CreateImportBinding(in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
  8. Let moduleContext be a new ECMAScript code execution context.
  9. Set the Function of moduleContext to null.
  10. Assert: module.[[Realm]] is not undefined.
  11. Set the Realm of moduleContext to module.[[Realm]].
  12. Set the ScriptOrModule of moduleContext to module.
  13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
  14. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
  15. Set the PrivateEnvironment of moduleContext to null.
  16. Set module.[[Context]] to moduleContext.
  17. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
  18. Let code be module.[[ECMAScriptCode]].
  19. Let varDeclarations be the VarScopedDeclarations of code.
  20. Let declaredVarNames be a new empty List.
  21. For each element d of varDeclarations, do
    1. For each element dn of the BoundNames of d, do
      1. If declaredVarNames does not contain dn, then
        1. Perform ! env.CreateMutableBinding(dn, false).
        2. Perform ! env.InitializeBinding(dn, undefined).
        3. Append dn to declaredVarNames.
  22. Let lexDeclarations be the LexicallyScopedDeclarations of code.
  23. Let privateEnv be null.
  24. For each element d of lexDeclarations, do
    1. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! env.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! env.CreateMutableBinding(dn, false).
      3. If d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
        1. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
        2. Perform ! env.InitializeBinding(dn, fo).
  25. Remove moduleContext from the execution context stack.
  26. Return unused.

16.1.1.8 HostLoadImportedModule ( referrer, specifier, hostDefined, payload )

The host-defined abstract operation HostLoadImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), specifier (a String), hostDefined (anything), and payload (a GraphLoadingState Record or a PromiseCapability RecordDynamicImportState Record) and returns unused.

Note 1

An example of when referrer can be a Realm Record is in a web browser host. There, if a user clicks on a control given by

<button type="button" onclick="import('./foo.mjs')">Click me</button>

there will be no active script or module at the time the import() expression runs. More generally, this can happen in any situation where the host pushes execution contexts with null ScriptOrModule components onto the execution context stack.

An implementation of HostLoadImportedModule must conform to the following requirements:

The actual process performed is host-defined, but typically consists of performing whatever I/O operations are necessary to load the appropriate Module Record. Multiple different (referrer, specifier) pairs may map to the same Module Record instance. The actual mapping semantics is host-defined but typically a normalization process is applied to specifier as part of the mapping process. A typical normalization process would include actions such as expansion of relative and abbreviated path specifiers.

Note 2

Implementations may provide unobservable module loading optimizations, such as speculative preloading of modules that are likely to be requested next. When doing so, they should consider whether the module is being imported for its source phase, which won't cause calls to the HostLoadImportedModule hook for its transitive dependencies, or for its evaluation phase.

16.1.1.9 FinishLoadingImportedModule ( referrer, specifier, payload, result )

The abstract operation FinishLoadingImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), specifier (a String), payload (a GraphLoadingState Record or a PromiseCapability RecordDynamicImportState 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 Record record such that record.[[Specifier]] is specifier, then
      1. Assert: record.[[Module]] is result.[[Value]].
    2. Else, append the Record { [[Specifier]]: specifier, [[Module]]: result.[[Value]] } to referrer.[[LoadedModules]].
  2. If payload is a GraphLoadingState Record, then
    1. Perform ContinueModuleLoading(payload, referrer, specifier, result).
  3. Else,
    1. Perform ContinueDynamicImport(payload, result).

16.2 Imports

Syntax

ImportDeclaration : import ImportClause FromClause ; import ModuleSpecifier ; import source ImportedBinding FromClause ; ImportClause : ImportedDefaultBinding NameSpaceImport NamedImports ImportedDefaultBinding , NameSpaceImport ImportedDefaultBinding , NamedImports ImportedDefaultBinding : ImportedBinding NameSpaceImport : * as ImportedBinding NamedImports : { } { ImportsList } { ImportsList , } FromClause : from ModuleSpecifier ImportsList : ImportSpecifier ImportsList , ImportSpecifier ImportSpecifier : ImportedBinding ModuleExportName as ImportedBinding ModuleSpecifier : StringLiteral ImportedBinding : BindingIdentifier[~Yield, +Await]

16.2.1 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 ImportEntries of ModuleItemList.
  2. Let entries2 be 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 ;
  1. Let module be the sole element of ModuleRequests of FromClause.
  2. Return ImportEntriesForModule of ImportClause with argument module.
ImportDeclaration : import ModuleSpecifier ;
  1. Return a new empty List.
ImportDeclaration : import source ImportedBinding FromClause ;
  1. Let localName be the sole element of BoundNames of ImportedBinding.
  2. Let entry be the ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: source, [[LocalName]]: localName }.
  3. Return « entry ».

28 Reflection

28.1 Module Source Objects

Module Source Objects represent modules in their source import phase, which are not linked, instantiated or executed.

All Module Source Objects should have a prototype of %AbstractModuleSource%.prototype and define a [[ModuleSourceRecord]] internal slot.

Hosts may define their own Module Source subclasses for custom module record types.

28.1.1 The %AbstractModuleSource% Constructor

The %AbstractModuleSource% constructor:

  • is %AbstractModuleSource%.
  • along with its corresponding prototype object, provides common properties that are inherited by module source constructors and their instances.
  • does not have a global name or appear as a property of the global object.
  • acts as the abstract superclass of the ModuleSource constructor.
  • will throw an error when invoked, because it is an abstract class constructor. The module source constructors do not perform a super call to it.

28.1.1.1 %AbstractModuleSource% ( )

This function performs the following steps when called:

  1. Throw a TypeError exception.

The "length" property of this function is +0𝔽.

28.1.2 Properties of the %AbstractModuleSource% Intrinsic Object

The %AbstractModuleSource% intrinsic object:

  • has a [[Prototype]] internal slot whose value is %Function.prototype%.
  • has a "name" property whose value is "AbstractModuleSource".
  • has the following properties:

28.1.2.1 %AbstractModuleSource%.prototype

The initial value of %AbstractModuleSource%.prototype is the %AbstractModuleSource% prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

28.1.3 Properties of the %AbstractModuleSource% Prototype Object

The %AbstractModuleSource% prototype object:

  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is %AbstractModuleSource.prototype%.
  • is an ordinary object.
  • does not have a global name or appear as a property of the global object.
  • does not have a [[ModuleSourceRecord]] slot that is specific to AbstractModuleSource and AbstractModuleSource subclass instance objects.
  • has the following properties:

28.1.3.1 %AbstractModuleSource%.prototype.constructor

The initial value of %AbstractModuleSource%.prototype.constructor is %AbstractModuleSource%.

28.1.3.2 get %AbstractModuleSource%.prototype [ @@toStringTag ]

%AbstractModuleSource%.prototype [@@toStringTag] is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps when called:

  1. Let O be the this value.
  2. If O is not an Object, return undefined.
  3. If O does not have a [[ModuleSourceRecord]] internal slot, return undefined.
  4. Let name be O.[[ModuleSourceRecord]].[[SourceClassName]]
  5. Assert: name is a String.
  6. Return name.

This property has the attributes { [[Enumerable]]: false, [[Configurable]]: true }.

The initial value of the "name" property of this function is "get [Symbol.toStringTag]".

A Host Layering Points

A.1 Host-defined Fields

[[HostDefined]] on Realm Records: See Table 24.

[[HostDefined]] on Script Records: See Table 39.

[[HostDefined]] on Module Records: See Table 4.

[[HostDefined]] on ModuleSource Records: See Table 3.

[[HostDefined]] on JobCallback Records: See Table 28.

[[HostSynchronizesWith]] on Candidate Executions: See Table 90.

[[IsHTMLDDA]]: See B.3.6.

B Copyright & Software License

Copyright Notice

© 2023 Luca Casonato, Guy Bedford, Nicolò Ribaudo

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.