diff --git a/source b/source index 2ffe100e3bc..ca7bf8c76fd 100644 --- a/source +++ b/source @@ -2272,6 +2272,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • collect a sequence of code points and its associated position variable
  • skip ASCII whitespace
  • +
  • strictly split
  • +
  • string concatenate
  • The ordered map data structure and the associated definitions for key, value, @@ -2311,6 +2313,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute dequeue
  • The ordered set data structure and the associated definition for append and + iterate, and + remove, and union
  • The struct specification type and the associated definition for item
  • @@ -62776,6 +62780,10 @@ document.body.append(script1, script2);
    "module"
    +

    Let map be settings object's global object's import map.

    +

    If el does not have an integrity attribute, then set options's integrity metadata to the result of @@ -62867,15 +62875,6 @@ document.body.append(script1, script2);

    "importmap"
      -
    1. If el's relevant global object's import maps - allowed is false, then queue an element task on the DOM - manipulation task source given el to fire an event named error at el, and return.

    2. - -
    3. Set el's relevant global object's import maps - allowed to false.

    4. -
    5. Let result be the result of creating an import map parse result given source text and base URL.

    6. @@ -105691,6 +105690,43 @@ new PaymentRequest(…); // Allowed to use

      A global object has an about-to-be-notified rejected promises list, a list of Promise objects, initially empty.

      +

      A global object has an import map, + initially an empty import map.

      + +

      For now, only Window global + objects have their import map modified + from the initial empty one. The import map is + only accessed for the resolution of a root module script. Modules further down the + tree will be resolved using a copied import map that will be threaded through. That + is done to guarantee that once we started parsing a module graph, the entire graph would be + resolved using the same import map.

      + +

      A specifier resolution record is a struct. It has the following items:

      +
      +
      A base URL
      +
      A string-or-null that represents the base URL of the specifier, when one + exists.
      + +
      A specifier
      +
      A string representing the specifier.
      + +
      An asURL
      +
      A URL-or-null that represents the URL in case of a URL-like module + specifier.
      +
      + +

      A global object has a resolved module set, a set + of specifier resolution records, initially + empty.

      + +

      The resolved module set ensures that module specifier resolution + returns the same result when called multiple times with the same (referrer, specifier) pair. It + does that by ensuring that import map rules that impact the specifier in its + referrer's scope cannot be defined after its initial resolution. For now, only Window + global objects have their module set data structures modified + from the initial empty one.

      +

      There is always a 1-to-1-to-1 mapping between realms,

      Let integrity be the empty string.

      -
    7. If settingsObject's global object is a Window object, - then set integrity to the result of resolving a module integrity metadata - with url and settingsObject.

    8. +
    9. Set integrity to the result of resolving a module integrity + metadata with url and settingsObject.

    10. Set newOptions's integrity metadata to @@ -106643,13 +106677,9 @@ document.querySelector("button").addEventListener("click", bound); settings object settingsObject:

        -
      1. Assert: settingsObject's global object is a Window - object.

      2. -
      3. Let map be settingsObject's global object's import map.

      4. + data-x="concept-global-import-map">import map.

      5. If map's integrity[url] does not module script (on success).

          -
        1. Disallow further import maps given settingsObject.

        2. -
        3. Fetch a single module script given url, settingsObject, "script", options, settingsObject, " (on success).

            -
          1. Disallow further import maps given settingsObject.

          2. -
          3. Fetch a single module script given url, settingsObject, destination, options, settingsObject, "

          4. Run onComplete given result.

          5. +
          6. Assert: settingsObject's global object implements + Window.

          7. +
          8. If result is not null, optionally fetch the descendants of and link result given @@ -107010,8 +107040,6 @@ document.querySelector("button").addEventListener("click", bound); algorithm accepting null (on failure) or a module script (on success).

              -
            1. Disallow further import maps given settingsObject.

            2. -
            3. Let script be the result of creating a JavaScript module script using sourceText, settingsObject, baseURL, and options.

            4. @@ -107535,7 +107563,7 @@ document.querySelector("button").addEventListener("click", bound);

              To create a JavaScript module script, given a string source, an environment settings object settings, a URL baseURL, and a script fetch - options options:

              + options options:
              1. If scripting is disabled for @@ -108341,11 +108369,9 @@ dictionary PromiseRejectionEventInit : EventIniterror to rethrow for global and return.

              2. -
              3. Assert: global's import - map is an empty import map.

              4. - -
              5. Set global's import map to - result's import map.

              6. +
              7. Merge existing and new import + maps, given global and result's import map.

              @@ -108385,7 +108411,7 @@ dictionary PromiseRejectionEventInit : EventInit

              To resolve a module specifier given a script-or-null - referringScript and a string specifier:

              + referringScript, and a string specifier:
              1. Let settingsObject and baseURL be null.

              2. @@ -108420,7 +108446,7 @@ dictionary PromiseRejectionEventInit : EventInit

                If settingsObject's global object implements Window, then set importMap to settingsObject's global object's - import map.

                + import map.

              3. Let baseURLString be baseURL, serialized.

              4. @@ -108432,6 +108458,9 @@ dictionary PromiseRejectionEventInit : EventInitserialization of asURL, if asURL is non-null; otherwise, specifier.

                +
              5. Add module to resolved module set given settingsObject, + baseURLString, normalizedSpecifier, and asURL.

              6. +
              7. For each scopePrefixscopeImports of importMap's scopes:

                @@ -108620,16 +108649,12 @@ dictionary PromiseRejectionEventInit : EventInitchild text content containing a JSON representation of the import map.

                -

                Only one import map is processed per Document. After the first import map is - seen, others will be ignored, with their corresponding script elements generating - error events. Similarly, once any modules have been imported, - e.g., via import() expressions or script elements with their type attribute set to "module", further - import maps will be ignored.

                - -

                These restrictions, as well as the lack of support for external import maps, are - in place to keep the initial version of the feature simple. They might be lifted over time as - implementer bandwidth allows.

                +

                A Document can have multiple import maps processed, which can happen either + before or after any modules have been imported, e.g., via import() expressions or + script elements with their type attribute set + to "module". The merge existing and new import maps algorithm + ensures that new import maps cannot define the module resolution for modules that were already + defined by past import maps, or for ones that were already resolved.

                The simplest use of import maps is to globally remap a bare module specifier:

                @@ -108898,13 +108923,9 @@ dictionary PromiseRejectionEventInit : EventInit -

                Each Window has an import map, - initially an empty import map.

                - -

                Each Window has an import maps allowed boolean, initially true.

                - -

                To disallow further import maps given an environment settings object - settingsObject:

                +

                To add module to resolved module set given an environment settings + object settingsObject, a string baseURLString, a + string specifier, and a URL-or-null asURL:

                1. Let global be settingsObject's PromiseRejectionEventInit : EventInit

                  If global does not implement Window, then return.

                2. -
                3. Set global's import maps allowed to false.

                4. -
                - -

                Import maps are currently disallowed once any module loading has started, or once - a single import map is loaded. These restrictions might be lifted in future specification - revisions.

                +
              8. Let record be a new specifier resolution record, with base URL set to + baseURLString, specifier + set to specifier, and asURL + set to asURL.

              9. +
              10. Append record to global's + resolved module set.

              11. +

              To parse an import map string, given a string input and a @@ -109025,6 +109048,348 @@ dictionary PromiseRejectionEventInit : EventInitscopes.

              +
              + +

              To merge module specifier maps, given a module specifier map + newMap and a module specifier map oldMap:

              + +
                +
              1. Let mergedMap be a deep copy of oldMap.

              2. + +
              3. +

                For each specifier → + url of newMap:

                + +
                  +
                1. +

                  If specifier exists in + oldMap, then:

                  + +
                    +
                  1. The user agent may report the ignored rule as a warning to the developer + console. They may choose to avoid reporting if the rule is identical to an existing + one.

                  2. + +
                  3. Continue.

                  4. +
                  +
                2. + +
                3. Set mergedMap[specifier] to url.

                4. +
                +
              4. + +
              5. Return mergedMap.

              6. +
              + +

              To merge existing and new import maps, + given a global object global and + an import map newImportMap:

              + +
                +
              1. +

                Let newImportMapScopes be a deep copy of newImportMap's scopes.

                + +

                We're mutating these copies and removing items from them when they are used to + ignore scope-specific rules. This is true for newImportMapScopes, as well as to + newImportMapImports below.

                +
              2. + +
              3. Let newImportMapImports be a deep copy of newImportMap's imports.

              4. + +
              5. +

                For each scopePrefix → + scopeImports of newImportMapScopes:

                + +
                  +
                1. +

                  For each record of global's + resolved module set:

                  + +
                    +
                  1. +

                    If scopePrefix is record's base URL, or if scopePrefix + ends with U+002F (/) and scopePrefix is a code unit prefix of + record's base URL, + then:

                    + +
                      +
                    1. +

                      For each specifierKey → + resolutionResult of scopeImports:

                      + +
                        +
                      1. +

                        If specifierKey is record's specifier, or if the following + conditions are all true:

                        + +
                          +
                        1. specifierKey ends with U+002F (/).

                        2. + +
                        3. specifierKey is a code unit prefix of + record's specifier.

                        4. + +
                        5. Either record's asURL is null or is + special

                        6. +
                        + +

                        then:

                        + +
                          +
                        1. The user agent may report the ignored rule as a warning to the developer + console. They may choose to avoid reporting if the rule is identical to an existing + one.

                        2. + +
                        3. Remove scopeImports[specifier].

                        4. +
                        +
                      2. +
                      +
                    2. +
                    +
                  2. +
                  + +

                  Implementers are encouraged to implement a more efficient matching + algorithm when working with the resolved module set. As guidance, the number of + resolved/mapped modules in a large application can be in the order of thousands.

                  +
                2. + +
                3. If scopePrefix exists in + oldImportMap's scopes, then + set oldImportMap's scopes[scopePrefix] to the result of + merging module specifier maps, given + scopeImports and oldImportMap's scopes[scopePrefix].

                4. + +
                5. Otherwise, set oldImportMap's scopes[scopePrefix] to + scopeImports.

                6. +
                +
              6. + +
              7. +

                For each url → + integrity of newImportMap's integrity:

                + +
                  +
                1. +

                  If url exists in oldImportMap's + integrity, then:

                  + +
                    +
                  1. The user agent may report the ignored rule as a warning to the developer + console. They may choose to avoid reporting if the rule is identical to an existing + one.

                  2. + +
                  3. Continue.

                  4. +
                  +
                2. + +
                3. Set oldImportMap's integrity[url] to + integrity.

                4. +
                +
              8. + +
              9. +

                For each record of global's + resolved module set:

                + +
                  +
                1. +

                  For each specifierurl of + newImportMapImports:

                  + +
                    +
                  1. +

                    If specifier starts with record's specifier, then:

                    + +
                      +
                    1. The user agent may report the ignored rule as a warning to the developer + console. They may choose to avoid reporting if the rule is identical to an existing + one.

                    2. + +
                    3. Remove newImportMapImports[specifier].

                    4. +
                    +
                  2. +
                  +
                2. +
                +
              10. + +
              11. Set oldImportMap's imports to + the result of merge module specifier maps, + given newImportMapImports and oldImportMap's imports.

              12. +
              + +

              The above algorithm merges a new import map into the given environment + settings object's global object's import map. Let's examine a + few examples:

              + +
              +

              There are two cases when rules of the new import map don't get merged into the existing + one.

              + +
                +
              1. The new import map rule has the exact same scope and specifier as a rule in the existing + import map. We'll call that "conflicting rule".

              2. + +
              3. The new import map rule may impact the resolution of an already resolved module. We'll + call that "impacted already resolved module".

              4. +
              + +

              When the new import map has no conflicting rules, and there are no impacted resolved modules, + the resulting map would be a combination of the new and existing maps. Rules that would have + individually impacted similar modules (e.g. "/app/" and "/app/helper") but are not an exact + match are not conflicting, and all make it to the merged map.

              + +

              So, the following existing and new import maps:

              +
              {
              +   "imports": {
              +    "/app/": "./original-app/",
              +  }
              +}
              +{
              +  "imports": {
              +    "/app/helper": "./helper/index.mjs"
              +  },
              +  "scopes": {
              +    "/js": {
              +      "/app/": "./js-app/"
              +    }
              +  }
              +}
              +

              Would be equivalent to the following single import map:

              +
              {
              +  "imports": {
              +    "/app/": "./original-app/",
              +    "/app/helper": "./helper/index.mjs"
              +  },
              +  "scopes": {
              +    "/js": {
              +      "/app/": "./js-app/"
              +    }
              +  }
              +}
              +
              + +
              +

              When the new import map impacts an already resolved module, that rule gets dropped from the + import map.

              + +

              So, if the resolved module set already contains the "/app/helper", the following new import map:

              +
              {
              +   "imports": {
              +    "/app/helper": "./helper/index.mjs",
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +  }
              +}
              +

              Would be equivalent to the following one:

              +
              {
              +  "imports": {
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +  }
              +}
              +
              + +
              +

              The same is true for rules that impact already resolved modules defined in specific scopes. + If we already resolved "/app/helper" from "/app/main.mjs" the following new import map:

              +
              {
              +  "scopes": {
              +    "/app/": {
              +      "/app/helper": "./helper/index.mjs"
              +    }
              +  },
              +   "imports": {
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +  }
              +}
              +

              Would similarly be equivalent to:

              +
              {
              +  "imports": {
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +  }
              +}
              +
              + +
              +

              We could also have cases where a single already-resolved module specifier has multiple rules + for its resolution, depending on the referring script. In such cases, only the relevant rules + would not be added to the map.

              +

              For example, if we already resolved "/app/helper" from "/app/vendor/main.mjs", the following new import map:

              +
              {
              +  "scopes": {
              +    "/app/": {
              +      "/app/helper": "./helper/index.mjs"
              +    },
              +    "/app/vendor/": {
              +      "/app/": "./vendor_helper/"
              +    },
              +    "/vendor/": {
              +      "/app/helper": "./helper/vendor_index.mjs"
              +    }
              +  },
              +   "imports": {
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +    "/app/": "./general_app_path/"
              +    "/app/helper": "./other_path/helper/index.mjs"
              +  }
              +}
              +

              Would be equivalent to:

              +
              {
              +  "scopes": {
              +    "/vendor/": {
              +      "/app/helper": "./helper/vendor_index.mjs"
              +    }
              +  },
              +  "imports": {
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +  }
              +}
              + +

              This is achieved by the fact that the merge algorithm tracks already resolved modules + and removes rules affecting them from new import maps before they are merged into the existing + one.

              +
              + +
              +

              When the new import map has conflicting rules to the existing import map, with no impacted + already resolved modules, the existing import map rules persist.

              + +

              For example, the following existing and new import maps:

              +
              {
              +   "imports": {
              +    "/app/helper": "./helper/index.mjs",
              +    "lodash": "/node_modules/lodash-es/lodash.js"
              +  }
              +}
              +{
              +  "imports": {
              +    "/app/helper": "./main/helper/index.mjs"
              +  }
              +}
              +

              Would be equivalent to the following single import map:

              +
              {
              +  "imports": {
              +    "/app/helper": "./helper/index.mjs",
              +    "lodash": "/node_modules/lodash-es/lodash.js",
              +  }
              +}
              +
              +

              To sort and normalize a module specifier map, given an ordered map originalMap and a URL baseURL:

              @@ -110003,8 +110368,6 @@ import "https://example.com/foo/../module2.mjs";
          9. -
          10. Disallow further import maps given settingsObject.

          11. -
          12. Let url be the result of resolving a module specifier given referencingScript and moduleRequest.[[Specifier]], catching any exceptions. If they throw an exception, let