This proposal would ideally use the withkeyword to denote assertions, but there are existing implementations based on the previous version of the proposal using the assertkeyword. Due to potential web compatibility risks, the proposal still includes assert marked as normative optional and legacy in sections 13.3.10.2 and 16.2.2. Usage of the old syntax is discouraged, and it removal is being investigated.
The abstract operation EvaluateImportCall takes argument specifierExpression (a ParseNode) and optional argument optionsExpression (a ParseNode) and returns a Promise. It performs the following steps when called:
Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
Return promiseCapability.[[Promise]].
Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
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.
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.
A List of all the ModuleSpecifier strings and import assertions used by the module represented by this record to request the importation of a module. The List is in source text occurrence order.
@@ -2975,7 +3007,7 @@
A map from the specifier strings used by the module represented by this record to request the importation of a module with the relative assertions to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]]([[Specifier]], [[Assertions]]) pair.
@@ -3030,8 +3062,8 @@
16.2.1.5 Cyclic Module Records
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 4:
An ImportEntry Record is a Record that digests information about a single declarative import. Each ImportEntry Record has the fields defined in Table 4:
If this operation is called multiple times with the same (referrer, specifier) pair(referrer, moduleRequest.[[Specifer]], moduleRequest.[[Assertions]]) triple and it performs FinishLoadingImportedModule(referrer, specifiermoduleRequest, payload, result) where result is a normal completion, then it must perform FinishLoadingImportedModule(referrer, specifiermoduleRequest, payload, result) with the same result each time.
-
-
It is recommended but not required that implementations additionally conform to the following stronger constraint:
-
-
-
If this operation is called multiple times with the same (referrer, moduleRequest.[[Specifier]]) pair and it performs FinishLoadingImportedModule(referrer, moduleRequest, payload, result) where result is a normal completion, then it must perform FinishLoadingImportedModule(referrer, moduleRequest, payload, result) with the same result each time.
-
-
-
- moduleRequest.[[Assertions]] must not influence the interpretation of the module or the module specifier; instead, it may be used to determine whether the algorithm completes normally or with an abrupt completion.
+ If this operation is called multiple times with the same (referrer, specifier) pair(referrer, moduleRequest.[[Specifer]], moduleRequest.[[Assertions]]) triple and it performs FinishLoadingImportedModule(referrer, specifiermoduleRequest, payload, result) where result is a normal completion, then it must perform FinishLoadingImportedModule(referrer, specifiermoduleRequest, payload, result) with the same result each time.
The operation must treat payload as an opaque value to be passed through to FinishLoadingImportedModule.
@@ -3111,18 +3134,14 @@
16.2.1.8 HostLoadImportedModule ( referrer<
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.[[Assertions]]) 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.
- Editor's Note
-
The above text implies that is recommended but not required that hosts do not use moduleRequest.[[Assertions]] as part of the module cache key. In either case, an exception thrown from an import with a given assertion list does not rule out success of another import with the same specifier but a different assertion list.
-
-
Assertions do not affect the contents of the module. Future follow-up proposals may relax this restriction with "evaluator attributes" that would change the contents of the module. There are three possible ways to handle multiple imports of the same module with "evaluator attributes":
-
+ Note 2
+
There are three possible ways to handle multiple imports of the same module with different valid assertions:
-
Race and use the attribute that was requested by the first import. This seems broken--the second usage is ignored.
-
Reject the module graph and don't load if attributes differ. This seems bad for composition--using two unrelated packages together could break, if they load the same module with disagreeing attributes.
-
Clone and make two copies of the module, for the different ways it's transformed. In this case, the attributes would have to be part of the cache key. These semantics would run counter to the intuition that there is just one copy of a module.
+
Race and use the assertion that was requested by the first import. The second usage is ignored.
+
Reject the module graph and don't load if assertions differ. This may be bad for composition: using two unrelated packages together could break, if they load the same module with disagreeing assertions.
+
Clone and make two copies of the module, for the different ways it's transformed. These semantics would run counter to the intuition that there is just one copy of a module for each specifier.
-
-
It's possible that one of these three options may make sense for a module load, on a case-by-case basis by attribute, but it's worth careful thought before making this choice.
+
It's possible that one of these three options may make sense for a module load, on a case-by-case basis by assertion, but it's worth careful thought before making this choice.
@@ -3143,23 +3162,29 @@
16.2.1.9.1 AssertionsEqual ( left
-
-
16.2.1.10 HostGetSupportedImportAssertions ( )
-
The host-defined abstract operation HostGetSupportedImportAssertions takes no arguments and returns a List of Strings. It allows host environments to specify which import assertions they support. Only assertions with supported keys will be provided to the host.
The abstract operation AllImportAssertionsSupported takes argument assertions (a List of ImportAssertion Records) and returns a Boolean. It performs the following steps when called:
If supported does not contain assertion.[[Key]], return false.
Return true.
-
An implementation of HostGetSupportedImportAssertions must conform to the following requrements:
+
+
16.2.1.10.1 HostGetSupportedImportAssertions ( )
+
The host-defined abstract operation HostGetSupportedImportAssertions takes no arguments and returns a List of Strings. It allows host environments to specify which import assertions they support. Only assertions with supported keys will be provided to the host.
-
-
It must return a List of Strings, each indicating a supported assertion.
+
An implementation of HostGetSupportedImportAssertions must conform to the following requrements:
-
Each time this operation is called, it must return the same List with the same contents.
+
+
It must return a List of Strings, each indicating a supported assertion.
-
An implementation of HostGetSupportedImportAssertions must always complete normally (i.e., not return an abrupt completion).
-
+
Each time this operation is called, it must return the same List with the same contents.
+
+
An implementation of HostGetSupportedImportAssertions must always complete normally (i.e., not return an abrupt completion).
+
-
The default implementation of HostGetSupportedImportAssertions is to return a new empty List.
+
The default implementation of HostGetSupportedImportAssertions is to return a new empty List.
- Note
The purpose of requiring the host to specify its supported import assertions, rather than passing all assertions to the host and letting it then choose which ones it wants to handle, is to ensure that unsupported assertions are handled in a consistent way across different hosts.
+ Note
The purpose of requiring the host to specify its supported import assertions, rather than passing all assertions to the host and letting it then choose which ones it wants to handle, is to ensure that unsupported assertions are handled in a consistent way across different hosts.
Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
The module script would have an additional item, which would be the module type, as a string (e.g., "json"), or undefined for a JavaScript module.
-
HostLoadImportedModule would take a ModuleRequest Record parameter in place of a specifier string, which would be passed down through several abstract operations to reach the fetch a single module script algorithm. Somewhere near the entrypoint, if the ModuleRequest Record's [[Assertions]] field has an element entry such that entry.[[Key]] is "type", then let type be entry.[[Value]]; otherwise let type be undefined. If the type is invalid, then an exception is thrown and module loading fails. Otherwise, this will equal the module type, if the module can be successfully fetched with a matching MIME type.
-
In the fetch the descendents of a module script algorithm, when iterating over [[RequestedModules]], the elements are ModuleRequest Records rather than just specifier strings; these Records is passed on to the internal module script graph fetching procedure (which sends it to "fetch a single module script". Other usage sites of [[RequestedModules]] ignore the assertion.
+
HostLoadImportedModule would take a ModuleRequest Record parameter in place of a specifier string, which would be passed down through several abstract operations to reach the fetch a single module script algorithm. Somewhere near the entrypoint, if the ModuleRequest Record's [[Assertions]] field has an element entry such that entry.[[Key]] is "type", then let type be entry.[[Value]]; otherwise let type be undefined. If the type is invalid, then an exception is thrown and module loading fails. Otherwise, this will equal the module type, if the module can be successfully fetched with a matching MIME type.
+
In the fetch the descendents of a module script algorithm, when iterating over [[RequestedModules]], the elements are ModuleRequest Records rather than just specifier strings; these Records is passed on to the internal module script graph fetching procedure (which sends it to "fetch a single module script". Other usage sites of [[RequestedModules]] ignore the assertion.
"Fetch a single module script" would check the assertion in two places:
The module map is keyed with both the absolute URL and the module type, so an existing entry will be found only if its type matches.
This proposal would ideally use the `with` keyword to denote assertions, but there are existing implementations based on the previous version of the proposal using the `assert` keyword. Due to potential web compatibility risks, the proposal still includes `assert` marked as normative optional and legacy in sections and . Usage of the old syntax is discouraged, and it removal is being investigated.
@@ -87,23 +119,27 @@
1. If Type(_options_) is not Object,
1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « a newly created *TypeError* object »).
1. Return _promiseCapability_.[[Promise]].
- 1. Let _assertionsObj_ be Completion(Get(_options_, *"assert"*)).
+ 1. Let _assertionsObj_ be Completion(Get(_options_, *"with"*)).
1. IfAbruptRejectPromise(_assertionsObj_, _promiseCapability_).
+ 1. [normative-optional-legacy=""] If _assertionsObj_ is *undefined*, then
+ 1. Let _assertionsObj_ be Completion(Get(_options_, *"assert"*)).
+ 1. IfAbruptRejectPromise(_assertionsObj_, _promiseCapability_).
1. If _assertionsObj_ is not *undefined*,
1. If Type(_assertionsObj_) is not Object,
1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « a newly created *TypeError* object »).
1. Return _promiseCapability_.[[Promise]].
1. Let _keys_ be Completion(EnumerableOwnPropertyNames(_assertionsObj_, ~key~)).
1. IfAbruptRejectPromise(_keys_, _promiseCapability_).
- 1. Let _supportedAssertions_ be ! HostGetSupportedImportAssertions().
1. For each String _key_ of _keys_,
1. Let _value_ be Completion(Get(_assertionsObj_, _key_)).
1. IfAbruptRejectPromise(_value_, _promiseCapability_).
1. If Type(_value_) is not String, then
1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « a newly created *TypeError* object »).
1. Return _promiseCapability_.[[Promise]].
- 1. If _supportedAssertions_ contains _key_, then
- 1. Append the ImportAssertion Record { [[Key]]: _key_, [[Value]]: _value_ } to _assertions_.
+ 1. Append the ImportAssertion Record { [[Key]]: _key_, [[Value]]: _value_ } to _assertions_.
+ 1. If AllImportAssertionsSupported(_assertions_) is *false*, then
+ 1. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*, « a newly created *TypeError* object »).
+ 1. Return _promiseCapability_.[[Promise]].
1. Sort _assertions_ by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
1. Let _moduleRequest_ be a new ModuleRequest Record { [[Specifier]]: _specifierString_, [[Assertions]]: _assertions_ }.
1. Perform HostLoadImportedModule(_referrer_, _moduleRequest_, ~empty~, _promiseCapability_).
@@ -478,16 +514,7 @@
The host environment must perform FinishLoadingImportedModule(_referrer_, _specifier__moduleRequest_, _payload_, _result_), where _result_ is either a normal completion containing the loaded Module Record or a throw completion, either synchronously or asynchronously.
-
If this operation is called multiple times with the same (_referrer_, _specifier_) pair(_referrer_, _moduleRequest_.[[Specifer]], _moduleRequest_.[[Assertions]]) triple and it performs FinishLoadingImportedModule(_referrer_, _specifier__moduleRequest_, _payload_, _result_) where _result_ is a normal completion, then it must perform FinishLoadingImportedModule(_referrer_, _specifier__moduleRequest_, _payload_, _result_) with the same _result_ each time.
-
-
It is recommended but not required that implementations additionally conform to the following stronger constraint:
-
-
-
If this operation is called multiple times with the same (_referrer_, _moduleRequest_.[[Specifier]]) pair and it performs FinishLoadingImportedModule(_referrer_, _moduleRequest_, _payload_, _result_) where _result_ is a normal completion, then it must perform FinishLoadingImportedModule(_referrer_, _moduleRequest_, _payload_, _result_) with the same _result_ each time.
-
-
-
- _moduleRequest_.[[Assertions]] must not influence the interpretation of the module or the module specifier; instead, it may be used to determine whether the algorithm completes normally or with an abrupt completion.
+ If this operation is called multiple times with the same (_referrer_, _specifier_) pair(_referrer_, _moduleRequest_.[[Specifer]], _moduleRequest_.[[Assertions]]) triple and it performs FinishLoadingImportedModule(_referrer_, _specifier__moduleRequest_, _payload_, _result_) where _result_ is a normal completion, then it must perform FinishLoadingImportedModule(_referrer_, _specifier__moduleRequest_, _payload_, _result_) with the same _result_ each time.
The operation must treat _payload_ as an opaque value to be passed through to FinishLoadingImportedModule.
@@ -496,18 +523,14 @@
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_.[[Assertions]]) 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.
-
-
The above text implies that is recommended but not required that hosts do not use _moduleRequest_.[[Assertions]] as part of the module cache key. In either case, an exception thrown from an import with a given assertion list does not rule out success of another import with the same specifier but a different assertion list.
-
-
Assertions do not affect the contents of the module. Future follow-up proposals may relax this restriction with "evaluator attributes" that would change the contents of the module. There are three possible ways to handle multiple imports of the same module with "evaluator attributes":
-
+
+
There are three possible ways to handle multiple imports of the same module with different valid assertions:
-
Race and use the attribute that was requested by the first import. This seems broken--the second usage is ignored.
-
Reject the module graph and don't load if attributes differ. This seems bad for composition--using two unrelated packages together could break, if they load the same module with disagreeing attributes.
-
Clone and make two copies of the module, for the different ways it's transformed. In this case, the attributes would have to be part of the cache key. These semantics would run counter to the intuition that there is just one copy of a module.
+
Race and use the assertion that was requested by the first import. The second usage is ignored.
+
Reject the module graph and don't load if assertions differ. This may be bad for composition: using two unrelated packages together could break, if they load the same module with disagreeing assertions.
+
Clone and make two copies of the module, for the different ways it's transformed. These semantics would run counter to the intuition that there is just one copy of a module for each specifier.
-
-
It's possible that one of these three options may make sense for a module load, on a case-by-case basis by attribute, but it's worth careful thought before making this choice.
+
It's possible that one of these three options may make sense for a module load, on a case-by-case basis by assertion, but it's worth careful thought before making this choice.
@@ -568,30 +591,50 @@
-
+
- HostGetSupportedImportAssertions ( ): a List of Strings
+ AllImportAssertionsSupported (
+ _assertions_: a List of ImportAssertion Records,
+ ): a Boolean
description
-
It allows host environments to specify which import assertions they support. Only assertions with supported keys will be provided to the host.
+
+
+ 1. Let _supported_ be HostGetSupportedImportAssertions().
+ 1. For each Record _assertion_ of _assertions_, do
+ 1. If _supported_ does not contain _assertion_.[[Key]], return *false*.
+ 1. Return *true*.
+
+
+
+
+
+ HostGetSupportedImportAssertions ( ): a List of Strings
+
+
+
+
description
+
It allows host environments to specify which import assertions they support. Only assertions with supported keys will be provided to the host.
+
-
An implementation of HostGetSupportedImportAssertions must conform to the following requrements:
+
An implementation of HostGetSupportedImportAssertions must conform to the following requrements:
-
-
It must return a List of Strings, each indicating a supported assertion.
+
+
It must return a List of Strings, each indicating a supported assertion.
-
Each time this operation is called, it must return the same List with the same contents.
+
Each time this operation is called, it must return the same List with the same contents.
-
An implementation of HostGetSupportedImportAssertions must always complete normally (i.e., not return an abrupt completion).
-
+
An implementation of HostGetSupportedImportAssertions must always complete normally (i.e., not return an abrupt completion).
+
-
The default implementation of HostGetSupportedImportAssertions is to return a new empty List.
+
The default implementation of HostGetSupportedImportAssertions is to return a new empty List.
- The purpose of requiring the host to specify its supported import assertions, rather than passing all assertions to the host and letting it then choose which ones it wants to handle, is to ensure that unsupported assertions are handled in a consistent way across different hosts.
+ The purpose of requiring the host to specify its supported import assertions, rather than passing all assertions to the host and letting it then choose which ones it wants to handle, is to ensure that unsupported assertions are handled in a consistent way across different hosts.
+
@@ -607,8 +650,12 @@
AssertClause :
+ `with` `{` `}`
+ `with` `{` AssertEntries `,`? `}`
+
`assert` `{` `}`
`assert` `{` AssertEntries `,`? `}`
+
AssertEntries :
AssertionKey `:` StringLiteral
@@ -624,10 +671,15 @@
It is a Syntax Error if AssertClauseToAssertions of |AssertClause| has two entries _a_ and _b_ such that _a_.[[Key]] is _b_.[[Key]].
+
It is a Syntax Error if AllImportAssertionsSupported(AssertClauseToAssertions of |AssertClause|) is *false*.
@@ -641,12 +693,20 @@
- AssertClause : `assert` `{` `}`
+
+ AssertClause :
+ `with` `{` `}`
+ `assert` `{` `}`
+
1. Return a new empty List.
- AssertClause : `assert` `{` AssertEntries `,`? `}`
+
+ AssertClause :
+ `with` `{` AssertEntries `,`? `}`
+ `assert` `{` AssertEntries `,`? `}`
+
1. Let _assertions_ be AssertClauseToAssertions of |AssertEntries|.
1. Sort _assertions_ by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
@@ -655,23 +715,17 @@
AssertEntries : AssertionKey `:` StringLiteral
- 1. Let _supportedAssertions_ be ! HostGetSupportedImportAssertions().
1. Let _key_ be StringValue of |AssertionKey|.
- 1. If _supportedAssertions_ contains _key_,
- 1. Let _entry_ be an ImportAssertion Record { [[Key]]: _key_, [[Value]]: StringValue of |StringLiteral| }.
- 1. Return a new List containing the single element, _entry_.
- 1. Otherwise, return a new empty List.
+ 1. Let _entry_ be the ImportAssertion Record { [[Key]]: _key_, [[Value]]: StringValue of |StringLiteral| }.
+ 1. Return « _entry_ ».
AssertEntries : AssertionKey `:` StringLiteral `,` AssertEntries
- 1. Let _supportedAssertions_ be ! HostGetSupportedImportAssertions().
1. Let _key_ be StringValue of |AssertionKey|.
- 1. If _supportedAssertions_ contains _key_,
- 1. Let _entry_ be an ImportAssertion Record { [[Key]]: _key_, [[Value]]: StringValue of |StringLiteral| }.
- 1. Let _rest_ be AssertClauseToAssertions of |AssertEntries|.
- 1. Return a new List containing _entry_ followed by the elements of _rest_.
- 1. Otherwise, return AssertClauseToAssertions of |AssertEntries|.
+ 1. Let _entry_ be the ImportAssertion Record { [[Key]]: _key_, [[Value]]: StringValue of |StringLiteral| }.
+ 1. Let _rest_ be AssertClauseToAssertions of |AssertEntries|.
+ 1. Return the list-concatenation of « _entry_ » and _rest_.