diff --git a/source b/source index 7700c834858..b76416cec1d 100644 --- a/source +++ b/source @@ -2853,8 +2853,16 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute

User agents that support JavaScript must also implement the Top-Level Await proposal.

- +

User agents that support JavaScript must also implement the Import Assertions + proposal. The following terms are defined there, and used in this specification:

+ + +
WebAssembly
@@ -2867,7 +2875,6 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute -
DOM
@@ -88706,7 +88713,8 @@ document.querySelector("button").addEventListener("click", bound);
  • If result is null, asynchronously complete this algorithm with null, and return.

  • -
  • Let visited set be « url ».

  • +
  • Let visited set be « (url, "javascript") + ».

  • Fetch the descendants of and link result given settings object, @@ -88715,29 +88723,46 @@ document.querySelector("button").addEventListener("click", bound); result.

  • -

    To fetch an import() module script graph given a specifier, a base - URL, a settings object, and some options, run these steps. The - algorithm will asynchronously complete with either null (on failure) or a module +

    To fetch an import() module script graph given a moduleRequest, a + base URL, a settings object, and some options, run these steps. + The algorithm will asynchronously complete with either null (on failure) or a module script (on success).

    1. Let url be the result of resolving a - module specifier given base URL and specifier.

    2. + module specifier given base URL and moduleRequest.[[Specifier]].

    3. If url is failure, then asynchronously complete this algorithm with null, and return.

    4. +
    5. Assert: moduleRequest.[[Assertions]] does not contain any Record + entry such that entry.[[Key]] is not "type", because + we only asked for "type" assertions in + HostGetSupportedAssertions.

    6. + +
    7. +

      If moduleRequest.[[Assertions]] has a Record entry such + that entry.[[Key]] is "type" then asynchronously complete this + algorithm with null, and return.

      + +

      Currently no non-JS module types are supported, so we conservatively fail if any + type assertion is provided. When support is added for other module types, the "type" assertion will be used to check that the type of the fetched module + matches the type expected by the importer.

      +
    8. +
    9. Fetch a single module script given url, settings object, "script", options, settings object, - "client", and with the top-level module fetch flag set. If the - caller of this algorithm specified custom perform - the fetch steps, pass those along as well. Wait until the algorithm asynchronously - completes with result.

    10. + "client", moduleRequest, and with the + top-level module fetch flag set. If the caller of this algorithm specified custom + perform the fetch steps, pass those along as + well. Wait until the algorithm asynchronously completes with result.

    11. If result is null, asynchronously complete this algorithm with null, and return.

    12. -
    13. Let visited set be « url ».

    14. +
    15. Let visited set be « (url, "javascript") + ».

    16. Fetch the descendants of and link result given settings object, @@ -88764,7 +88789,8 @@ document.querySelector("button").addEventListener("click", bound);

      If result is not null, optionally perform the following steps:

        -
      1. Let visited set be « url ».

      2. +
      3. Let visited set be « (url, "javascript") + ».

      4. Fetch the descendants of and link result given settings object, @@ -88992,7 +89018,8 @@ document.querySelector("button").addEventListener("click", bound);

      5. If result is null, asynchronously complete this algorithm with null, and return.

      6. -
      7. Let visited set be « url ».

      8. +
      9. Let visited set be « (url, "javascript") + ».

      10. Fetch the descendants of and link result given fetch client settings @@ -89066,16 +89093,15 @@ document.querySelector("button").addEventListener("click", bound); record.[[RequestedModules]] is empty, asynchronously complete this algorithm with module script.

      11. -
      12. Let urls be a new empty list.

      13. +
      14. Let moduleRequests be a new empty list.

      15. -

        For each string requested of - record.[[RequestedModules]],

        +

        For each ModuleRequest Record + requested of record.[[RequestedModules]],

        1. Let url be the result of resolving - a module specifier given module script's base URL and requested.

        2. + data-x="concept-script-base-url">base URL and requested.[[Specifier]].

        3. Assert: url is never failure, because resolving a module specifier must have been

          If visited set does not contain - url, then:

          + (url, "javascript"), then:

            -
          1. Append url to urls.

          2. +
          3. Append requested to + moduleRequests.

          4. -
          5. Append url to visited - set.

          6. +
          7. Append (url, "javascript") to visited set.

        @@ -89103,11 +89130,12 @@ document.querySelector("button").addEventListener("click", bound); script.

      16. -

        For each url in urls, perform the - internal module script graph fetching procedure given url, fetch - client settings object, destination, options, module - script's settings object, visited set, and module - script's base URL. If the caller of this +

        For each moduleRequest in + moduleRequests, perform the internal module script graph fetching + procedure given moduleRequest, fetch client settings object, + destination, options, module script's settings + object, visited set, and module script's base URL. If the caller of this algorithm specified custom perform the fetch steps, pass those along while performing the internal module script graph fetching procedure.

        @@ -89126,21 +89154,30 @@ document.querySelector("button").addEventListener("click", bound);

      To perform the internal module script graph fetching procedure given a - url, a fetch client settings object, a destination, some - options, a module map settings object, a visited set, and a + moduleRequest, a fetch client settings object, a destination, + some options, a module map settings object, a visited set, and a referrer, perform these steps. The algorithm will asynchronously complete with either null (on failure) or a module script (on success).

        +
      1. Let url be the result of resolving + a module specifier given referrer and moduleRequest.[[Specifier]]. +

      2. + +
      3. Assert: url is never failure, because resolving a module specifier must have been previously successful with these same two + arguments.

      4. +
      5. Assert: visited set contains - url.

      6. + (url, "javascript").

      7. Fetch a single module script given url, fetch client settings object, destination, options, module map settings object, - referrer, and with the top-level module fetch flag unset. If the caller of - this algorithm specified custom perform the - fetch steps, pass those along while fetching a - single module script.

        + referrer, moduleRequest, and with the + top-level module fetch flag unset. If the caller of this algorithm specified custom + perform the fetch steps, pass those along + while fetching a single module script.

      8. Return from this algorithm, and run the following steps when fetching a single module script asynchronously completes with @@ -89159,24 +89196,25 @@ document.querySelector("button").addEventListener("click", bound);

        To fetch a single module script, given a url, a fetch client settings object, a destination, some options, a module map - settings object, a referrer, and a top-level module fetch flag, run - these steps. The algorithm will asynchronously complete with either null (on failure) or a - module script (on success).

        + settings object, a referrer, an optional moduleRequest, and a + top-level module fetch flag, run these steps. The algorithm will asynchronously + complete with either null (on failure) or a module script (on success).

        1. Let moduleMap be module map settings object's module map.

        2. -
        3. If moduleMap[url] is "fetching", wait - in parallel until that entry's value changes, then queue a task on - the networking task source to proceed with running the following steps.

        4. +
        5. If moduleMap[(url, "javascript")] is + "fetching", wait in parallel until that entry's value + changes, then queue a task on the networking task source to proceed + with running the following steps.

        6. -
        7. If moduleMap[url] exists, - asynchronously complete this algorithm with moduleMap[url], and - return.

        8. +
        9. If moduleMap[(url, "javascript")] exists, asynchronously complete this algorithm with + moduleMap[(url, "javascript")], and return.

        10. -
        11. Set moduleMap[url] to "fetching".

          +
        12. Set moduleMap[(url, "javascript")] to "fetching".

        13. Let request be a new request whose url is url, JavaScript MIME type,

        14. -

          then set moduleMap[url] to null, - asynchronously complete this algorithm with null, and return.

          +

          then set moduleMap[(url, "javascript")] to null, asynchronously complete this algorithm with null, and + return.

        15. Let source text be the result of UTF-8 @@ -89237,8 +89276,9 @@ document.querySelector("button").addEventListener("click", bound); data-x="concept-response-url">url, and options.

        16. -

          Set moduleMap[url] to module - script, and asynchronously complete this algorithm with module script.

          +

          Set moduleMap[(url, "javascript")] to module script, and asynchronously complete this + algorithm with module script.

          It is intentional that the module map is keyed by the request URL, whereas the moduleScript's parse error.

        17. -
        18. Let childSpecifiers be the value of moduleScript's

          Let moduleRequests be the value of moduleScript's record's [[RequestedModules]] internal slot.

        19. -
        20. Let childURLs be the list obtained by calling - resolve a module specifier once for each item of childSpecifiers, given - moduleScript's base URL and that item. - (None of these will ever fail, as otherwise moduleScript would have been marked as itself having a parse error.)

        21. - -
        22. Let childModules be the list obtained by getting each value in moduleMap whose key is given by an - item of childURLs.

        23. -
        24. -

          For each childModule of - childModules:

          +

          For each moduleRequest of + moduleRequests:

            +
          1. Let childURL be the result of resolving a module specifier given + moduleScript's base URL and + moduleRequest.[[Specifier]]. (This will never fail, as otherwise + moduleScript would have been marked + as itself having a parse error.)

          2. + +
          3. Let childModule be moduleMap[(childURL, "javascript")].

          4. +
          5. Assert: childModule is a module script (i.e., it is not "fetching" or null); by now all module scripts in the graph rooted at moduleScript will have successfully been @@ -89409,17 +89449,24 @@ document.querySelector("button").addEventListener("click", bound);

        25. +
        26. Assert: requested.[[Assertions]] does not contain any Record + entry such that entry.[[Key]] is not "type", because + we only asked for "type" assertions in + HostGetSupportedAssertions.

        27. +
        28. -

          For each string requested of - result.[[RequestedModules]]:

          +

          For each ModuleRequest record + requested of result.[[RequestedModules]]:

          1. Let url be the result of resolving a module specifier given script's base - URL and requested.

          2. + URL and requested.[[Specifier]].

          3. -

            If url is failure, then:

            +

            If url is failure, or if requested.[[Assertions]] has a + Record entry such that entry.[[Key]] is "type" then:

            1. Let error be a new TypeError exception.

            2. @@ -89432,10 +89479,17 @@ document.querySelector("button").addEventListener("click", bound);
            -

            This step is essentially validating all of the requested module specifiers. We - treat a module with unresolvable module specifiers the same as one that cannot be parsed; in - both cases, a syntactic issue makes it impossible to ever contemplate linking the module - later.

            +
            +

            This step is essentially validating all of the requested module specifiers and type + assertions. We treat a module with unresolvable module specifiers or an unsupported type + assertion the same as one that cannot be parsed; in both cases, a syntactic issue makes + it impossible to ever contemplate linking the module later.

            + +

            Currently no non-JS module types are supported, so we conservatively fail if any type + assertion is provided. When support is added for other module types, the "type" assertion will be used to check that the type of the fetched module + matches the type expected by the importer.

            +
          4. Set script's record to @@ -90202,17 +90256,23 @@ dictionary PromiseRejectionEventInit : EventInit {

    -

    A module map is a map of URL records to values that are either a module script, - null (used to represent failed fetches), or a placeholder value "A module map is a map keyed by tuples consisting of a URL record and a string. + The URL record is the request URL at which + the module was fetched, and the string indicates the type of the module (e.g. "javascript"). The module map's values are either a module + script, null (used to represent failed fetches), or a placeholder value "fetching". Module maps are used to ensure that imported JavaScript modules are only fetched, parsed, and evaluated once per - Document or worker.

    + Document or worker . Currently only JavaScript module scripts are supported, so the module type will always be + "javascript" until additional module types are introduced.

    -

    Since module maps are keyed by URL, the following code will - create three separate entries in the module map, since it results in three different - URLs:

    +

    Since module maps are keyed by (URL, module type), the + following code will create three separate entries in the module map, since it + results in three different (URL, module type) tuples (all with "javascript" type):

    import "https://example.com/module.mjs";
     import "https://example.com/module.mjs#map-buster";
    @@ -90237,6 +90297,36 @@ import "https://example.com/foo/../module2.mjs";

    Note that this behavior is the same as how shared workers are keyed by their parsed constructor url.

    + +

    Once additional module types are introduced, it will be possible to have multiple map entries + for a single URL since module type is also part of the module map key. For + example, once JSON modules are introduced the following code will create two separate entries in + the module map (the type is "javascript" for the first, and + "json" for the second): + +

    <script>
    +  import "https://example.com/module";
    +</script>
    +<script>
    +  import "https://example.com/module" assert { type: "json" };
    +</script>
    + +

    This can result in two separate fetches and two separate module evaluations being performed. + This is a willful violation of a constraint recommended (but not required) by the import + assertions specification stating that each call to HostResolveImportedModule with + the same referencingScriptOrModule, moduleRequest.[[Specifier]] pair must return the + same Module Record.

    + +

    In practice, due to the as-yet-unspecified memory cache (see issue #6110) the resource may only be fetched + once in WebKit and Blink-based browsers. Additionally, as long as all module types are mutually + exclusive, the module type check in fetch a single module script will fail for at + least one of the imports, so at most one module evaluation will occur.

    + +

    The purpose of including the type in the module map key is so that an import + with the wrong type assertion does not prevent a different import of the same specifier but with + the correct type from succeeding.

    @@ -90340,7 +90430,7 @@ import "https://example.com/foo/../module2.mjs";
    HostImportModuleDynamically(referencingScriptOrModule, - specifier, promiseCapability)
    + moduleRequest, promiseCapability)

    JavaScript contains an implementation-defined HostImportModuleDynamically abstract operation. @@ -90393,9 +90483,9 @@ import "https://example.com/foo/../module2.mjs"; case, referencingScriptOrModule is non-null.

    -
  • Fetch an import() module script graph given specifier, base - URL, settings object, and fetch options. Wait until the algorithm - asynchronously completes with result.

  • +
  • Fetch an import() module script graph given moduleRequest, + base URL, settings object, and fetch options. Wait until the + algorithm asynchronously completes with result.

  • Let promise be null. @@ -90406,13 +90496,13 @@ import "https://example.com/foo/../module2.mjs"; script">running a module script given result and true.

  • Perform FinishDynamicImport(referencingScriptOrModule, - specifier, promiseCapability, promise).

  • + moduleRequest, promiseCapability, promise).

  • Return undefined.

  • HostResolveImportedModule(referencingScriptOrModule, - specifier)
    + moduleRequest)

    JavaScript contains an implementation-defined HostResolveImportedModule abstract operation. User @@ -90457,15 +90547,16 @@ import "https://example.com/foo/../module2.mjs"; data-x="concept-settings-object-module-map">module map.

  • Let url be the result of resolving a - module specifier given base URL and specifier.

  • + module specifier given base URL and moduleRequest.[[Specifier]].

  • Assert: url is never failure, because resolving a module specifier must have been previously successful with these same two arguments (either while creating the corresponding module script, or in fetch an import() module script graph).

  • -
  • Let resolved module script be moduleMap[url]. (This entry - must exist for us to have gotten to this point.)

  • +
  • Let resolved module script be moduleMap[(url, "javascript")]. (This entry must exist for us + to have gotten to this point.)

  • Assert: resolved module script is a module script (i.e., is not null or "fetching").

  • @@ -90477,6 +90568,16 @@ import "https://example.com/foo/../module2.mjs"; data-x="concept-script-record">record.

    +
    HostGetSupportedAssertions()
    + +

    The Import Assertions proposal contains an implementation-defined + HostGetSupportedAssertions abstract operation. + User agents must use the following implementation:

    + +
      +
    1. Return « "type" ».

    2. +
    +

    Event loops

    @@ -122754,6 +122855,9 @@ INSERT INTERFACES HERE
    [JSERRORSTACKS]
    (Non-normative) Error Stacks. Ecma International.
    +
    [JSIMPORTASSERTIONS]
    +
    Import Assertions. Ecma International.
    +
    [JSINTL]
    ECMAScript Internationalization API Specification. Ecma International.