diff --git a/index.html b/index.html index 39b6993..c97b4c6 100644 --- a/index.html +++ b/index.html @@ -1457,6 +1457,10 @@ transition: background-color 0.25s ease; cursor: pointer; } +var.field { + font: inherit; + color: inherit; +} var.referenced0 { color: inherit; @@ -2619,7 +2623,7 @@

Stage 2 Draft / February 10, 2023

+

Stage 2 Draft / February 22, 2023

import assertions

See the explainer for information.

@@ -2774,7 +2778,7 @@

2.1.1 Runtime Semantics: Evaluation

2.1.1.1 EvaluateImportCall ( specifierExpression [ , optionsExpression ] )

-
  1. Let referencingScriptOrModule be ! GetActiveScriptOrModule().
  2. Let specifierRef be the result of evaluating specifierExpression.
  3. Let specifier be ? GetValue(specifierRef).
  4. If optionsExpression is present, then
    1. Let optionsRef be the result of evaluating optionsExpression.
    2. Let options be ? GetValue(optionsRef).
  5. Else,
    1. Let options be undefined.
  6. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  7. Let specifierString be ToString(specifier).
  8. IfAbruptRejectPromise(specifierString, promiseCapability).
  9. Let assertions be a new empty List.
  10. 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 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 EnumerableOwnPropertyNames(assertionsObj, key).
      3. IfAbruptRejectPromise(keys, promiseCapability).
      4. Let supportedAssertions be ! HostGetSupportedImportAssertions().
      5. For each String key of keys,
        1. Let value be 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 { [[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.
  11. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
  12. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
  13. Return promiseCapability.[[Promise]].
+
  1. Let referencingScriptOrModule be ! GetActiveScriptOrModule().
  2. Let specifierRef be the result of evaluating specifierExpression.
  3. Let specifier be ? GetValue(specifierRef).
  4. If optionsExpression is present, then
    1. Let optionsRef be the result of evaluating optionsExpression.
    2. Let options be ? GetValue(optionsRef).
  5. Else,
    1. Let options be undefined.
  6. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  7. Let specifierString be ToString(specifier).
  8. IfAbruptRejectPromise(specifierString, promiseCapability).
  9. Let assertions be a new empty List.
  10. 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 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 EnumerableOwnPropertyNames(assertionsObj, key).
      3. IfAbruptRejectPromise(keys, promiseCapability).
      4. Let supportedAssertions be ! HostGetSupportedImportAssertions().
      5. For each String key of keys,
        1. Let value be 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 { [[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.
  11. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
  12. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
  13. Return promiseCapability.[[Promise]].
@@ -2809,7 +2813,7 @@

2.1.1.1 EvaluateImportCall ( specifierExpre

2.2 HostLoadImportedModule ( referrer, specifiermoduleRequest, 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
+ 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>
@@ -2823,31 +2827,27 @@

2.2 HostLoadImportedModule ( referrer 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.[[Specifier]], 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.

    +

    If this operation is called multiple times with the same (referrer, specifier) pair(referrer, moduleRequest.[[Specifier]], 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. -
  • The operation must treat payload as an opaque value to be passed through to FinishLoadingImportedModule.
  • -

    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, specifiermoduleRequest.[[Specifier]]) pairs may map to the same Module Record instance. The actual mapping semantic is host-defined but typically a normalization process is applied to specifiermoduleRequest.[[Specifier]] as part of the mapping process. A typical normalization process would include actions such as expansion of relative and abbreviated path specifiers.

    +

    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, specifiermoduleRequest.[[Specifier]]) pairs may map to the same Module Record instance. The actual mapping semantic is host-defined but typically a normalization process is applied to specifiermoduleRequest.[[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
    +

    When the same specifier is imported multiple times with different attributes, hosts could choose between three possible behaviors:

    • 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.
    • +
    • Reject the module graph and don't load if attributes are incompatible. 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.

    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.

    @@ -2858,17 +2858,17 @@

    2.2 HostLoadImportedModule ( referrer

    2.3 FinishLoadingImportedModule ( referrer, specifiermoduleRequest, 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.

    -
    1. If result is a normal completion, then
      1. If referrer.[[LoadedModules]] contains a Record record such that record.[[Specifier]] is moduleRequest.[[Specifier]] and AssertionsEqual(record.[[Assertions]], moduleRequest.[[Assertions]]) is true, then
        1. Assert: record.[[Module]] is result.[[Value]].
      2. Else, add Record { [[Specifier]]: moduleRequest.[[Specifier]], [[Assertions]]: moduleRequest.[[Assertions]], [[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.
    +
    1. If result is a normal completion, then
      1. If referrer.[[LoadedModules]] contains a Record record such that record.[[Specifier]] is moduleRequest.[[Specifier]] and AssertionsEqual(record.[[Assertions]], moduleRequest.[[Assertions]]) is true, then
        1. Assert: record.[[Module]] is result.[[Value]].
      2. Else, add Record { [[Specifier]]: moduleRequest.[[Specifier]], [[Assertions]]: moduleRequest.[[Assertions]], [[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 include the [[Assertions]] field.

    +

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

    2.3.1 AssertionsEqual(left, right)

    -

    The abstract operation AssertionsEqual takes arguments left and right (two Lists of Records { [[Key]]: a String, [[Value]]: a String }), and returns a Boolean.

    +

    The abstract operation AssertionsEqual takes arguments left and right (two Lists of Records { [[Key]]: a String, [[Value]]: a String }), and returns a Boolean.

    -
    1. If the number of elements in left is not the same as the number of elements in right, return false.
    2. For each Record { [[Key]], [[Value]] } r of left, do
      1. Let found be false.
      2. For each Record { [[Key]], [[Value]] } s of right, do
        1. If r.[[Key]] is s.[[Key]] and r.[[Value]] is s.[[Value]], then
          1. Set found to true.
      3. If found is false, return false.
    3. Return true.
    +
    1. If the number of elements in left is not the same as the number of elements in right, return false.
    2. For each Record { [[Key]], [[Value]] } r of left, do
      1. Let found be false.
      2. For each Record { [[Key]], [[Value]] } s of right, do
        1. If r.[[Key]] is s.[[Key]] and r.[[Value]] is s.[[Value]], then
          1. Set found to true.
      3. If found is false, return false.
    3. Return true.
    @@ -2907,7 +2907,7 @@

    2.5 Static Semantics: Early Errors

      -
    • 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 AssertClauseToAssertions of AssertClause has two entries a and b such that a.[[Key]] is b.[[Key]].
    @@ -2933,7 +2933,7 @@

    2.6 Static Semantics: AssertClauseToAssertions -
    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 : @@ -2943,7 +2943,7 @@

    2.6 Static Semantics: AssertClauseToAssertions -
    1. Let supportedAssertions be !HostGetSupportedImportAssertions().
    2. Let key be StringValue of AssertionKey.
    3. If supportedAssertions contains key,
      1. Let entry be a 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 supportedAssertions be !HostGetSupportedImportAssertions().
    2. Let key be StringValue of AssertionKey.
    3. If supportedAssertions contains key,
      1. Let entry be a Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
      2. Return a new List containing the single element, entry.
    4. Otherwise, return a new empty List.
    AssertEntries : @@ -2955,7 +2955,7 @@

    2.6 Static Semantics: AssertClauseToAssertions -
    1. Let supportedAssertions be !HostGetSupportedImportAssertions().
    2. Let key be StringValue of AssertionKey.
    3. If supportedAssertions contains key,
      1. Let entry be a 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 supportedAssertions be !HostGetSupportedImportAssertions().
    2. Let key be StringValue of AssertionKey.
    3. If supportedAssertions contains key,
      1. Let entry be a 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.
    @@ -2993,7 +2993,7 @@

    2.8 ModuleRequest Records

    - [[Specifier]] + [[Specifier]] String @@ -3004,10 +3004,10 @@

    2.8 ModuleRequest Records

    - [[Assertions]] + [[Assertions]] - a List of Records { [[Key]]: a String, [[Value]]: a String } + a List of Records { [[Key]]: a String, [[Value]]: a String } The import assertions @@ -3036,7 +3036,7 @@

    2.8 ModuleRequest Records

    - [[Status]] + [[Status]] unlinked | linking | linked | evaluating | evaluated @@ -3047,41 +3047,41 @@

    2.8 ModuleRequest Records

    - [[EvaluationError]] + [[EvaluationError]] An abrupt completion | undefined - A completion of type throw representing the exception that occurred during evaluation. undefined if no exception occurred or if [[Status]] is not evaluated. + A completion of type throw representing the exception that occurred during evaluation. undefined if no exception occurred or if [[Status]] is not evaluated. - [[DFSIndex]] + [[DFSIndex]] Integer | undefined Auxiliary field used during Link and Evaluate only. - If [[Status]] is linking or evaluating, this nonnegative number records the point at which the module was first visited during the ongoing depth-first traversal of the dependency graph. + If [[Status]] is linking or evaluating, this nonnegative number records the point at which the module was first visited during the ongoing depth-first traversal of the dependency graph. - [[DFSAncestorIndex]] + [[DFSAncestorIndex]] Integer | undefined - Auxiliary field used during Link and Evaluate only. If [[Status]] is linking or evaluating, this is either the module's own [[DFSIndex]] or that of an "earlier" module in the same strongly connected component. + Auxiliary field used during Link and Evaluate only. If [[Status]] is linking or evaluating, this is either the module's own [[DFSIndex]] or that of an "earlier" module in the same strongly connected component. - [[RequestedModules]] + [[RequestedModules]] List of StringModuleRequest Record @@ -3111,7 +3111,7 @@

    2.8 ModuleRequest Records

    - [[ModuleRequest]] + [[ModuleRequest]] String @@ -3124,18 +3124,18 @@

    2.8 ModuleRequest Records

    - [[ImportName]] + [[ImportName]] String - The name under which the desired binding is exported by the module identified by [[ModuleRequest]]. The value "*" indicates that the import request is for the target module's namespace object. + The name under which the desired binding is exported by the module identified by [[ModuleRequest]]. The value "*" indicates that the import request is for the target module's namespace object. - [[LocalName]] + [[LocalName]] String @@ -3160,7 +3160,7 @@

    2.9 Static Semantics: ModuleRequests

    -
    1. Return ModuleRequests of FromClause.
    2. Let specifier be StringValue of the StringLiteral contained in FromClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
    +
    1. Return ModuleRequests of FromClause.
    2. Let specifier be StringValue of the StringLiteral contained in FromClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
    ImportDeclaration : import @@ -3171,7 +3171,7 @@

    2.9 Static Semantics: ModuleRequests

    -
    1. Let specifier be StringValue of the StringLiteral contained in FromClause.
    2. Let assertions be AssertClauseToAssertions of AssertClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
    +
    1. Let specifier be StringValue of the StringLiteral contained in FromClause.
    2. Let assertions be AssertClauseToAssertions of AssertClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
    Module : [empty] @@ -3205,7 +3205,7 @@

    2.9 Static Semantics: ModuleRequests

    -
    1. Return ModuleRequests of FromClause.
    2. Let specifier be StringValue of the StringLiteral contained in FromClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
    +
    1. Return ModuleRequests of FromClause.
    2. Let specifier be StringValue of the StringLiteral contained in FromClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
    ExportDeclaration : export @@ -3216,7 +3216,7 @@

    2.9 Static Semantics: ModuleRequests

    -
    1. Let specifier be StringValue of the StringLiteral contained in FromClause.
    2. Let assertions be AssertClauseToAssertions of AssertClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
    +
    1. Let specifier be StringValue of the StringLiteral contained in FromClause.
    2. Let assertions be AssertClauseToAssertions of AssertClause.
    3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
    ExportDeclaration : export @@ -3262,8 +3262,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 183266b..c07ec6e 100644 --- a/spec.emu +++ b/spec.emu @@ -147,9 +147,6 @@
  • -
  • - _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. -
  • The operation must treat _payload_ as an opaque value to be passed through to FinishLoadingImportedModule.
  • @@ -157,12 +154,11 @@

    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__moduleRequest_.[[Specifier]]) pairs may map to the same Module Record instance. The actual mapping semantic is host-defined but typically a normalization process is applied to _specifier__moduleRequest_.[[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":

    + +

    When the same specifier is imported multiple times with different attributes, hosts could choose between three possible behaviors:

    • 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.
    • +
    • Reject the module graph and don't load if attributes are incompatible. 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.

    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.