Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement import.meta.resolve() #34188

Merged
merged 1 commit into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module

test(() => {
assert_equals(typeof import.meta, "object");
assert_not_equals(import.meta, null);
}, "import.meta is an object");

test(() => {
import.meta.newProperty = 1;
assert_true(Object.isExtensible(import.meta));
}, "import.meta is extensible");

test(() => {
for (const name of Reflect.ownKeys(import.meta)) {
const desc = Object.getOwnPropertyDescriptor(import.meta, name);
assert_equals(desc.writable, true);
assert_equals(desc.enumerable, true);
assert_equals(desc.configurable, true);
}
}, "import.meta's properties are writable, configurable, and enumerable");
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<!--
More extensive tests of import maps and import.meta.resolve() will be
located in the import maps test suite. This contains some basic tests plus
tests some tricky parts of the import.meta.resolve() algorithm around string
conversion which are only testable with import maps.
-->

<script type="importmap">
{
"imports": {
"bare": "https://example.com/",
"https://example.com/rewrite": "https://example.com/rewritten",

"1": "https://example.com/PASS-1",
"null": "https://example.com/PASS-null",
"undefined": "https://example.com/PASS-undefined",
"[object Object]": "https://example.com/PASS-object",

"./start": "./resources/export-1.mjs",
"./resources/export-1.mjs": "./resources/export-2.mjs"
}
}
</script>

<script type="module">
test(() => {
assert_equals(import.meta.resolve("bare"), "https://example.com/");
}, "import.meta.resolve() given an import mapped bare specifier");

test(() => {
assert_equals(import.meta.resolve("https://example.com/rewrite"), "https://example.com/rewritten");
}, "import.meta.resolve() given an import mapped URL-like specifier");

test(() => {
assert_equals(import.meta.resolve(), "https://example.com/PASS-undefined", "no-arg case");

assert_equals(import.meta.resolve(1), "https://example.com/PASS-1");
assert_equals(import.meta.resolve(null), "https://example.com/PASS-null");
assert_equals(import.meta.resolve(undefined), "https://example.com/PASS-undefined");

// Only toString() methods are consulted by ToString, not valueOf() ones.
// So this becomes "[object Object]".
assert_equals(import.meta.resolve({ valueOf() { return "./x"; } }), "https://example.com/PASS-object");
}, "Testing the ToString() step of import.meta.resolve() via import maps");

promise_test(async () => {
const one = (await import("./start")).default;
assert_equals(one, 1);

const two = (await import(import.meta.resolve("./start"))).default;
assert_equals(two, 2);
}, "import(import.meta.resolve(x)) can be different from import(x)");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<iframe src="resources/store-import-meta.html"></iframe>

<script type="module">
import * as otherImportMeta from "./resources/export-import-meta.mjs";
setup({ explicit_done: true });

window.onload = () => {
test(() => {
assert_not_equals(frames[0].importMetaURL, import.meta.url,
"Precondition check: we've set things up so that the other script has a different import.meta.url");

const expected = (new URL("resources/x", location.href)).href;
assert_equals(frames[0].importMetaResolve("./x"), expected);
}, "import.meta.resolve resolves URLs relative to the import.meta.url, not relative to the active script when it is called: another global's inline script");

test(() => {
const otherFrameImportMetaResolve = frames[0].importMetaResolve;

document.querySelector("iframe").remove();

const expected = (new URL("resources/x", location.href)).href;
assert_equals(otherFrameImportMetaResolve("./x"), expected);
}, "import.meta.resolve still works if its global has been destroyed (by detaching the iframe)");

test(() => {
assert_not_equals(otherImportMeta.url, import.meta.url,
"Precondition check: we've set things up so that the other script has a different import.meta.url");

const expected = (new URL("resources/x", location.href)).href;
assert_equals(otherImportMeta.resolve("./x"), expected);
}, "import.meta.resolve resolves URLs relative to the import.meta.url, not relative to the active script when it is called: another module script");

done();
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module

import { importMetaOnRootModule, importMetaOnDependentModule }
from "./import-meta-root.js";

test(() => {
assert_equals(typeof import.meta.resolve, "function");
assert_equals(import.meta.resolve.name, "resolve");
assert_equals(import.meta.resolve.length, 1);
assert_equals(Object.getPrototypeOf(import.meta.resolve), Function.prototype);
}, "import.meta.resolve is a function with the right properties");

test(() => {
assert_false(isConstructor(import.meta.resolve));

assert_throws_js(TypeError, () => new import.meta.resolve("./x"));
}, "import.meta.resolve is not a constructor");

test(() => {
// See also tests in ./import-meta-resolve-importmap.html.

assert_equals(import.meta.resolve({ toString() { return "./x"; } }), resolveURL("x"));
assert_throws_js(TypeError, () => import.meta.resolve(Symbol("./x")),
"symbol");
assert_throws_js(TypeError, () => import.meta.resolve(),
"no argument (which is treated like \"undefined\")");
}, "import.meta.resolve ToString()s its argument");

test(() => {
assert_equals(import.meta.resolve("./x"), resolveURL("x"),
"current module import.meta");
assert_equals(importMetaOnRootModule.resolve("./x"), resolveURL("x"),
"sibling module import.meta");
assert_equals(importMetaOnDependentModule.resolve("./x"), resolveURL("x"),
"dependency module import.meta");
}, "Relative URL-like specifier resolution");

test(() => {
assert_equals(import.meta.resolve("https://example.com/"), "https://example.com/",
"current module import.meta");
assert_equals(importMetaOnRootModule.resolve("https://example.com/"), "https://example.com/",
"sibling module import.meta");
assert_equals(importMetaOnDependentModule.resolve("https://example.com/"), "https://example.com/",
"dependency module import.meta");
}, "Absolute URL-like specifier resolution");

test(() => {
const invalidSpecifiers = [
"https://eggplant:b/c",
"pumpkins.js",
".tomato",
"..zuccini.mjs",
".\\yam.es"
];

for (const specifier of invalidSpecifiers) {
assert_throws_js(TypeError, () => import.meta.resolve(specifier), specifier);
}
}, "Invalid module specifiers");

test(() => {
const { resolve } = import.meta;
assert_equals(resolve("https://example.com/"), "https://example.com/", "current module import.meta");
}, "Works fine with no this value");

function resolveURL(urlRelativeToThisTest) {
return (new URL(urlRelativeToThisTest, location.href)).href;
}

function isConstructor(o) {
try {
new (new Proxy(o, { construct: () => ({}) }));
return true;
} catch {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,6 @@ test(() => {
base + "/import-meta-dependent.js");
}, "import.meta.url in a dependent external script");

test(() => {
assert_equals(typeof importMetaOnRootModule, "object");
assert_not_equals(importMetaOnRootModule, null);
}, "import.meta is an object");

test(() => {
importMetaOnRootModule.newProperty = 1;
assert_true(Object.isExtensible(importMetaOnRootModule));
}, "import.meta is extensible");

test(() => {
const names = new Set(Reflect.ownKeys(importMetaOnRootModule));
for (const name of names) {
var desc = Object.getOwnPropertyDescriptor(importMetaOnRootModule, name);
assert_equals(desc.writable, true);
assert_equals(desc.enumerable, true);
assert_equals(desc.configurable, true);
}
}, "import.meta's properties are writable, configurable, and enumerable");


import { importMetaOnRootModule as hashedImportMetaOnRootModule1,
importMetaOnDependentModule as hashedImportMetaOnDependentModule1 }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 1;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 2;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const url = import.meta.url;
export const resolve = import.meta.resolve;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!DOCTYPE html>
<script type="module">
window.importMetaURL = import.meta.url;
window.importMetaResolve = import.meta.resolve;
</script>