commit 4637467005110899e667511e7c1ab1d3af4e1594
parent 64d22f85bb64904ef701cd33d86c9a20f3d7254c
Author: Yoav Weiss <yoavweiss@chromium.org>
Date: Wed, 26 Nov 2025 09:00:27 +0000
Bug 2002190 [wpt PR 56251] - Fix sorting issue with import map scopes, a=testonly
Automatic update from web-platform-tests
Fix sorting issue with import map scopes
This CL fixes the iteration order of `ImportMap::scopes_map_`,
which should use `scopes_vector_` (sorted by keys as specified).
Change-Id: I6b177b01dfa9f4ad66ff7432f3380a0eb87497eb
Bug: 433490539, 406357273, 453147451
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7117300
Reviewed-by: Hiroshige Hayashizaki <hiroshige@chromium.org>
Commit-Queue: Yoav Weiss (@Shopify) <yoavweiss@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1549571}
--
wpt-commits: 7f8d6b3544da6ce717dc0eb4e63754e5fbc1a3f0
wpt-pr: 56251
Diffstat:
2 files changed, 161 insertions(+), 0 deletions(-)
diff --git a/testing/web-platform/tests/import-maps/data-driven/resolving.html b/testing/web-platform/tests/import-maps/data-driven/resolving.html
@@ -4,6 +4,7 @@
<meta name="variant" content="?overlapping-entries.json">
<meta name="variant" content="?packages-via-trailing-slashes.json">
<meta name="variant" content="?resolving-null.json">
+<meta name="variant" content="?empty-scopes.json">
<meta name="variant" content="?scopes-exact-vs-prefix.json">
<meta name="variant" content="?scopes.json">
<meta name="variant" content="?tricky-specifiers.json">
diff --git a/testing/web-platform/tests/import-maps/data-driven/resources/empty-scopes.json b/testing/web-platform/tests/import-maps/data-driven/resources/empty-scopes.json
@@ -0,0 +1,160 @@
+{
+ "name": "Scope sorting with multiple empty scopes",
+ "details": "Tests that empty scopes don't interfere with scope resolution priority. This reproduces a bug where having multiple empty scope entries before a more specific scope causes the wrong scope to be selected.",
+ "link": "https://github.com/astegmaier/playground-import-maps",
+ "tests": {
+ "Multiple empty scopes before specific scope": {
+ "importMap": {
+ "scopes": {
+ "./__bundles__/asdfasdf/": {},
+ "./__bundles__/qwerqwer/": {},
+ "./__bundles__/foo/": {
+ "bar": "./__bundles__/bar/version2/index.js"
+ },
+ "./__bundles__/": {
+ "bar": "./__bundles__/bar/version1/index.js"
+ }
+ }
+ },
+ "importMapBaseURL": "https://example.com/",
+ "tests": {
+ "Import from foo should use version2": {
+ "baseURL": "https://example.com/__bundles__/foo/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version2/index.js"
+ }
+ },
+ "Import from root bundles should use version1": {
+ "baseURL": "https://example.com/__bundles__/other/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version1/index.js"
+ }
+ },
+ "Import from asdfasdf should use version1 (empty scope)": {
+ "baseURL": "https://example.com/__bundles__/asdfasdf/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version1/index.js"
+ }
+ },
+ "Import from qwerqwer should use version1 (empty scope)": {
+ "baseURL": "https://example.com/__bundles__/qwerqwer/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version1/index.js"
+ }
+ }
+ }
+ },
+ "Empty scopes after specific scope": {
+ "importMap": {
+ "scopes": {
+ "./__bundles__/foo/": {
+ "bar": "./__bundles__/bar/version2/index.js"
+ },
+ "./__bundles__/": {
+ "bar": "./__bundles__/bar/version1/index.js"
+ },
+ "./__bundles__/asdfasdf/": {},
+ "./__bundles__/qwerqwer/": {}
+ }
+ },
+ "importMapBaseURL": "https://example.com/",
+ "tests": {
+ "Import from foo should use version2 (order independent)": {
+ "baseURL": "https://example.com/__bundles__/foo/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version2/index.js"
+ }
+ },
+ "Import from root bundles should use version1": {
+ "baseURL": "https://example.com/__bundles__/other/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version1/index.js"
+ }
+ }
+ }
+ },
+ "Single empty scope before specific scope": {
+ "importMap": {
+ "scopes": {
+ "./__bundles__/asdfasdf/": {},
+ "./__bundles__/foo/": {
+ "bar": "./__bundles__/bar/version2/index.js"
+ },
+ "./__bundles__/": {
+ "bar": "./__bundles__/bar/version1/index.js"
+ }
+ }
+ },
+ "importMapBaseURL": "https://example.com/",
+ "tests": {
+ "Import from foo should use version2 (single empty scope)": {
+ "baseURL": "https://example.com/__bundles__/foo/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/__bundles__/bar/version2/index.js"
+ }
+ }
+ }
+ },
+ "Deeply nested scopes with empty scopes": {
+ "importMap": {
+ "scopes": {
+ "./a/b/c/d/": {},
+ "./a/b/c/e/": {},
+ "./a/b/foo/": {
+ "pkg": "./resolved/version2.js"
+ },
+ "./a/b/": {
+ "pkg": "./resolved/version1.js"
+ }
+ }
+ },
+ "importMapBaseURL": "https://example.com/",
+ "tests": {
+ "Import from a/b/foo should use version2": {
+ "baseURL": "https://example.com/a/b/foo/index.js",
+ "expectedResults": {
+ "pkg": "https://example.com/resolved/version2.js"
+ }
+ },
+ "Import from a/b/ should use version1": {
+ "baseURL": "https://example.com/a/b/other.js",
+ "expectedResults": {
+ "pkg": "https://example.com/resolved/version1.js"
+ }
+ }
+ }
+ },
+ "Many empty scopes with different lengths": {
+ "importMap": {
+ "scopes": {
+ "./x/": {},
+ "./xy/": {},
+ "./xyz/": {},
+ "./xyzw/": {},
+ "./xyzwv/": {},
+ "./packages/foo/": {
+ "bar": "./bar/version2.js"
+ },
+ "./packages/": {
+ "bar": "./bar/version1.js"
+ }
+ }
+ },
+ "importMapBaseURL": "https://example.com/",
+ "tests": {
+ "Import from packages/foo should use version2": {
+ "baseURL": "https://example.com/packages/foo/index.js",
+ "expectedResults": {
+ "bar": "https://example.com/bar/version2.js"
+ }
+ },
+ "Import from packages/ should use version1": {
+ "baseURL": "https://example.com/packages/other.js",
+ "expectedResults": {
+ "bar": "https://example.com/bar/version1.js"
+ }
+ }
+ }
+ }
+ }
+}