Stage 3 Draft / September 28, 2023

Import Attributes

See the explainer for information.

The relevant syntax changes are in the Import Calls and Imports sections.

This feature would ideally use the with keyword to denote attributes, but there are existing implementations based on a previous version of the proposal using the assert keyword. Due to potential web compatibility risks, the proposal still includes assert marked as deprecated. Usage of the old syntax is discouraged, and its removal is being investigated.

Editor's Note

This document might be out of date. Please refer to the tc39/ecma262#3057 preview for the latest version.

2 Conformance

2.1 Example Deprecated Clause Heading

Example clause contents.

13 ECMAScript Language: Expressions

13.3 Left-Hand-Side Expressions

Syntax

ImportCall[Yield, Await] : import ( AssignmentExpression[+In, ?Yield, ?Await] )

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]].

13.3.10.2

The abstract operation EvaluateImportCall takes argument specifierExpression (a ParseNode) and optional argument optionsExpression (a ParseNode) and returns either a normal completion containing a Promise or a throw 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 specifierRef be the result of evaluating specifierExpression.
  4. Let specifier be ? GetValue(specifierRef).
  5. If optionsExpression is present, then
    1. Let optionsRef be the result of evaluating optionsExpression.
    2. Let options be ? GetValue(optionsRef).
  6. Else,
    1. Let options be undefined.
  7. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  8. Let specifierString be Completion(ToString(specifier)).
  9. IfAbruptRejectPromise(specifierString, promiseCapability).
  10. Let attributes be a new empty List.
  11. If options is not undefined, then
    1. If Type(options) is not 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 the host supports the deprecated assert keyword for import attributes and attributesObj is undefined, then
      1. Set attributesObj to Completion(Get(options, "assert")).
      2. IfAbruptRejectPromise(attributesObj, promiseCapability).
    5. If attributesObj is not undefined, then
      1. If Type(attributesObj) is not 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 entry of entries, do
        1. Let key be ! Get(entry, "0").
        2. Let value be ! Get(entry, "1").
        3. If Type(value) is not String, then
          1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
          2. Return promiseCapability.[[Promise]].
        4. Append the ImportAttribute Record { [[Key]]: key, [[Value]]: value } to attributes.
    6. If AllImportAttributesSupported(attributes) is false, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    7. Sort attributes according to the lexicographic order of their [[Key]] fields, 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 distinguishing among attributes by the order they occur in.
  12. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Attributes]]: attributes }.
  13. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
  14. Return promiseCapability.[[Promise]].
Note
Removal of the assert fallback when options's with property is undefined is being investigated.

16 ECMAScript Language: Scripts and Modules

16.2 Modules

16.2.1 Module Semantics

16.2.1.1

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

Table 1: ModuleRequest Record fields
Field Name Value Type Meaning
[[Specifier]] String The module specifier
[[Attributes]] a List of ImportAttribute Records The import attributes
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.

Table 2: LoadedModuleRequest Record fields
Field Name Value Type Meaning
[[Specifier]] a String The module specifier
[[Attributes]] a List of ImportAttribute Records The import attributes
[[Module]] a Module Record The loaded module corresponding to this module request

Table 3: ImportAttribute Record fields
Field Name Value Type Meaning
[[Key]] String The attribute key
[[Value]] String The attribute value

16.2.1.1.1

The abstract operation ModuleRequestsEqual takes arguments left (a ModuleRequest Record or a LoadedModuleRequest Record) and right (a ModuleRequest Record or a LoadedModuleRequest Record) and returns a Boolean. It performs the following steps when called:

  1. If left.[[Specifier]] is not right.[[Specifier]], return false.
  2. Let leftAttrs be left.[[Attributes]].
  3. Let rightAttrs be right.[[Attributes]].
  4. Let leftAttrsCount be the number of elements in leftAttrs.
  5. Let rightAttrsCount be the number of elements in rightAttrs.
  6. If leftAttrsCountrightAttrsCount, return false.
  7. For each ImportAttribute Record l of leftAttrs, do
    1. Let found be false.
    2. For each ImportAttribute Record r of rightAttrs, do
      1. If l.[[Key]] is r.[[Key]], then
        1. If l.[[Value]] is r.[[Value]], then
          1. Assert: found is false.
          2. Set found to true.
        2. Else,
          1. Return false.
    3. If found is false, return false.
  8. Return true.

16.2.1.3 Static Semantics: ModuleRequests

The syntax-directed operation ModuleRequests takes no arguments and returns a List of Strings. 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 moduleNames be ModuleRequests of ModuleItemList.
  2. Let additionalNames be ModuleRequests of ModuleItem.
  3. For each String name of additionalNames, do
    1. If moduleNames does not contain name , then
      1. Append name to moduleNames.
  4. Return moduleNames.
ModuleItem : StatementListItem
  1. Return a new empty List.
ImportDeclaration : import ImportClause FromClause ;
  1. Return ModuleRequests of FromClause.
ModuleSpecifier : StringLiteral
  1. Return a List whose sole element is the SV of StringLiteral.
ExportDeclaration : export ExportFromClause FromClause ;
  1. Return ModuleRequests of FromClause.
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.5 Cyclic Module Records

A Cyclic Module Record is used to represent information about a module that can participate in dependency cycles with other modules that are subclasses of the Cyclic Module Record type. Module Records that are not subclasses of the Cyclic Module Record type must not participate in dependency cycles with Source Text Module Records.

In addition to the fields defined in Table 40 Cyclic Module Records have the additional fields listed in Table 4

Table 4: Additional Fields of Cyclic Module Records
Field Name Value Type Meaning
[[Status]]
[[EvaluationError]]
[[DFSIndex]]
[[DFSAncestorIndex]]
[[RequestedModules]] a List of Strings A List of all the ModuleSpecifier strings used by the module represented by this record to request the importation of a module. The List is in source text occurrence order.
[[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]].
[[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.

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 number of elements in module.[[RequestedModules]].
    3. Set state.[[PendingModulesCount]] to state.[[PendingModulesCount]] + requestedModulesCount.
    4. For each String request of module.[[RequestedModules]], do
      1. if module.[[LoadedModules]] contains a Record record such that record.[[Specifier]] is request , then
        1. Perform InnerModuleLoading(state, record.[[Module]]).
      2. Else,
        1. Perform HostLoadImportedModule(module, request, 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.2.1.6 Source Text Module Records

An ImportEntry Record is a Record that digests information about a single declarative import. Each ImportEntry Record has the fields defined in Table 5:

Table 5: ImportEntry Record Fields
Field Name Value Type Meaning
[[ModuleRequest]] String String value of the ModuleSpecifier of the ImportDeclaration.
[[ImportName]]
[[LocalName]]

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 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, result).
  3. Else,
    1. Perform ContinueDynamicImport(payload, result).
  4. Return unused.
Editor's Note

The description of the [[LoadedModules]] field of Realm Record, Script Record, and Cyclic Module Record should be updated to use LoadedModuleRequest Records.

16.2.1.10

The abstract operation AllImportAttributesSupported takes argument attributes (a List of ImportAttribute Records) and returns a Boolean. It performs the following steps when called:

  1. Let supported be HostGetSupportedImportAttributes().
  2. For each ImportAttribute Record attribute of attributes, do
    1. If supported does not contain attribute.[[Key]], return false.
  3. Return true.

16.2.1.10.1

The host-defined abstract operation HostGetSupportedImportAttributes takes no arguments and returns a List of Strings. It allows host environments to specify which import attributes they support. Only attributes with supported keys will be provided to the host.

An implementation of HostGetSupportedImportAttributes must conform to the following requrements:

  • It must return a List of Strings, each indicating a supported attribute.
  • Each time this operation is called, it must return the same List with the same contents in the same order.
  • An implementation of HostGetSupportedImportAttributes must always complete normally (i.e., not return an abrupt completion).

The default implementation of HostGetSupportedImportAttributes is to return a new empty List.

Note

16.2.2 Imports

ImportDeclaration : import ImportClause FromClause ; import ModuleSpecifier ; Note

16.2.2.1 Static Semantics: Early Errors

16.2.2.2

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

WithClause : AttributesKeyword { }
  1. Return a new empty List.
WithClause : AttributesKeyword { WithEntries ,opt }
  1. Let attributes be WithClauseToAttributes of WithEntries.
  2. Sort attributes according to the lexicographic order of their [[Key]] fields, 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 distinguishing among attributes by the order they occur in.
  3. Return attributes.
WithEntries : AttributeKey : StringLiteral
  1. Let key be the PropName of AttributeKey.
  2. Let entry be the ImportAttribute Record { [[Key]]: key, [[Value]]: SV of StringLiteral }.
  3. Return « entry ».
WithEntries : AttributeKey : StringLiteral , WithEntries
  1. Let key be the PropName of AttributeKey.
  2. Let entry be the ImportAttribute Record { [[Key]]: key, [[Value]]: SV of StringLiteral }.
  3. Let rest be WithClauseToAttributes of WithEntries.
  4. Return the list-concatenation of « entry » and rest.

16.2.2.3

Import Attributes are denoted using the with keyword. However, there are existing implementations based on a previous version of the proposal using the assert keyword. Due to potential web compatibility risks, the assert keyword is still included in this specification, but its removal is being investigated.

This deprecated feature includes the assert fallback for import attributes in import calls (step 11.d of 13.3.10.2).

The following extends the AttributesKeyword production in 16.2.2:

AttributesKeyword : with [no LineTerminator here] assert

16.2.3 Exports

ExportDeclaration : export ExportFromClause FromClause ; 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] ;

A Sample host integration: The Web embedding

The import attributes proposal is intended to give key information about how modules are interpreted to hosts. For the Web embedding and environments which aim to be similar to it, the string is interpreted as the "module type". This is not the primary way the module type is determined (which, on the Web, would be the MIME type, and in other environments may be the file extension), but rather a secondary check which is required to pass for the module graph to load.

In the Web embedding, the following changes would be made to the HTML specification for import attributes:

The module map is keyed by the absolute URL and the type. Initially no other import attributes are supported, so they are not present.