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

A conforming implementation of ECMAScript should not implement Deprecated subclauses or algorithm steps, unless necessary for compatibility with existing applications that already run in such implementation before the deprecation of the given language feature. All of the language features and behaviours specified within Deprecated subclauses or algorithm steps have one or more undesirable characteristics. However, their use in existing applications currently prevents their removal from this specification. These features are not considered part of the core ECMAScript language. Programmers should not use or assume the existence of these features and behaviours when writing new ECMAScript code.

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] ,opt ) import ( AssignmentExpression[+In, ?Yield, ?Await] , AssignmentExpression[+In, ?Yield, ?Await] ,opt )

13.3.10 Import Calls

13.3.10.1 Runtime Semantics: Evaluation

ImportCall : import ( AssignmentExpression ,opt )
  1. Return ? EvaluateImportCall(AssignmentExpression).
ImportCall : import ( AssignmentExpression , AssignmentExpression ,opt )
  1. Return ? EvaluateImportCall(the first AssignmentExpression, the second AssignmentExpression).
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 EvaluateImportCall ( specifierExpression [ , optionsExpression ] )

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 ModuleRequest and ImportAttribute Records

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.

A LoadedModuleRequest Record represents the request to import a module together with the resulting Module Record. It consists of the same fields defined in table Table 1, with the addition of [[Module]]:

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

An ImportAttribute Record consists of the following fields:

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 ModuleRequestsEqual ( left, right )

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 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. If moduleNamesrequests does not contain name a ModuleRequest Record mr2 such that ModuleRequestsEqual(mr, mr2) is true, 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, [[Attributes]]: « » }.
ImportDeclaration : import ImportClause 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 { [[Specifer]]: specifier, [[Attributes]]: attributes }.
ImportDeclaration : import ModuleSpecifier ;
  1. Let specifier be the SV of ModuleSpecifier.
  2. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: « » }.
ImportDeclaration : import ModuleSpecifier WithClause ;
  1. Let specifier be the SV of ModuleSpecifier.
  2. Let attributes be WithClauseToAttributes of WithClause.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: attributes }.
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, [[Attributes]]: « » }.
ExportDeclaration : export ExportFromClause FromClause WithClause ;
  1. Let specifier be SV of FromClause.
  2. Let attributes be WithClauseToAttributes of WithClause.
  3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: attributes }.
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 StringsModuleRequest Records A List of all the ModuleSpecifier strings and import attributes 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)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 attributes to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]]([[Specifier]], [[Attributes]]) pair.
[[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 StringModuleRequest Record request of module.[[RequestedModules]], do
      1. If AllImportAttributesSupported(request.[[Attributes]]) is false, then
        1. Let error be ThrowCompletion(a newly created SyntaxError object).
        2. Perform ContinueModuleLoading(state, error).
      2. Else if module.[[LoadedModules]] contains a Record record such that record.[[Specifier]] is request LoadedModuleRequest Record record such that ModuleRequestsEqual(record, request) is true, then
        1. Perform InnerModuleLoading(state, record.[[Module]]).
      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.
  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 ModuleRequest Record String value of the ModuleSpecifier of the ImportDeclaration. ModuleRequest Record representing the ModuleSpecifier and import attributes of the ImportDeclaration.
[[ImportName]]
[[LocalName]]

16.2.1.8 HostLoadImportedModule ( referrer, specifier, moduleRequest, 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), moduleRequest (a ModuleRequest Record), 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(referrer, moduleRequest.[[Specifer]], moduleRequest.[[Attributes]]) triples 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, moduleRequest, payload, result )

The abstract operation FinishLoadingImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), specifier (a String), 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 RecordLoadedModuleRequest record such that record.[[Specifier]] is specifierModuleRequestsEqual(record, moduleRequest) is true, then
      1. Assert: record.[[Module]] is result.[[Value]].
    2. Else, append the Record { [[Specifier]]: specifiermoduleRequest.[[Specifer]], [[Attributes]]: moduleRequest.[[Attributes]], [[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 AllImportAttributesSupported ( attributes )

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 HostGetSupportedImportAttributes ( )

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
The purpose of requiring the host to specify its supported import attributes, rather than passing all attributes to the host and letting it then choose which ones it wants to handle, is to ensure that unsupported attributes are handled in a consistent way across different hosts.

16.2.2 Imports

ImportDeclaration : import ImportClause FromClause WithClauseopt ; import ModuleSpecifier WithClauseopt ; WithClause : AttributesKeyword { } AttributesKeyword { WithEntries ,opt } AttributesKeyword : with WithEntries : AttributeKey : StringLiteral AttributeKey : StringLiteral , WithEntries AttributeKey : IdentifierName StringLiteral Note

This section is extended by 16.2.2.3.

16.2.2.1 Static Semantics: Early Errors

WithClause : AttributesKeyword { WithEntries ,opt }

16.2.2.2 Static Semantics: WithClauseToAttributes

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 Deprecated assert keyword for Import Attributes

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

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.