Skip to content

Commit

Permalink
Fix up the merge algorithm and add integrity handling
Browse files Browse the repository at this point in the history
  • Loading branch information
yoavweiss committed Aug 2, 2024
1 parent 6505ba6 commit be89886
Showing 1 changed file with 45 additions and 26 deletions.
71 changes: 45 additions & 26 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -108763,23 +108763,25 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
<var>newMap</var> and a <span>module specifier map</span> <var>oldMap</var>:</p>

<ol>
<li><p>Let <var>mergedMap</var> be a deep copy of <var>oldMap</var>.</p></li>

<li><p><span data-x="map iterate">For each</span> <var>specifier</var> →
<var>url</var> of <var>newMap</var>:</p>

<ol>
<li><p>If <var>specifier</var> <span data-x="map exists">exists</span> in
<var>oldMap</var>, <span>continue</span>.</p></li>

<li><p>Set <var>oldMap</var>[<var>specifier</var>] to <var>url</var>.</p></li>
<li><p>Set <var>mergedMap</var>[<var>specifier</var>] to <var>url</var>.</p></li>
</ol>
</li>

<li><p>Return <var>oldMap</var>.</p></li>
<li><p>Return <var>mergedMap</var>.</p></li>
</ol>

<p>To <dfn data-x="merge existing and new import maps">merge existing and new import maps</dfn>,
given an <span>environment settings object</span> <var>settings</var>, and an <span>import
map</span> <var>newImportMap</var>:
map</span> <var>newImportMap</var>:</p>

<ol>
<li><p>Let <var>global</var> be <var>settings</var>'s <span
Expand All @@ -108799,19 +108801,9 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
<li><p>Let <var>oldImportMap</var> be <var>global</var>'s <span
data-x="concept-window-import-map">import map</span>.</p></li>

<li>
<div class="note">
<p>The loops below have O(<var>N</var><sup>2</sup>) complexity. Implementations
could optimize that by e.g. sorting the set based on referrer script can enable O(NlogN)
lookups for a prefix.</p>

<p>Breaking each referring script URL to its potential prefixes and adding all of them to a map
that would return the specifier for any prefix. This can work because scopes always end with
"<code data-x="">/</code>".</p>
</div>

<p><span data-x="map iterate">For each</span> <var>scopePrefix</var> →
<var>scopeImports</var> of <var>newImportMap</var>:</p>
<li><p><span data-x="map iterate">For each</span> <var>scopePrefix</var> →
<var>scopeImports</var> of <var>newImportMap</var>'s <span
data-x="concept-import-map-scopes">scopes</span>:</p>
<ol>
<li>
<p><span data-x="set iterate">For each</span> <var>pair</var> of
Expand All @@ -108837,24 +108829,51 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
data-x="concept-import-map-scopes">scopes</span>[<var>scopePrefix</var>] to
<var>scopeImports</var>.</p></li>
</ol>
<div class="note">
<p>The loops above have O(<var>N</var><sup>2</sup>) complexity. Implementations could optimize
that by e.g. sorting the set based on referrer script can enable O(NlogN) lookups for a
prefix.</p>

<p>Breaking each referring script URL to its potential prefixes and adding all of them to a map
that would return the specifier for any prefix. This can work because scopes always end with
"<code data-x="">/</code>".</p>
</div>
</li>

<li>
<p><span data-x="map iterate">For each</span> <var>url</var> →
<var>integrity</var> of <var>newImportMap</var>'s <span
data-x="concept-import-map-integrity">integrity</span>:</p>
<ol>
<li><p>If <var>url</var> <span data-x="map exists">exists</span> in <var>oldImportMap</var>'s
<span data-x="concept-import-map-integrity">integrity</span>, then
<span>continue</span>.</p></li>

<li><p>Set <var>oldImportMap</var>'s <span
data-x="concept-import-map-integrity">integrity</span>[<var>url</var>] to
<var>integrity</var>.</p></li>
</ol>
</li>

<li><p><span data-x="list iterate">For each</span> <var>pair</var> of
<var>resolvedSetCopy</var>, remove <var>newImportMap</var>[<var>specifier</var>].</p></li>
<var>resolvedSetCopy</var>, remove <var>newImportMap</var>'s <span
data-x="concept-import-map-imports">imports</span>[<var>specifier</var>].</p></li>

<li><p>Set <var>global</var>'s <span>import map</span> to the result of <span
data-x="merge module specifier maps">merge module specifier maps</span>, given
<var>newImportMap</var> and <var>oldImportMap</var>.</p></li>
<var>newImportMap</var>'s <span data-x="concept-import-map-imports">imports</span> and
<var>oldImportMap</var>'s <span data-x="concept-import-map-imports">imports</span>.</p></li>
</ol>

<p class="note">The above algorithm merges two import maps into a coherent one. Let's examine a
<p class="note">The above algorithm merges a new import map into the given <span>environment
settings object</span>'s <span>global object</span>'s <span>import map</span>. Let's examine a
few examples:</p>

<div class="example" id="example-import-map-merge-unrelated">
<p>When two import maps that have no conflicting rules are being merged, and no resolved modules
correspond to the rules defined, the resulting map would be a combination of the two maps.</p>

<p>So, the following two import maps:</p>
<p>So, the following existing and new import maps:</p>
<pre><code class="json" data-x="">{
"imports": {
"/app/helper": "./helper/index.mjs",
Expand All @@ -108881,7 +108900,7 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
resolved, that rule gets dropped from the import map.</p>

<p>So, if the <span>resolved module set</span> already contains the pair (null, "<code
data-x="">/app/helper</code>"), the following import map:</p>
data-x="">/app/helper</code>"), the following new import map:</p>
<pre><code class="json" data-x="">{
"imports": {
"/app/helper": "./helper/index.mjs",
Expand All @@ -108899,7 +108918,7 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
<div class="example" id="example-import-map-merge-conflict-scopes">
<p>The same it true for rules defined in specific scopes. If the <span>resolved module set</span>
contains the pair ("<code data-x="">/app/main.mjs</code>", "<code data-x="">/app/helper</code>"),
the following import map:</p>
the following new import map:</p>
<pre><code class="json" data-x="">{
"scopes": {
"/app/": {
Expand All @@ -108925,7 +108944,7 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
resolution, depending on the referring script. In such cases, only the most specific rule would
not be added to the map.</p>
<p>For example, if the <span>resolved module set</span> contains the pair ("<code
data-x="">/app/main.mjs</code>", "<code data-x="">/app/helper</code>"), the following import
data-x="">/app/main.mjs</code>", "<code data-x="">/app/helper</code>"), the following new import
map:</p>
<pre><code class="json" data-x="">{
"scopes": {
Expand All @@ -108952,10 +108971,10 @@ dictionary <dfn dictionary>PromiseRejectionEventInit</dfn> : <span>EventInit</sp
</div>

<div class="example" id="example-import-map-merge-two-map-conflict">
<p>When two import maps that have conflicting rules are being merged, and no resolved modules
correspond to the rules defined, the first defined rules persist.</p>
<p>When an existing and new import maps that have conflicting rules are being merged, and no
resolved modules correspond to the rules defined, the first defined rules persist.</p>

<p>For example, the following two import maps:</p>
<p>For example, the following existing and new import maps:</p>
<pre><code class="json" data-x="">{
"imports": {
"/app/helper": "./helper/index.mjs",
Expand Down

0 comments on commit be89886

Please sign in to comment.