From d554d6de43f6a366d0062c443ec1c7d7b4a310a3 Mon Sep 17 00:00:00 2001 From: Dan Clark Date: Thu, 29 Jul 2021 09:31:43 -0700 Subject: [PATCH] Re-add JSON module scripts Reland JSON modules (#4315), originally found in db03474b8b87aab3454ff7d5c1f4a5f044b4395c but removed in a530f6fe47e1f1e09f2a0b47634693f590432b83. Importing a JSON module now requires the module type to be specified at every import site with an import assertion, addressing the security concern that led to the revert. Additionally, some of the infrastructure now lives in the TC39 proposal at https://github.com/tc39/proposal-json-modules, and 3d45584d286e9455cc24ebae1f3aca3db120dc9d introduced the import assertions integration, so overall this patch is pretty small. --- source | 138 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 41 deletions(-) diff --git a/source b/source index 55b15337e83..e27253e91ed 100644 --- a/source +++ b/source @@ -2888,13 +2888,15 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • The HostGetSupportedImportAssertions abstract operation
  • -

    The following terms are defined in the JSON modules proposal and used in this - specification:

    +

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

    @@ -58396,6 +58398,9 @@ interface HTMLScriptElement : HTMLElement {

    The contents of the external script resource for CSS module scripts must conform to the requirements of the CSS specification.

    +

    The contents of the external script resource for JSON module + scripts must conform to the requirements of the JSON specification .

    +

    When used to include data blocks, the data must be embedded inline, the format of the data must be given using the type attribute, and the contents of the script element must conform to the requirements @@ -58714,7 +58719,29 @@ o............A....e where this script element appears in the document, it will not be evaluated until both document parsing has complete and its dependency (dom-utils.mjs) has been fetched and evaluated.

    + +
    +

    The following sample shows how a JSON module script can be imported from inside + a JavaScript module script:

    + +
    <script type="module">
    + import peopleInSpace from "http://api.open-notify.org/astros.json" assert { type: "json" };
    +
    + const list = document.querySelector("#people-in-space");
    + for (const { craft, name } of peopleInSpace.people) {
    +   const li = document.createElement("li");
    +   li.textContent = `${name} / ${craft}`;
    +   list.append(li);
    + }
    +</script>
    + +

    MIME type checking for module scripts is strict. In order for the fetch of the JSON + module script to succeed, the HTTP reponse must have a JSON MIME type, for + example Content-Type: text/json. On the other hand, if the assert { type: "json" } part of the statement is omitted, it is assumed that the + intent is to import a JavaScript module script, and the fetch will fail if the HTTP + response has a MIME type that is not a JavaScript MIME type.

    @@ -90154,8 +90181,8 @@ document.querySelector("button").addEventListener("click", bound);
  • a Source Text Module Record, for JavaScript module scripts;

  • -
  • a Synthetic Module Record, for CSS - module scripts; or

  • +
  • a Synthetic Module Record, for CSS module + scripts and JSON module scripts

  • null, representing a parsing failure.

  • @@ -90221,7 +90248,7 @@ document.querySelector("button").addEventListener("click", bound); data-x="concept-script">script. It has no additional items.

    -

    Module scripts can be classified into two types:

    +

    Module scripts can be classified into three types:

    +

    As CSS stylesheets and JSON documents do not import dependent modules, and do not + throw exceptions on evaluation, the fetch + options and base URL of CSS module scripts and JSON module + scripts and are always null.

    +

    The active script is determined by the following algorithm:

      @@ -90648,8 +90685,9 @@ document.querySelector("button").addEventListener("click", bound); type be entry.[[Value]]. Otherwise let module type be "javascript".

      -
    1. If module type is neither "javascript" nor "css", then asynchronously complete this algorithm with null, and return.

    2. +
    3. If module type is not "javascript", "css", or "json", then asynchronously complete this + algorithm with null, and return.

    4. Fetch a single module script given url, settings object, "script", options, settings object, @@ -91126,11 +91164,12 @@ document.querySelector("button").addEventListener("click", bound);

    -
  • Assert: module type is either "javascript" or "css". Otherwise we would not have reached this point because a failure would - have been raised when inspecting moduleRequest.[[Assertions]] in create a JavaScript module script or fetch - an import() module script graph.

  • +
  • Assert: module type is "javascript", "css", or "json". Otherwise we would not have reached + this point because a failure would have been raised when inspecting + moduleRequest.[[Assertions]] in create a JavaScript module script or + fetch an import() module script graph.

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

  • @@ -91215,6 +91254,11 @@ document.querySelector("button").addEventListener("click", bound); result of creating a CSS module script given source text and module map settings object.

    +
  • If MIME type essence is a JSON MIME type and module + type is "json", then set module script to the result of + creating a JSON module script given source text and module map + settings object.

  • +
  • Set moduleMap[(url, module type)] to module script, and asynchronously complete this algorithm with @@ -91417,8 +91461,9 @@ document.querySelector("button").addEventListener("click", bound); data-x="">javascript".

  • -

    If url is failure, or if module type is neither "javascript" nor "css", then:

    +

    If url is failure, or if module type is not "javascript", "css", or "json", + then:

    1. Let error be a new TypeError exception.

    2. @@ -91480,27 +91525,38 @@ document.querySelector("button").addEventListener("click", bound);
    3. Set script's record to the result - of creating a synthetic - module record with a default export of sheet with settings.

      -
    4. + of CreateDefaultExportSyntheticModule(sheet).

    5. Return script.

    -

    To create a synthetic module record with a default export of a JavaScript value - value with an environment settings object settings:

    +

    To create a JSON module script, given a + string source and an environment settings object settings:

      +
    1. Let script be a new module script that this algorithm will + subsequently initialize.

    2. + +
    3. Set script's settings object to settings.

    4. + +
    5. Set script's base URL and + fetch options to null.

    6. + +
    7. Set script's parse error and + error to rethrow to null.

    8. +
    9. -

      Return CreateSyntheticModule(« "default" », the following - steps, settings's Realm, - value) with the following steps given module as an argument:

      +

      Let result be ParseJSONModule(source).

      -
        -
      1. Perform ! SetSyntheticModuleExport(module, "default", module.[[HostDefined]]).
      2. -
      +

      If this throws an exception, set script's parse error to that exception, and return + script.

    10. + +
    11. Set script's record to + result.

    12. + +
    13. Return script.

    Calling scripts