Stage 1 Draft / December 19, 2022

Module & ModuleSource API

1 Well-known intrinsic objects

Table 1: Well-known Intrinsic Objects
Intrinsic Name Global Name ECMAScript Language Association
%ModuleSource% ModuleSource The ModuleSource constructor (20.2)
%Module% Module The Module constructor (21.2)

16 ECMAScript Language: Scripts and Modules

16.2.1 Module Semantics

16.2.1.5 Cyclic Module Records

In addition to the fields defined in Table 44 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]]
[[EvaluationError]]
[[DFSIndex]]
[[DFSAncestorIndex]]
[[RequestedModules]]
[[LoadedModules]] a List of Records with fields [[Specifier]] (a String) and [[Module]] (a Module Record) A map from the specifier strings used by the module represented by this record to request the importation of a module to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]].
[[LoadingModules]] a List of Records with fields [[Specifier]] (a String) and [[LoadStates]] (a List of either GraphLoadingState Records or PromiseCapability Records) A map from the specifier strings imported by this module to the states of the loading processes that are waiting for the resolved module record. It is used to avoid multiple calls to the loading hook with the same (specifier, referrer) pair. The list does not contain two different Records with the same [[Specifier]]. Editor's Note
This field must also be added to Script Records and Realm Records, in parallel to the existing [[LoadedModules]] fields.
[[CycleRoot]]
[[HasTLA]]
[[AsyncEvaluation]]
[[TopLevelCapability]]
[[AsyncParentModules]]
[[PendingAsyncDependencies]]

16.2.1.5.1 LoadRequestedModules ( [ hostDefined ] )

The LoadRequestedModules concrete method of a Cyclic Module Record module takes optional argument hostDefined (anything) and returns a Promise object.

16.2.1.5.1.1 InnerModuleLoading ( state, module )

The abstract operation InnerModuleLoading takes arguments state (a GraphLoadingState Record) and module (a Module Record) and returns unused. It is used by LoadRequestedModules to recursively perform the actual loading process for module's dependency graph. It performs the following steps when called:

  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
    1. Append module to state.[[Visited]].
    2. Let requestedModulesCount be the length of module.[[RequestedModules]].
    3. Set state.[[PendingModulesCount]] to state.[[PendingModulesCount]] + requestedModulesCount.
    4. For each String required of module.[[RequestedModules]], do
      1. If module.[[LoadedModules]] contains a Record record whose [[Specifier]] is required, then
        1. Perform InnerModuleLoading(state, record.[[Module]]).
      2. Else,
        1. Perform HostLoadImportedModuleLoadImportedModule(module, required, state.[[HostDefined]], state).
        2. NOTE: HostLoadImportedModuleLoadImportedModule 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 in 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.2.1.6 Source Text Module Records

In addition to the fields defined in Table 2, Source Text Module Records have the additional fields listed in Table 3. Each of these fields is initially set in ParseModule.

Table 3: Additional Fields of Source Text Module Records
Field Name Value Type Meaning
...
[[ModuleInstance]] An instance of a %Module% constructor or undefined. A Module Instance or undefined if no Module Instance is associated to this Record.

16.2.1.7 LoadImportedModule ( referrer, specifier, hostDefined, state )

The abstract operation LoadImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), specifier (a String), hostDefined (anything), and state (a GraphLoadingState Record or a PromiseCapability Record) and returns unused. It performs the following steps when called:

  1. If referrer.[[LoadedModules]] contains a Record loaded whose [[Specifier]] is specifier, then
    1. Let module be loaded.[[Module]].
    2. Perform FinishLoadingImportedModule(referrer, specifier, NormalCompletion(module)).
    3. Return unused.
  2. If referrer.[[LoadingModules]] contains a Record loading whose [[Specifier]] is specifier, then
    1. Add state to loading.[[LoadStates]].
    2. Return unused.
  3. Append the Record { [[Specifier]]: specifier, [[LoadStates]]: « state » } to referrer.[[LoadingModules]].
  4. If referrer is not a Source Text Module Record, referrer.[[ModuleInstance]] is undefined, or referrer.[[ModuleInstance]].[[ImportHook]] is undefined, then
    1. Perform HostLoadImportedModule(referrer, specifier, hostDefined).
    2. Return unused.
  5. Let importHookResult be Completion(Call(referrer.[[ModuleInstance]].[[ImportHook]], referrer.[[ModuleInstance]].[[HandlerValue]], « specifier »).
  6. If importHookResult is an abrupt completion, then
    1. Perform FinishLoadingImportedModule(referrer, specifier, importHookResult).
    2. Return unused.
  7. Let importHookPromise be Completion(PromiseResolve(%Promise%, importHookResult.[[Value]])).
  8. If importHookPromise is an abrupt completion, then
    1. Perform FinishLoadingImportedModule(referrer, specifier, importHookPromise).
    2. Return unused.
  9. Let fulfilledClosure be a new Abstract Closure with parameters (result) that captures referrer and specifier, and performs the following steps when called:
    1. Let completion be null.
    2. If Type(result) is Object and result has a [[ImportHook]] internal slot, then
      1. Set completion to NormalCompletion(result.[[Module]]).
    3. Else,
      1. Set completion to ThrowCompletion(a newly created TypeError object).
    4. Perform FinishLoadingImportedModule(referrer, specifier, completion).
    5. Return unused.
  10. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
  11. Let rejectedClosure be a new Abstract Closure with parameters (error) that captures referrer and specifier, and performs the following steps when called:
    1. Perform FinishLoadingImportedModule(referrer, specifier, ThrowCompletion(error)).
    2. Return unused.
  12. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
  13. Perform PerformPromiseThen(importHookPromise.[[Value]], onFulfilled, onRejected).
  14. Return unused.

16.2.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 Record) and returns unused.

Note

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.

16.2.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 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 whose [[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. Let loading be the Record in referrer.[[LoadingModules]] whose [[Specifier]] is specifier.
  3. Assert: loading exists and is unique.
  4. Remove loading from referrer.[[LoadingModules]].
  5. For each Record state in loading.[[LoadStates]], do
    1. If payloadstate is a GraphLoadingState Record, then
      1. Perform ContinueModuleLoading(payloadstate, result).
    2. Else,
      1. Perform ContinueDynamicImport(payloadstate, result).
  6. Return unused.

17 Meta Properties

17.1 Runtime Semantics: Evaluation

ImportMeta : import . meta
  1. Let module be GetActiveScriptOrModule().
  2. Assert: module is a Source Text Module Record.
  3. Let importMeta be module.[[ImportMeta]].
  4. If importMeta is empty, then
    1. Set importMeta to OrdinaryObjectCreate(null).
    2. If module.[[ModuleInstance]] is undefined or module.[[ModuleInstance]].[[ImportMetaHook]] is undefined, then
      1. Let importMetaValues be HostGetImportMetaProperties(module).
      2. For each Record { [[Key]], [[Value]] } p of importMetaValues, do
        1. Perform ! CreateDataPropertyOrThrow(importMeta, p.[[Key]], p.[[Value]]).
      3. Perform HostFinalizeImportMeta(importMeta, module).
    3. Else,
      1. Let importMetaHook be module.[[ModuleInstance]].[[ImportMetaHook]].
      2. Let handler be module.[[ModuleInstance]].[[HandlerValue]].
      3. Perform ? Call(importMetaHook, handler, « importMeta »).
    4. Set module.[[ImportMeta]] to importMeta.
    5. Return importMeta.
  5. Else,
    1. Assert: Type(importMeta) is Object.
    2. Return importMeta.

18 Module Source Records

A Module Source Record is used to represent information about a module source that was defined from ECMAScript source text (11) that was parsed using the goal symbol Module. Its fields contain digested information about the names that are imported and exported by the module.

Module Source Records have the fields listed in Table 4. Each of these fields is initially set in CreateModuleSourceRecord.

Table 4: Fields of Module Source Records
Field Name Value Type Meaning
[[ECMAScriptCode]] a Parse Node The result of parsing the source text of this module using Module as the goal symbol.
[[ImportEntries]] a List of ImportEntry Records A List of ImportEntry records derived from the code of this module source.
[[LocalExportEntries]] a List of ExportEntry Records A List of ExportEntry records derived from the code of this module that correspond to declarations that occur within the module source.
[[IndirectExportEntries]] a List of ExportEntry Records A List of ExportEntry records derived from the code of this module source that correspond to reexported imports that occur within the module or exports from export * as namespace declarations.
[[StarExportEntries]] a List of ExportEntry Records A List of ExportEntry records derived from the code of this module source that correspond to export * declarations that occur within the module, not including export * as namespace declarations.
[[HasTLA]] a Boolean Whether this module source is individually asynchronous. Having an asynchronous dependency does not mean this field is true.
[[RequestedModules]] a List of Strings A List of all the ModuleSpecifier strings used by the module source represented by this record to request the importation of a module. The List is source text occurrence ordered.
[[HostDefined]] anything (default value is undefined) Field reserved for use by host environments that need to associate additional information with a module source.
Editor's Note
A Module Source Record is the static portion of a Module Record. A refactor of the spec can make this separation more formal instead of just copying internal slot from one record to another.

19 Import Calls

19.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 specifierspecifierOrModule be ? GetValue(argRef).
  5. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  6. If Type(specifierOrModule) is Object that has a [[ModuleSourceInstance]] internal slot, then
    1. Perform ContinueDynamicImport(promiseCapability, specifierOrModule.[[Module]]).
  7. Else,
    1. Let specifierString be Completion(ToString(specifierspecifierOrModule)).
    2. IfAbruptRejectPromise(specifierString, promiseCapability).
    3. Perform HostLoadImportedModuleLoadImportedModule(referrer, specifierString, empty, promiseCapability).
  8. Return promiseCapability.[[Promise]].

20 ModuleSource Objects

20.1 ModuleSource Abstract Operations

20.1.1 CreateModuleSourceRecord ( body )

The abstract operation CreateModuleSourceRecord takes argument body (Parse Node) and returns a Module Source Record. It creates a Module Source Record based upon a Module Parse Node. It performs the following steps when called:

  1. Let requestedModules be the ModuleRequests of body.
  2. Let importEntries be ImportEntries of body.
  3. Let importedBoundNames be ImportedLocalNames(importEntries).
  4. Let indirectExportEntries be a new empty List.
  5. Let localExportEntries be a new empty List.
  6. Let starExportEntries be a new empty List.
  7. Let exportEntries be ExportEntries of body.
  8. For each ExportEntry Record ee of exportEntries, do
    1. If ee.[[ModuleRequest]] is null, then
      1. If ee.[[LocalName]] is not an element of importedBoundNames, then
        1. Append ee to localExportEntries.
      2. Else,
        1. Let ie be the element of importEntries whose [[LocalName]] is the same as 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.
  9. Let async be body Contains await.
  10. NOTE: How should hostDefined be populated if this operation is triggered by the user and whether or not hostDefined should be used for sources created in user land.
  11. Let hostDefined be undefined.
  12. Return Module Source Record { [[HasTLA]]: async, [[ECMAScriptCode]]: body, [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries, [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[HostDefined]]: hostDefined }.
Editor's Note
A Module Source Record is the static portion of a Module Record. A refactor of the spec can make this separation more formal instead of just having both of them sharing the same set of Internal Slots.

20.2 The ModuleSource Constructor

The ModuleSource constructor:

  • is the intrinsic object %ModuleSource%.
  • is the initial value of the "ModuleSource" property of the global object.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • creates and initializes a new ModuleSource object when called as a constructor.

20.2.1 ModuleSource ( sourceText )

When the ModuleSource function is called with argument sourceText, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%ModuleSource.prototype%", « [[ModuleSource]] »).
  3. Let body be ParseText(sourceText, Module).
  4. If body is a List of errors, throw a SyntaxError exception.
  5. Set O.[[ModuleSource]] to ? CreateModuleSourceRecord(body).
  6. Return O.

20.3 Properties of the ModuleSource Constructor

The ModuleSource constructor:

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

20.3.1 ModuleSource.prototype

The initial value of ModuleSource.prototype is %ModuleSource.prototype%.

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

20.4 Properties of the ModuleSource Prototype Object

The ModuleSource prototype object:

20.4.1 ModuleSource.prototype.constructor

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

20.4.2 ModuleSource.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "ModuleSource".

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

20.5 Properties of ModuleSource Instances

ModuleSource instances are ordinary objects that inherit properties from the ModuleSource prototype object (the intrinsic, %ModuleSource.prototype%). ModuleSource instances are initially created with the internal slots described in Table 5.

Table 5: Internal Slots of ModuleSource Instances
Internal Slot Type Description
[[ModuleSource]] Module Source Record The Module Source Record for the provided source text.

21 Module Objects

21.1 Module Abstract Operations

21.1.1 CreateModuleRecord ( moduleSource )

The abstract operation CreateModuleRecord takes argument moduleSource (a Module Source Record) and returns a Source Text Module Record. It creates a Source Text Module Record based upon the result of a previously parsed sourceText as a Module associated to the provided Module Source Record. It performs the following steps when called:

  1. Assert: moduleSource is a Module Source Record.
  2. Let async be sourceModule.[[HasTLA]].
  3. Let body be sourceModule.[[ECMAScriptCode]].
  4. Let requestedModules be sourceModule.[[RequestedModules]].
  5. Let importEntries be sourceModule.[[ImportEntries]].
  6. Let localExportEntries be sourceModule.[[LocalExportEntries]].
  7. Let indirectExportEntries be sourceModule.[[IndirectExportEntries]].
  8. Let starExportEntries be sourceModule.[[StarExportEntries]].
  9. Let hostDefined be sourceModule.[[HostDefined]].
  10. Let realm be the current Realm Record.
  11. Return Source Text Module Record { [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[CycleRoot]]: empty, [[HasTLA]]: async, [[AsyncEvaluation]]: false, [[TopLevelCapability]]: empty, [[AsyncParentModules]]: « », [[PendingAsyncDependencies]]: empty, [[Status]]: unlinked, [[EvaluationError]]: empty, [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[ImportMeta]]: empty, [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries, [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: empty, [[DFSAncestorIndex]]: empty, [[ModuleInstance]]: undefined }.

21.2 The Module Constructor

The Module constructor:

  • is the intrinsic object %Module%.
  • is the initial value of the "Module" property of the global object.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • creates and initializes a new Module object when called as a constructor.

21.2.1 Module ( moduleSource, handler )

When the Module function is called with the arguments moduleSource and handler, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Perform ? RequireInternalSlot(moduleSource, [[ModuleSource]]).
  3. Let moduleRecord to ! CreateModuleRecord(moduleSource.[[ModuleSource]]).
  4. If Type(handler) is Object, then
    1. Let importHook be ? GetMethod(handler, "importHook").
    2. If importHook is not undefined and IsCallable(importHook) is false, throw a TypeError exception.
    3. Let importMetaHook be ? GetMethod(handler, "importMetaHook").
    4. If importMetaHook is not undefined and IsCallable(importMetaHook) is false, throw a TypeError exception.
  5. Else if handler is undefined, then
    1. Let importHook be undefined.
    2. Let importMetaHook be undefined.
  6. Else,
    1. Throw a TypeError exception.
  7. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%Module.prototype%", « [[Module]], [[ModuleSourceInstance]], [[HandlerValue]], [[ImportHook]], [[ImportMetaHook]] »).
  8. Set O.[[ModuleSourceInstance]] to moduleSource.
  9. Set O.[[HandlerValue]] be handler.
  10. Set O.[[ImportHook]] be importHook.
  11. Set O.[[ImportMetaHook]] be importMetaHook.
  12. Set moduleRecord.[[ModuleInstance]] to O.
  13. Set O.[[Module]] to moduleRecord.
  14. Return O.

21.3 Properties of the Module Constructor

The Module constructor:

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

21.3.1 Module.prototype

The initial value of Module.prototype is %Module.prototype%.

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

21.4 Properties of the Module Prototype Object

The Module prototype object:

  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • is %Module.prototype%.
  • is an ordinary object.
  • does not have a [[Module]] or any other of the internal slots that are specific to Realm instance objects.

21.4.1 Module.prototype.constructor

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

21.4.2 get Module.prototype.source

Module.prototype.source is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

  1. Let M be the this value.
  2. Perform ? RequireInternalSlot(M, [[ModuleSourceInstance]]).
  3. Return M.[[ModuleSourceInstance]].

21.4.3 Module.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Module".

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

21.5 Properties of Module Instances

Module instances are ordinary objects that inherit properties from the Module prototype object (the intrinsic, %Module.prototype%). Module instances are initially created with the internal slots described in Table 6.

Table 6: Internal Slots of Module Instances
Internal Slot Type Description
[[Module]] Source Text Module Record The Source Text Module Record that represents this Module Instance.
[[ModuleSourceInstance]] ModuleSource Instance or null The ModuleSource Instance associated to Module Instance. null if this Module Instance has not a source associated to it.
[[HandlerValue]] an ECMAScript language value This is the this value used for invocation of the hook functions.
[[ImportHook]] a function object or undefined Defaults to undefined. The function can return a module instance to resolve module dependencies.
[[ImportMetaHook]] a function object or undefined Defaults to undefined. The function can augment the import.meta object provided as the first argument.
Editor's Note
A Module Instance without a [[ModuleSourceInstance]] value associated to it is a Module Instance created via the Import Reflection API where the host decides that the source is not available. E.g.: fs module or any built-in module in the future.