diff --git a/index.html b/index.html index b946a92..db00d7f 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ -import assertions +Import Assertions +

Import Assertions

See the explainer for information.

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

+ +

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 13.3.10.2 and 16.2.2. Usage of the old syntax is discouraged, and it removal is being investigated.

@@ -2672,7 +2704,7 @@

13.3.10.1 Runtime Semantics: Evaluation

-
  1. Return ? EvaluateImportCall(AssignmentExpression).
+
  1. Return ? EvaluateImportCall(AssignmentExpression).
ImportCall : @@ -2686,7 +2718,7 @@

13.3.10.1 Runtime Semantics: Evaluation

-
  1. Return ? EvaluateImportCall(the first AssignmentExpression, the second AssignmentExpression).
+
  1. Return ? EvaluateImportCall(the first AssignmentExpression, the second AssignmentExpression).
ImportCall : @@ -2697,13 +2729,13 @@

13.3.10.1 Runtime Semantics: Evaluation

-
  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]].
+
  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 a Promise. 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 assertions be a new empty List.
  11. If options is not undefined, then
    1. If Type(options) is not Object,
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    2. Let assertionsObj be Completion(Get(options, "assert")).
    3. IfAbruptRejectPromise(assertionsObj, promiseCapability).
    4. If assertionsObj is not undefined,
      1. If Type(assertionsObj) is not Object,
        1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
        2. Return promiseCapability.[[Promise]].
      2. Let keys be Completion(EnumerableOwnPropertyNames(assertionsObj, key)).
      3. IfAbruptRejectPromise(keys, promiseCapability).
      4. Let supportedAssertions be ! HostGetSupportedImportAssertions().
      5. For each String key of keys,
        1. Let value be Completion(Get(assertionsObj, key)).
        2. IfAbruptRejectPromise(value, promiseCapability).
        3. If Type(value) is not String, then
          1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
          2. Return promiseCapability.[[Promise]].
        4. If supportedAssertions contains key, then
          1. Append the ImportAssertion Record { [[Key]]: key, [[Value]]: value } to assertions.
    5. 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.
  12. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
  13. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
  14. Return promiseCapability.[[Promise]].
+
  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 assertions be a new empty List.
  11. If options is not undefined, then
    1. If Type(options) is not Object,
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    2. Let assertionsObj be Completion(Get(options, "with")).
    3. IfAbruptRejectPromise(assertionsObj, promiseCapability).
    4. If assertionsObj is undefined, then
      1. Let assertionsObj be Completion(Get(options, "assert")).
      2. IfAbruptRejectPromise(assertionsObj, promiseCapability).
    5. If assertionsObj is not undefined,
      1. If Type(assertionsObj) is not Object,
        1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
        2. Return promiseCapability.[[Promise]].
      2. Let keys be Completion(EnumerableOwnPropertyNames(assertionsObj, key)).
      3. IfAbruptRejectPromise(keys, promiseCapability).
      4. For each String key of keys,
        1. Let value be Completion(Get(assertionsObj, key)).
        2. IfAbruptRejectPromise(value, promiseCapability).
        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 ImportAssertion Record { [[Key]]: key, [[Value]]: value } to assertions.
    6. If AllImportAssertionsSupported(assertions) is false, then
      1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
      2. Return promiseCapability.[[Promise]].
    7. 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.
  12. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
  13. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
  14. Return promiseCapability.[[Promise]].
@@ -2722,7 +2754,7 @@

16.2.1 Module Semantics

16.2.1.1 ModuleRequest and ImportAssertion Records

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

-
Table 1: ModuleRequest Record fields
+
Table 1: ModuleRequest Record fields
@@ -2752,7 +2784,7 @@

16.2.1.1 ModuleRequest and ImportAssertion [[Assertions]]

- a List of ImportAssertion Records + a List of ImportAssertion Records The import assertions @@ -2763,7 +2795,7 @@

16.2.1.1 ModuleRequest and ImportAssertion

An ImportAssertion Record consists of the following fields:

-
Table 2: ImportAssertion Record fields
+
Table 2: ImportAssertion Record fields
@@ -2803,12 +2835,12 @@

16.2.1.1 ModuleRequest and ImportAssertion

- 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.
+ Editor's Note
In general, this proposal replaces places where module specifiers are passed around with ModuleRequest Records. For example, several syntax-directed operations, such as ModuleRequests produce Lists of ModuleRequest Records rather than Lists of Strings which are interpreted as module specifiers. Some algorithms like ImportEntries and ImportEntriesForModule pass around ModuleRequest Records rather than Strings, in a way which doesn't require any particular textual change. Additionally, record fields in Cyclic Module Records and Source Text Module Records which contained Lists of Strings are replaced by Lists of ModuleRequest Records, as indicated above.

16.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:

+

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] @@ -2818,7 +2850,7 @@

16.2.1.3 Static Semantics: ModuleRequests

ModuleItemList : ModuleItem
-
  1. Return ModuleRequests of ModuleItem.
+
  1. Return ModuleRequests of ModuleItem.
ModuleItemList : ModuleItemList @@ -2826,7 +2858,7 @@

16.2.1.3 Static Semantics: ModuleRequests

-
  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.
+
  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 @@ -2841,18 +2873,18 @@

16.2.1.3 Static Semantics: ModuleRequests

-
  1. Return ModuleRequests of FromClause.
  2. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: « » }.
+
  1. Return ModuleRequests of FromClause.
  2. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: « » }.
ImportDeclaration : import ImportClause FromClause - AssertClause + AssertClause ; -
  1. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  2. Let assertions be AssertClauseToAssertions of AssertClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
+
  1. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  2. Let assertions be AssertClauseToAssertions of AssertClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
ModuleSpecifier : StringLiteral @@ -2867,18 +2899,18 @@

16.2.1.3 Static Semantics: ModuleRequests

-
  1. Return ModuleRequests of FromClause.
  2. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: « » }.
+
  1. Return ModuleRequests of FromClause.
  2. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: « » }.
ExportDeclaration : export ExportFromClause FromClause - AssertClause + AssertClause ; -
  1. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  2. Let assertions be AssertClauseToAssertions of AssertClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
+
  1. Let specifier be SV of the ModuleSpecifier contained in FromClause.
  2. Let assertions be AssertClauseToAssertions of AssertClause.
  3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
ExportDeclaration : export @@ -2916,9 +2948,9 @@

16.2.1.3 Static Semantics: ModuleRequests

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 3

-
Table 3: Additional Fields of 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 3

+
Table 3: Additional Fields of Cyclic Module Records
@@ -2964,7 +2996,7 @@

16.2.1.5 Cyclic Module Records

[[RequestedModules]]
- a List of StringsModuleRequest Records + a List of StringsModuleRequest 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 @@

16.2.1.5 Cyclic Module Records

[[LoadedModules]]
- a List of Records with fields [[Specifier]] (a String), [[Assertions]] (a List of ImportAssertion Records) and [[Module]] (a Module Record) + a List of Records with fields [[Specifier]] (a String), [[Assertions]] (a List of ImportAssertion Records) 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 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:

-
Table 4: ImportEntry Record Fields
+

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

+
Table 4: ImportEntry Record Fields
@@ -3077,32 +3109,23 @@

16.2.1.6 Source Text Module Records

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.

+

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
+ Note 1

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

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

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

+

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 host environment must perform FinishLoadingImportedModule(referrer, specifiermoduleRequest, payload, result), where result is either a normal completion containing the loaded Module Record or a throw completion, either synchronously or asynchronously. + The host environment must perform FinishLoadingImportedModule(referrer, specifiermoduleRequest, 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, 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:

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

    + +

    16.2.1.10 AllImportAssertionsSupported ( assertions )

    +

    The abstract operation AllImportAssertionsSupported takes argument assertions (a List of ImportAssertion Records) and returns a Boolean. It performs the following steps when called:

    +
    1. Let supported be HostGetSupportedImportAssertions().
    2. For each Record assertion of assertions, do
      1. If supported does not contain assertion.[[Key]], return false.
    3. 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.
    +
    @@ -3183,19 +3208,31 @@

    16.2.2 Imports

    ImportClause FromClause [no LineTerminator here] - AssertClause + AssertClause ;
    import ModuleSpecifier [no LineTerminator here] - AssertClause + AssertClause ; - AssertClause : + AssertClause : + with + { + } + + + with + { + AssertEntries + ,opt + } + + assert { } @@ -3203,23 +3240,23 @@

    16.2.2 Imports

    assert { - AssertEntries + AssertEntries ,opt } -
    +
    AssertEntries : - AssertionKey + AssertionKey : StringLiteral - AssertionKey + AssertionKey : StringLiteral , - AssertEntries + AssertEntries @@ -3229,33 +3266,46 @@

    16.2.2 Imports

    StringLiteral -
    +

    16.2.2.1 Static Semantics: Early Errors

    - - AssertClause : + + AssertClause : + with + { + AssertEntries + ,opt + } + + assert { - AssertEntries + AssertEntries ,opt }

    16.2.2.2 Static Semantics: AssertClauseToAssertions

    -

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

    +

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

    - - AssertClause : + + AssertClause : + with + { + } + + assert { } @@ -3264,39 +3314,46 @@

    16.2.2.2 Static Semantics: AssertClauseToAs
    1. Return a new empty List.
    - - AssertClause : + + AssertClause : + with + { + AssertEntries + ,opt + } + + assert { - AssertEntries + AssertEntries ,opt } -
    1. Let assertions be AssertClauseToAssertions of AssertEntries.
    2. 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.
    3. Return assertions.
    +
    1. Let assertions be AssertClauseToAssertions of AssertEntries.
    2. 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.
    3. Return assertions.
    AssertEntries : - AssertionKey + AssertionKey : StringLiteral -
    1. Let supportedAssertions be ! HostGetSupportedImportAssertions().
    2. Let key be StringValue of AssertionKey.
    3. If supportedAssertions contains key,
      1. Let entry be an ImportAssertion Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
      2. Return a new List containing the single element, entry.
    4. Otherwise, return a new empty List.
    +
    1. Let key be StringValue of AssertionKey.
    2. Let entry be the ImportAssertion Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
    3. Return « entry ».
    AssertEntries : - AssertionKey + AssertionKey : StringLiteral , - AssertEntries + AssertEntries -
    1. Let supportedAssertions be ! HostGetSupportedImportAssertions().
    2. Let key be StringValue of AssertionKey.
    3. If supportedAssertions contains key,
      1. Let entry be an ImportAssertion Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
      2. Let rest be AssertClauseToAssertions of AssertEntries.
      3. Return a new List containing entry followed by the elements of rest.
    4. Otherwise, return AssertClauseToAssertions of AssertEntries.
    +
    1. Let key be StringValue of AssertionKey.
    2. Let entry be the ImportAssertion Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
    3. Let rest be AssertClauseToAssertions of AssertEntries.
    4. Return the list-concatenation of « entry » and rest.
    @@ -3315,7 +3372,7 @@

    16.2.3 Exports

    ExportFromClause FromClause [no LineTerminator here] - AssertClause + AssertClause ;
    @@ -3365,8 +3422,8 @@

    A Sample host integration: The Web embedding

  • 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.
    • diff --git a/spec.emu b/spec.emu index 4a26250..76965e6 100644 --- a/spec.emu +++ b/spec.emu @@ -2,19 +2,51 @@ -import assertions +Import Assertions + + + +

      Import Assertions

      See the explainer for information.

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

      + +

      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 @@

      Static Semantics: Early Errors

      - AssertClause : `assert` `{` AssertEntries `,`? `}` + + AssertClause : + `with` `{` AssertEntries `,`? `}` + `assert` `{` AssertEntries `,`? `}` +
      • 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_.
@@ -3050,11 +3082,11 @@

16.2.1.6 Source Text Module Records

String - ModuleRequest Record + ModuleRequest Record - String value of the ModuleSpecifier of the ImportDeclaration. - ModuleRequest Record representing the ModuleSpecifier and import assertions of the ImportDeclaration. + String value of the ModuleSpecifier of the ImportDeclaration. + ModuleRequest Record representing the ModuleSpecifier and import assertions of the ImportDeclaration.