mirror of
https://github.com/servo/servo.git
synced 2025-08-23 22:35:33 +01:00
Update web-platform-tests to revision 2b80e6d28f3c1ca734384ebded282bf07df80657
This commit is contained in:
parent
32eb858a6a
commit
aff72973cf
379 changed files with 13969 additions and 2161 deletions
|
@ -2,7 +2,7 @@
|
|||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// "bare/..." (i.e. without leading "./") are bare specifiers
|
||||
|
@ -15,16 +15,10 @@
|
|||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare/bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
"bare/cross-origin-bare": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bare",
|
||||
"bare/to-data": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"bare/std-blank": "std:blank",
|
||||
"bare/blank": "@std/blank",
|
||||
"bare/std-none": "std:none",
|
||||
"bare/none": "@std/none",
|
||||
|
||||
"bare/to-bare": "bare/bare"
|
||||
"bare/none": "@std/none"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -41,16 +35,6 @@ const tests = {
|
|||
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
|
||||
// below. https://crbug.com/928435
|
||||
|
||||
// Bare to HTTP(S).
|
||||
"bare/bare":
|
||||
[Result.URL, Result.URL, "log:bare", "log:bare"],
|
||||
"bare/cross-origin-bare":
|
||||
[Result.URL, Result.URL, "log:cross-origin-bare", "log:cross-origin-bare"],
|
||||
|
||||
// Bare to data:
|
||||
"bare/to-data":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// Bare to built-in.
|
||||
"bare/std-blank":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
||||
|
@ -60,10 +44,6 @@ const tests = {
|
|||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
"bare/none":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
|
||||
// Bare to bare mapping is disabled.
|
||||
"bare/to-bare":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
|
@ -1,16 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"./resources/log.js?pipe=sub&name=empty": [ "@std/" ],
|
||||
"./resources/log.js?pipe=sub&name=empty-fallback": [
|
||||
"../resources/log.js?pipe=sub&name=empty": [ "@std/" ],
|
||||
"../resources/log.js?pipe=sub&name=empty-fallback": [
|
||||
"@std/",
|
||||
"./resources/log.js?pipe=sub&name=empty-fallback"
|
||||
"../resources/log.js?pipe=sub&name=empty-fallback"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ const tests = {
|
|||
"@std/":
|
||||
[Result.FETCH_ERROR, Result.PARSE_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
|
||||
|
||||
"./resources/log.js?pipe=sub&name=empty":
|
||||
"../resources/log.js?pipe=sub&name=empty":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
"./resources/log.js?pipe=sub&name=empty-fallback":
|
||||
"../resources/log.js?pipe=sub&name=empty-fallback":
|
||||
[Result.URL, Result.URL, Result.URL, Result.URL],
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
const tests = {
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
const tests = {
|
|
@ -2,7 +2,7 @@
|
|||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// "bare/..." (i.e. without leading "./") are bare specifiers
|
||||
|
@ -15,18 +15,10 @@
|
|||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"data:text/javascript,log.push('data:foo')": "./resources/log.js?pipe=sub&name=foo",
|
||||
"data:text/javascript,log.push('data:cross-origin-foo')": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo",
|
||||
"data:text/javascript,log.push('data:to-data')": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"data:text/javascript,log.push('data:std-blank')": "std:blank",
|
||||
"data:text/javascript,log.push('data:blank')": "@std/blank",
|
||||
"data:text/javascript,log.push('data:std-none')": "std:none",
|
||||
"data:text/javascript,log.push('data:none')": "@std/none",
|
||||
|
||||
"data:text/javascript,log.push('data:to-bare')": "bare"
|
||||
"data:text/javascript,log.push('data:none')": "@std/none"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -43,16 +35,6 @@ const tests = {
|
|||
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
|
||||
// below. https://crbug.com/928435
|
||||
|
||||
// data: to HTTP(S).
|
||||
"data:text/javascript,log.push('data:foo')":
|
||||
[Result.URL, Result.URL, "log:foo", "log:foo"],
|
||||
"data:text/javascript,log.push('data:cross-origin-foo')":
|
||||
[Result.URL, Result.URL, "log:cross-origin-foo", "log:cross-origin-foo"],
|
||||
|
||||
// data: to data:
|
||||
"data:text/javascript,log.push('data:to-data')":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// data: to built-in.
|
||||
"data:text/javascript,log.push('data:std-blank')":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
||||
|
@ -62,10 +44,6 @@ const tests = {
|
|||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
"data:text/javascript,log.push('data:none')":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
|
||||
// data: to bare mapping is disabled.
|
||||
"data:text/javascript,log.push('data:to-bare')":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
|
@ -2,7 +2,7 @@
|
|||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// Fallbacks from external URLs (such as HTTPS URLs) are
|
||||
|
@ -18,51 +18,51 @@
|
|||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
"bare": "../resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"./resources/log.js?pipe=sub&name=http-to-builtin": [
|
||||
"./resources/log.js?pipe=sub&name=http-to-builtin",
|
||||
"../resources/log.js?pipe=sub&name=http-to-builtin": [
|
||||
"../resources/log.js?pipe=sub&name=http-to-builtin",
|
||||
"@std/blank"
|
||||
],
|
||||
|
||||
"./resources/log.js?pipe=sub&name=fallback-to-different-url-1": [
|
||||
"../resources/log.js?pipe=sub&name=fallback-to-different-url-1": [
|
||||
"@std/blank",
|
||||
"./resources/log.js?pipe=sub&name=something-different"
|
||||
"../resources/log.js?pipe=sub&name=something-different"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=fallback-to-different-url-2": [
|
||||
"../resources/log.js?pipe=sub&name=fallback-to-different-url-2": [
|
||||
"@std/none",
|
||||
"./resources/log.js?pipe=sub&name=something-different2"
|
||||
"../resources/log.js?pipe=sub&name=something-different2"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=fallback-to-different-origin-1": [
|
||||
"../resources/log.js?pipe=sub&name=fallback-to-different-origin-1": [
|
||||
"@std/blank",
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=fallback-to-different-origin-1"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=fallback-to-different-origin-2": [
|
||||
"../resources/log.js?pipe=sub&name=fallback-to-different-origin-2": [
|
||||
"@std/none",
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=fallback-to-different-origin-2"
|
||||
],
|
||||
|
||||
"./resources/log.js?pipe=sub&name=more-than-two-values-1": [
|
||||
"../resources/log.js?pipe=sub&name=more-than-two-values-1": [
|
||||
"@std/none",
|
||||
"@std/blank",
|
||||
"./resources/log.js?pipe=sub&name=more-than-two-values-1"
|
||||
"../resources/log.js?pipe=sub&name=more-than-two-values-1"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=more-than-two-values-2": [
|
||||
"../resources/log.js?pipe=sub&name=more-than-two-values-2": [
|
||||
"@std/none",
|
||||
"./resources/log.js?pipe=sub&name=more-than-two-values-2",
|
||||
"../resources/log.js?pipe=sub&name=more-than-two-values-2",
|
||||
"@std/blank"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=fallback-from-http": [
|
||||
"./resources/log.js?pipe=sub&name=non-built-in",
|
||||
"./resources/log.js?pipe=sub&name=fallback-from-http"
|
||||
"../resources/log.js?pipe=sub&name=fallback-from-http": [
|
||||
"../resources/log.js?pipe=sub&name=non-built-in",
|
||||
"../resources/log.js?pipe=sub&name=fallback-from-http"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=fallback-from-data-1": [
|
||||
"../resources/log.js?pipe=sub&name=fallback-from-data-1": [
|
||||
"data:text/plain,",
|
||||
"./resources/log.js?pipe=sub&name=fallback-from-http"
|
||||
"../resources/log.js?pipe=sub&name=fallback-from-http"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=fallback-from-data-2": [
|
||||
"../resources/log.js?pipe=sub&name=fallback-from-data-2": [
|
||||
"data:text/javascript,log.push('dataURL')",
|
||||
"./resources/log.js?pipe=sub&name=fallback-from-http"
|
||||
"../resources/log.js?pipe=sub&name=fallback-from-http"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// This tests is for fallbacks with the pattern of
|
||||
|
@ -16,13 +16,13 @@
|
|||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"./resources/log.js?pipe=sub&name=blank": [
|
||||
"../resources/log.js?pipe=sub&name=blank": [
|
||||
"@std/blank",
|
||||
"./resources/log.js?pipe=sub&name=blank"
|
||||
"../resources/log.js?pipe=sub&name=blank"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=none": [
|
||||
"../resources/log.js?pipe=sub&name=none": [
|
||||
"@std/none",
|
||||
"./resources/log.js?pipe=sub&name=none"
|
||||
"../resources/log.js?pipe=sub&name=none"
|
||||
],
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank": [
|
||||
"@std/blank",
|
||||
|
@ -33,13 +33,13 @@ const importMap = `
|
|||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none"
|
||||
],
|
||||
|
||||
"./resources/log.js?pipe=sub&name=std-blank": [
|
||||
"../resources/log.js?pipe=sub&name=std-blank": [
|
||||
"std:blank",
|
||||
"./resources/log.js?pipe=sub&name=std-blank"
|
||||
"../resources/log.js?pipe=sub&name=std-blank"
|
||||
],
|
||||
"./resources/log.js?pipe=sub&name=std-none": [
|
||||
"../resources/log.js?pipe=sub&name=std-none": [
|
||||
"std:none",
|
||||
"./resources/log.js?pipe=sub&name=std-none"
|
||||
"../resources/log.js?pipe=sub&name=std-none"
|
||||
],
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank": [
|
||||
"std:blank",
|
||||
|
@ -61,18 +61,18 @@ const tests = {
|
|||
// - dynamic import.
|
||||
// Result.URL indicates that the specifier was not re-mapped by import maps,
|
||||
// i.e. either considered as a relative path, or fallback occured.
|
||||
"./resources/log.js?pipe=sub&name=blank":
|
||||
"../resources/log.js?pipe=sub&name=blank":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
||||
"./resources/log.js?pipe=sub&name=none":
|
||||
"../resources/log.js?pipe=sub&name=none":
|
||||
[Result.URL, Result.URL, Result.URL, Result.URL],
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none":
|
||||
[Result.URL, Result.URL, Result.URL, Result.URL],
|
||||
|
||||
"./resources/log.js?pipe=sub&name=std-blank":
|
||||
"../resources/log.js?pipe=sub&name=std-blank":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
||||
"./resources/log.js?pipe=sub&name=std-none":
|
||||
"../resources/log.js?pipe=sub&name=std-none":
|
||||
[Result.URL, Result.URL, Result.URL, Result.URL],
|
||||
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-helper.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// "bare/..." (i.e. without leading "./") are bare specifiers
|
||||
|
@ -14,18 +14,10 @@
|
|||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"./resources/log.js?pipe=sub&name=foo": "./resources/log.js?pipe=sub&name=bar",
|
||||
"./resources/log.js?pipe=sub&name=cross-origin-foo": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bar",
|
||||
"./resources/log.js?pipe=sub&name=to-data": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"./resources/log.js?pipe=sub&name=std-blank": "std:blank",
|
||||
"./resources/log.js?pipe=sub&name=blank": "@std/blank",
|
||||
"./resources/log.js?pipe=sub&name=std-none": "std:none",
|
||||
"./resources/log.js?pipe=sub&name=none": "@std/none",
|
||||
|
||||
"./resources/log.js?pipe=sub&name=to-bare": "bare"
|
||||
"../resources/log.js?pipe=sub&name=std-blank": "std:blank",
|
||||
"../resources/log.js?pipe=sub&name=blank": "@std/blank",
|
||||
"../resources/log.js?pipe=sub&name=std-none": "std:none",
|
||||
"../resources/log.js?pipe=sub&name=none": "@std/none"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -42,16 +34,6 @@ const tests = {
|
|||
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
|
||||
// below. https://crbug.com/928435
|
||||
|
||||
// HTTP(S) to HTTP(S).
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=foo":
|
||||
[Result.URL, Result.URL, "log:bar", "log:bar"],
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo":
|
||||
[Result.URL, Result.URL, "log:cross-origin-bar", "log:cross-origin-bar"],
|
||||
|
||||
// HTTP(S) to data:
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-data":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// HTTP(S) to built-in.
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=std-blank":
|
||||
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
|
||||
|
@ -61,10 +43,6 @@ const tests = {
|
|||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=none":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
|
||||
// HTTP(S) to bare mapping is disabled.
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-bare":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
||||
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-addresses.js
|
||||
-->
|
||||
<script type="module" src="resources/parsing-addresses.js"></script>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
||||
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-schema.js
|
||||
-->
|
||||
<script type="module" src="resources/parsing-schema.js"></script>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
||||
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-scope-keys.js
|
||||
-->
|
||||
<script type="module" src="resources/parsing-scope-keys.js"></script>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
||||
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-specifier-keys.js
|
||||
-->
|
||||
<script type="module" src="resources/parsing-specifier-keys.js"></script>
|
|
@ -2,7 +2,7 @@
|
|||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/jest-test-helper.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
|
@ -2,7 +2,7 @@
|
|||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/jest-test-helper.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
||||
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-scopes.js
|
||||
-->
|
||||
<script type="module" src="resources/resolving-scopes.js"></script>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../resources/jest-test-helper.js"></script>
|
||||
<script type="module" src="resources/helpers/parsing.js"></script>
|
||||
|
||||
<!--
|
||||
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js
|
||||
-->
|
||||
<script type="module" src="resources/resolving.js"></script>
|
|
@ -0,0 +1,44 @@
|
|||
'use strict';
|
||||
const { parseFromString } = require('../../lib/parser.js');
|
||||
|
||||
// Local modifications from upstream:
|
||||
// Currently warnings and scopes are not checked in expectSpecifierMap().
|
||||
exports.expectSpecifierMap = (input, baseURL, output, warnings = []) => {
|
||||
expect(parseFromString(`{ "imports": ${input} }`, baseURL))
|
||||
.toEqual({ imports: output, scopes: {} });
|
||||
};
|
||||
|
||||
exports.expectScopes = (inputArray, baseURL, outputArray, warnings = []) => {
|
||||
const checkWarnings = testWarningHandler(warnings);
|
||||
|
||||
const inputScopesAsStrings = inputArray.map(scopePrefix => `${JSON.stringify(scopePrefix)}: {}`);
|
||||
const inputString = `{ "scopes": { ${inputScopesAsStrings.join(', ')} } }`;
|
||||
|
||||
const outputScopesObject = {};
|
||||
for (const outputScopePrefix of outputArray) {
|
||||
outputScopesObject[outputScopePrefix] = {};
|
||||
}
|
||||
|
||||
expect(parseFromString(inputString, baseURL)).toEqual({ imports: {}, scopes: outputScopesObject });
|
||||
|
||||
checkWarnings();
|
||||
};
|
||||
|
||||
exports.expectBad = (input, baseURL, warnings = []) => {
|
||||
const checkWarnings = testWarningHandler(warnings);
|
||||
expect(() => parseFromString(input, baseURL)).toThrow(TypeError);
|
||||
checkWarnings();
|
||||
};
|
||||
|
||||
exports.expectWarnings = (input, baseURL, output, warnings = []) => {
|
||||
const checkWarnings = testWarningHandler(warnings);
|
||||
expect(parseFromString(input, baseURL)).toEqual(output);
|
||||
|
||||
checkWarnings();
|
||||
};
|
||||
|
||||
function testWarningHandler(expectedWarnings) {
|
||||
// We don't check warnings on WPT tests, because there are no
|
||||
// ways to catch console warnings from JavaScript.
|
||||
return () => {};
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
'use strict';
|
||||
const { expectSpecifierMap } = require('./helpers/parsing.js');
|
||||
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
|
||||
|
||||
describe('Relative URL-like addresses', () => {
|
||||
it('should accept strings prefixed with ./, ../, or /', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"dotSlash": "./foo",
|
||||
"dotDotSlash": "../foo",
|
||||
"slash": "/foo"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
dotSlash: [expect.toMatchURL('https://base.example/path1/path2/foo')],
|
||||
dotDotSlash: [expect.toMatchURL('https://base.example/path1/foo')],
|
||||
slash: [expect.toMatchURL('https://base.example/foo')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should not accept strings prefixed with ./, ../, or / for data: base URLs', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"dotSlash": "./foo",
|
||||
"dotDotSlash": "../foo",
|
||||
"slash": "/foo"
|
||||
}`,
|
||||
'data:text/html,test',
|
||||
{
|
||||
dotSlash: [],
|
||||
dotDotSlash: [],
|
||||
slash: []
|
||||
},
|
||||
[
|
||||
`Invalid address "./foo" for the specifier key "dotSlash".`,
|
||||
`Invalid address "../foo" for the specifier key "dotDotSlash".`,
|
||||
`Invalid address "/foo" for the specifier key "slash".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept the literal strings ./, ../, or / with no suffix', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"dotSlash": "./",
|
||||
"dotDotSlash": "../",
|
||||
"slash": "/"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
dotSlash: [expect.toMatchURL('https://base.example/path1/path2/')],
|
||||
dotDotSlash: [expect.toMatchURL('https://base.example/path1/')],
|
||||
slash: [expect.toMatchURL('https://base.example/')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore percent-encoded variants of ./, ../, or /', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"dotSlash1": "%2E/",
|
||||
"dotDotSlash1": "%2E%2E/",
|
||||
"dotSlash2": ".%2F",
|
||||
"dotDotSlash2": "..%2F",
|
||||
"slash2": "%2F",
|
||||
"dotSlash3": "%2E%2F",
|
||||
"dotDotSlash3": "%2E%2E%2F"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
dotSlash1: [],
|
||||
dotDotSlash1: [],
|
||||
dotSlash2: [],
|
||||
dotDotSlash2: [],
|
||||
slash2: [],
|
||||
dotSlash3: [],
|
||||
dotDotSlash3: []
|
||||
},
|
||||
[
|
||||
`Invalid address "%2E/" for the specifier key "dotSlash1".`,
|
||||
`Invalid address "%2E%2E/" for the specifier key "dotDotSlash1".`,
|
||||
`Invalid address ".%2F" for the specifier key "dotSlash2".`,
|
||||
`Invalid address "..%2F" for the specifier key "dotDotSlash2".`,
|
||||
`Invalid address "%2F" for the specifier key "slash2".`,
|
||||
`Invalid address "%2E%2F" for the specifier key "dotSlash3".`,
|
||||
`Invalid address "%2E%2E%2F" for the specifier key "dotDotSlash3".`
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Built-in module addresses', () => {
|
||||
it('should accept URLs using the built-in module scheme', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": "${BUILT_IN_MODULE_SCHEME}:foo"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
foo: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo`)]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore percent-encoded variants of the built-in module scheme', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
foo: []
|
||||
},
|
||||
[`Invalid address "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" for the specifier key "foo".`]
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow built-in module URLs that contain "/" or "\\"', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"slashEnd": "${BUILT_IN_MODULE_SCHEME}:foo/",
|
||||
"slashMiddle": "${BUILT_IN_MODULE_SCHEME}:foo/bar",
|
||||
"backslash": "${BUILT_IN_MODULE_SCHEME}:foo\\\\baz"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
slashEnd: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/`)],
|
||||
slashMiddle: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/bar`)],
|
||||
backslash: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo\\baz`)]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Absolute URL addresses', () => {
|
||||
it('should only accept absolute URL addresses with fetch schemes', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"about": "about:good",
|
||||
"blob": "blob:good",
|
||||
"data": "data:good",
|
||||
"file": "file:///good",
|
||||
"filesystem": "filesystem:good",
|
||||
"http": "http://good/",
|
||||
"https": "https://good/",
|
||||
"ftp": "ftp://good/",
|
||||
"import": "import:bad",
|
||||
"mailto": "mailto:bad",
|
||||
"javascript": "javascript:bad",
|
||||
"wss": "wss:bad"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
about: [expect.toMatchURL('about:good')],
|
||||
blob: [expect.toMatchURL('blob:good')],
|
||||
data: [expect.toMatchURL('data:good')],
|
||||
file: [expect.toMatchURL('file:///good')],
|
||||
filesystem: [expect.toMatchURL('filesystem:good')],
|
||||
http: [expect.toMatchURL('http://good/')],
|
||||
https: [expect.toMatchURL('https://good/')],
|
||||
ftp: [expect.toMatchURL('ftp://good/')],
|
||||
import: [],
|
||||
mailto: [],
|
||||
javascript: [],
|
||||
wss: []
|
||||
},
|
||||
[
|
||||
`Invalid address "import:bad" for the specifier key "import".`,
|
||||
`Invalid address "mailto:bad" for the specifier key "mailto".`,
|
||||
`Invalid address "javascript:bad" for the specifier key "javascript".`,
|
||||
`Invalid address "wss:bad" for the specifier key "wss".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should only accept absolute URL addresses with fetch schemes inside arrays', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"about": ["about:good"],
|
||||
"blob": ["blob:good"],
|
||||
"data": ["data:good"],
|
||||
"file": ["file:///good"],
|
||||
"filesystem": ["filesystem:good"],
|
||||
"http": ["http://good/"],
|
||||
"https": ["https://good/"],
|
||||
"ftp": ["ftp://good/"],
|
||||
"import": ["import:bad"],
|
||||
"mailto": ["mailto:bad"],
|
||||
"javascript": ["javascript:bad"],
|
||||
"wss": ["wss:bad"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
about: [expect.toMatchURL('about:good')],
|
||||
blob: [expect.toMatchURL('blob:good')],
|
||||
data: [expect.toMatchURL('data:good')],
|
||||
file: [expect.toMatchURL('file:///good')],
|
||||
filesystem: [expect.toMatchURL('filesystem:good')],
|
||||
http: [expect.toMatchURL('http://good/')],
|
||||
https: [expect.toMatchURL('https://good/')],
|
||||
ftp: [expect.toMatchURL('ftp://good/')],
|
||||
import: [],
|
||||
mailto: [],
|
||||
javascript: [],
|
||||
wss: []
|
||||
},
|
||||
[
|
||||
`Invalid address "import:bad" for the specifier key "import".`,
|
||||
`Invalid address "mailto:bad" for the specifier key "mailto".`,
|
||||
`Invalid address "javascript:bad" for the specifier key "javascript".`,
|
||||
`Invalid address "wss:bad" for the specifier key "wss".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse absolute URLs, ignoring unparseable ones', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"unparseable1": "https://ex ample.org/",
|
||||
"unparseable2": "https://example.com:demo",
|
||||
"unparseable3": "http://[www.example.com]/",
|
||||
"invalidButParseable1": "https:example.org",
|
||||
"invalidButParseable2": "https://///example.com///",
|
||||
"prettyNormal": "https://example.net",
|
||||
"percentDecoding": "https://ex%41mple.com/",
|
||||
"noPercentDecoding": "https://example.com/%41"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
unparseable1: [],
|
||||
unparseable2: [],
|
||||
unparseable3: [],
|
||||
invalidButParseable1: [expect.toMatchURL('https://example.org/')],
|
||||
invalidButParseable2: [expect.toMatchURL('https://example.com///')],
|
||||
prettyNormal: [expect.toMatchURL('https://example.net/')],
|
||||
percentDecoding: [expect.toMatchURL('https://example.com/')],
|
||||
noPercentDecoding: [expect.toMatchURL('https://example.com/%41')]
|
||||
},
|
||||
[
|
||||
`Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`,
|
||||
`Invalid address "https://example.com:demo" for the specifier key "unparseable2".`,
|
||||
`Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse absolute URLs, ignoring unparseable ones inside arrays', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"unparseable1": ["https://ex ample.org/"],
|
||||
"unparseable2": ["https://example.com:demo"],
|
||||
"unparseable3": ["http://[www.example.com]/"],
|
||||
"invalidButParseable1": ["https:example.org"],
|
||||
"invalidButParseable2": ["https://///example.com///"],
|
||||
"prettyNormal": ["https://example.net"],
|
||||
"percentDecoding": ["https://ex%41mple.com/"],
|
||||
"noPercentDecoding": ["https://example.com/%41"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
unparseable1: [],
|
||||
unparseable2: [],
|
||||
unparseable3: [],
|
||||
invalidButParseable1: [expect.toMatchURL('https://example.org/')],
|
||||
invalidButParseable2: [expect.toMatchURL('https://example.com///')],
|
||||
prettyNormal: [expect.toMatchURL('https://example.net/')],
|
||||
percentDecoding: [expect.toMatchURL('https://example.com/')],
|
||||
noPercentDecoding: [expect.toMatchURL('https://example.com/%41')]
|
||||
},
|
||||
[
|
||||
`Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`,
|
||||
`Invalid address "https://example.com:demo" for the specifier key "unparseable2".`,
|
||||
`Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".`
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Failing addresses: mismatched trailing slashes', () => {
|
||||
it('should warn for the simple case', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"trailer/": "/notrailer",
|
||||
"${BUILT_IN_MODULE_SCHEME}:trailer/": "/bim-notrailer"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'trailer/': [],
|
||||
[`${BUILT_IN_MODULE_SCHEME}:trailer/`]: []
|
||||
},
|
||||
[
|
||||
`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`,
|
||||
`Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for a mismatch alone in an array', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"trailer/": ["/notrailer"],
|
||||
"${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-notrailer"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'trailer/': [],
|
||||
[`${BUILT_IN_MODULE_SCHEME}:trailer/`]: []
|
||||
},
|
||||
[
|
||||
`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`,
|
||||
`Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for a mismatch alongside non-mismatches in an array', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"trailer/": ["/atrailer/", "/notrailer"],
|
||||
"${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-atrailer/", "/bim-notrailer"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'trailer/': [expect.toMatchURL('https://base.example/atrailer/')],
|
||||
[`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [expect.toMatchURL('https://base.example/bim-atrailer/')]
|
||||
},
|
||||
[
|
||||
`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`,
|
||||
`Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".`
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Other invalid addresses', () => {
|
||||
it('should ignore unprefixed strings that are not absolute URLs', () => {
|
||||
for (const bad of ['bar', '\\bar', '~bar', '#bar', '?bar']) {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": ${JSON.stringify(bad)}
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
foo: []
|
||||
},
|
||||
[`Invalid address "${bad}" for the specifier key "foo".`]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,139 @@
|
|||
'use strict';
|
||||
const { parseFromString } = require('../lib/parser.js');
|
||||
const { expectBad, expectWarnings, expectSpecifierMap } = require('./helpers/parsing.js');
|
||||
|
||||
const nonObjectStrings = ['null', 'true', '1', '"foo"', '[]'];
|
||||
|
||||
test('Invalid JSON', () => {
|
||||
expect(() => parseFromString('{ imports: {} }', 'https://base.example/')).toThrow(SyntaxError);
|
||||
});
|
||||
|
||||
describe('Mismatching the top-level schema', () => {
|
||||
it('should throw for top-level non-objects', () => {
|
||||
for (const nonObject of nonObjectStrings) {
|
||||
expectBad(nonObject, 'https://base.example/');
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw if imports is a non-object', () => {
|
||||
for (const nonObject of nonObjectStrings) {
|
||||
expectBad(`{ "imports": ${nonObject} }`, 'https://base.example/');
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw if scopes is a non-object', () => {
|
||||
for (const nonObject of nonObjectStrings) {
|
||||
expectBad(`{ "scopes": ${nonObject} }`, 'https://base.example/');
|
||||
}
|
||||
});
|
||||
|
||||
it('should ignore unspecified top-level entries', () => {
|
||||
expectWarnings(
|
||||
`{
|
||||
"imports": {},
|
||||
"new-feature": {},
|
||||
"scops": {}
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{ imports: {}, scopes: {} },
|
||||
[
|
||||
`Invalid top-level key "new-feature". Only "imports" and "scopes" can be present.`,
|
||||
`Invalid top-level key "scops". Only "imports" and "scopes" can be present.`
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mismatching the specifier map schema', () => {
|
||||
const invalidAddressStrings = ['true', '1', '{}'];
|
||||
const invalidInsideArrayStrings = ['null', 'true', '1', '{}', '[]'];
|
||||
|
||||
it('should ignore entries where the address is not a string, array, or null', () => {
|
||||
for (const invalid of invalidAddressStrings) {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": ${invalid},
|
||||
"bar": ["https://example.com/"]
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
bar: [expect.toMatchURL('https://example.com/')]
|
||||
},
|
||||
[
|
||||
`Invalid address ${invalid} for the specifier key "foo". ` +
|
||||
`Addresses must be strings, arrays, or null.`
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should ignore entries where the specifier key is an empty string', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"": ["https://example.com/"]
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{},
|
||||
[`Invalid empty string specifier key.`]
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore members of an address array that are not strings', () => {
|
||||
for (const invalid of invalidInsideArrayStrings) {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": ["https://example.com/", ${invalid}],
|
||||
"bar": ["https://example.com/"]
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
foo: [expect.toMatchURL('https://example.com/')],
|
||||
bar: [expect.toMatchURL('https://example.com/')]
|
||||
},
|
||||
[
|
||||
`Invalid address ${invalid} inside the address array for the specifier key "foo". ` +
|
||||
`Address arrays must only contain strings.`
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw if a scope\'s value is not an object', () => {
|
||||
for (const invalid of nonObjectStrings) {
|
||||
expectBad(`{ "scopes": { "https://scope.example/": ${invalid} } }`, 'https://base.example/');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Normalization', () => {
|
||||
it('should normalize empty import maps to have imports and scopes keys', () => {
|
||||
expect(parseFromString(`{}`, 'https://base.example/'))
|
||||
.toEqual({ imports: {}, scopes: {} });
|
||||
});
|
||||
|
||||
it('should normalize an import map without imports to have imports', () => {
|
||||
expect(parseFromString(`{ "scopes": {} }`, 'https://base.example/'))
|
||||
.toEqual({ imports: {}, scopes: {} });
|
||||
});
|
||||
|
||||
it('should normalize an import map without scopes to have scopes', () => {
|
||||
expect(parseFromString(`{ "imports": {} }`, 'https://base.example/'))
|
||||
.toEqual({ imports: {}, scopes: {} });
|
||||
});
|
||||
|
||||
it('should normalize addresses to arrays', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": "https://example.com/1",
|
||||
"bar": ["https://example.com/2"],
|
||||
"baz": null
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
foo: [expect.toMatchURL('https://example.com/1')],
|
||||
bar: [expect.toMatchURL('https://example.com/2')],
|
||||
baz: []
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,144 @@
|
|||
'use strict';
|
||||
const { expectScopes } = require('./helpers/parsing.js');
|
||||
|
||||
describe('Relative URL scope keys', () => {
|
||||
it('should work with no prefix', () => {
|
||||
expectScopes(
|
||||
['foo'],
|
||||
'https://base.example/path1/path2/path3',
|
||||
['https://base.example/path1/path2/foo']
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with ./, ../, and / prefixes', () => {
|
||||
expectScopes(
|
||||
['./foo', '../foo', '/foo'],
|
||||
'https://base.example/path1/path2/path3',
|
||||
[
|
||||
'https://base.example/path1/path2/foo',
|
||||
'https://base.example/path1/foo',
|
||||
'https://base.example/foo'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with /s, ?s, and #s', () => {
|
||||
expectScopes(
|
||||
['foo/bar?baz#qux'],
|
||||
'https://base.example/path1/path2/path3',
|
||||
['https://base.example/path1/path2/foo/bar?baz#qux']
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with an empty string scope key', () => {
|
||||
expectScopes(
|
||||
[''],
|
||||
'https://base.example/path1/path2/path3',
|
||||
['https://base.example/path1/path2/path3']
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with / suffixes', () => {
|
||||
expectScopes(
|
||||
['foo/', './foo/', '../foo/', '/foo/', '/foo//'],
|
||||
'https://base.example/path1/path2/path3',
|
||||
[
|
||||
'https://base.example/path1/path2/foo/',
|
||||
'https://base.example/path1/path2/foo/',
|
||||
'https://base.example/path1/foo/',
|
||||
'https://base.example/foo/',
|
||||
'https://base.example/foo//'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should deduplicate based on URL parsing rules', () => {
|
||||
expectScopes(
|
||||
['foo/\\', 'foo//', 'foo\\\\'],
|
||||
'https://base.example/path1/path2/path3',
|
||||
['https://base.example/path1/path2/foo//']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Absolute URL scope keys', () => {
|
||||
it('should accept all absolute URL scope keys, with or without fetch schemes', () => {
|
||||
expectScopes(
|
||||
[
|
||||
'about:good',
|
||||
'blob:good',
|
||||
'data:good',
|
||||
'file:///good',
|
||||
'filesystem:http://example.com/good/',
|
||||
'http://good/',
|
||||
'https://good/',
|
||||
'ftp://good/',
|
||||
'import:bad',
|
||||
'mailto:bad',
|
||||
'javascript:bad',
|
||||
'wss:ba'
|
||||
],
|
||||
'https://base.example/path1/path2/path3',
|
||||
[
|
||||
'about:good',
|
||||
'blob:good',
|
||||
'data:good',
|
||||
'file:///good',
|
||||
'filesystem:http://example.com/good/',
|
||||
'http://good/',
|
||||
'https://good/',
|
||||
'ftp://good/',
|
||||
'import:bad',
|
||||
'mailto:bad',
|
||||
'javascript:bad',
|
||||
'wss://ba/'
|
||||
],
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse absolute URL scope keys, ignoring unparseable ones', () => {
|
||||
expectScopes(
|
||||
[
|
||||
'https://ex ample.org/',
|
||||
'https://example.com:demo',
|
||||
'http://[www.example.com]/',
|
||||
'https:example.org',
|
||||
'https://///example.com///',
|
||||
'https://example.net',
|
||||
'https://ex%41mple.com/foo/',
|
||||
'https://example.com/%41'
|
||||
],
|
||||
'https://base.example/path1/path2/path3',
|
||||
[
|
||||
'https://base.example/path1/path2/example.org', // tricky case! remember we have a base URL
|
||||
'https://example.com///',
|
||||
'https://example.net/',
|
||||
'https://example.com/foo/',
|
||||
'https://example.com/%41'
|
||||
],
|
||||
[
|
||||
'Invalid scope "https://ex ample.org/" (parsed against base URL "https://base.example/path1/path2/path3").',
|
||||
'Invalid scope "https://example.com:demo" (parsed against base URL "https://base.example/path1/path2/path3").',
|
||||
'Invalid scope "http://[www.example.com]/" (parsed against base URL "https://base.example/path1/path2/path3").'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore relative URL scope keys when the base URL is a data: URL', () => {
|
||||
expectScopes(
|
||||
[
|
||||
'./foo',
|
||||
'../foo',
|
||||
'/foo'
|
||||
],
|
||||
'data:text/html,test',
|
||||
[],
|
||||
[
|
||||
'Invalid scope "./foo" (parsed against base URL "data:text/html,test").',
|
||||
'Invalid scope "../foo" (parsed against base URL "data:text/html,test").',
|
||||
'Invalid scope "/foo" (parsed against base URL "data:text/html,test").'
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,159 @@
|
|||
'use strict';
|
||||
const { expectSpecifierMap } = require('./helpers/parsing.js');
|
||||
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
|
||||
|
||||
const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`;
|
||||
|
||||
describe('Relative URL-like specifier keys', () => {
|
||||
it('should absolutize strings prefixed with ./, ../, or / into the corresponding URLs', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"./foo": "/dotslash",
|
||||
"../foo": "/dotdotslash",
|
||||
"/foo": "/slash"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'https://base.example/path1/path2/foo': [expect.toMatchURL('https://base.example/dotslash')],
|
||||
'https://base.example/path1/foo': [expect.toMatchURL('https://base.example/dotdotslash')],
|
||||
'https://base.example/foo': [expect.toMatchURL('https://base.example/slash')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should not absolutize strings prefixed with ./, ../, or / with a data: URL base', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"./foo": "https://example.com/dotslash",
|
||||
"../foo": "https://example.com/dotdotslash",
|
||||
"/foo": "https://example.com/slash"
|
||||
}`,
|
||||
'data:text/html,test',
|
||||
{
|
||||
'./foo': [expect.toMatchURL('https://example.com/dotslash')],
|
||||
'../foo': [expect.toMatchURL('https://example.com/dotdotslash')],
|
||||
'/foo': [expect.toMatchURL('https://example.com/slash')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should absolutize the literal strings ./, ../, or / with no suffix', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"./": "/dotslash/",
|
||||
"../": "/dotdotslash/",
|
||||
"/": "/slash/"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'https://base.example/path1/path2/': [expect.toMatchURL('https://base.example/dotslash/')],
|
||||
'https://base.example/path1/': [expect.toMatchURL('https://base.example/dotdotslash/')],
|
||||
'https://base.example/': [expect.toMatchURL('https://base.example/slash/')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should treat percent-encoded variants of ./, ../, or / as bare specifiers', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"%2E/": "/dotSlash1/",
|
||||
"%2E%2E/": "/dotDotSlash1/",
|
||||
".%2F": "/dotSlash2",
|
||||
"..%2F": "/dotDotSlash2",
|
||||
"%2F": "/slash2",
|
||||
"%2E%2F": "/dotSlash3",
|
||||
"%2E%2E%2F": "/dotDotSlash3"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'%2E/': [expect.toMatchURL('https://base.example/dotSlash1/')],
|
||||
'%2E%2E/': [expect.toMatchURL('https://base.example/dotDotSlash1/')],
|
||||
'.%2F': [expect.toMatchURL('https://base.example/dotSlash2')],
|
||||
'..%2F': [expect.toMatchURL('https://base.example/dotDotSlash2')],
|
||||
'%2F': [expect.toMatchURL('https://base.example/slash2')],
|
||||
'%2E%2F': [expect.toMatchURL('https://base.example/dotSlash3')],
|
||||
'%2E%2E%2F': [expect.toMatchURL('https://base.example/dotDotSlash3')]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Absolute URL specifier keys', () => {
|
||||
it('should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"about:good": "/about",
|
||||
"blob:good": "/blob",
|
||||
"data:good": "/data",
|
||||
"file:///good": "/file",
|
||||
"filesystem:good": "/filesystem",
|
||||
"http://good/": "/http/",
|
||||
"https://good/": "/https/",
|
||||
"ftp://good/": "/ftp/",
|
||||
"import:bad": "/import",
|
||||
"mailto:bad": "/mailto",
|
||||
"javascript:bad": "/javascript",
|
||||
"wss:bad": "/wss"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'about:good': [expect.toMatchURL('https://base.example/about')],
|
||||
'blob:good': [expect.toMatchURL('https://base.example/blob')],
|
||||
'data:good': [expect.toMatchURL('https://base.example/data')],
|
||||
'file:///good': [expect.toMatchURL('https://base.example/file')],
|
||||
'filesystem:good': [expect.toMatchURL('https://base.example/filesystem')],
|
||||
'http://good/': [expect.toMatchURL('https://base.example/http/')],
|
||||
'https://good/': [expect.toMatchURL('https://base.example/https/')],
|
||||
'ftp://good/': [expect.toMatchURL('https://base.example/ftp/')],
|
||||
'import:bad': [expect.toMatchURL('https://base.example/import')],
|
||||
'mailto:bad': [expect.toMatchURL('https://base.example/mailto')],
|
||||
'javascript:bad': [expect.toMatchURL('https://base.example/javascript')],
|
||||
'wss:bad': [expect.toMatchURL('https://base.example/wss')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse absolute URLs, treating unparseable ones as bare specifiers', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"https://ex ample.org/": "/unparseable1/",
|
||||
"https://example.com:demo": "/unparseable2",
|
||||
"http://[www.example.com]/": "/unparseable3/",
|
||||
"https:example.org": "/invalidButParseable1/",
|
||||
"https://///example.com///": "/invalidButParseable2/",
|
||||
"https://example.net": "/prettyNormal/",
|
||||
"https://ex%41mple.com/": "/percentDecoding/",
|
||||
"https://example.com/%41": "/noPercentDecoding"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'https://ex ample.org/': [expect.toMatchURL('https://base.example/unparseable1/')],
|
||||
'https://example.com:demo': [expect.toMatchURL('https://base.example/unparseable2')],
|
||||
'http://[www.example.com]/': [expect.toMatchURL('https://base.example/unparseable3/')],
|
||||
'https://example.org/': [expect.toMatchURL('https://base.example/invalidButParseable1/')],
|
||||
'https://example.com///': [expect.toMatchURL('https://base.example/invalidButParseable2/')],
|
||||
'https://example.net/': [expect.toMatchURL('https://base.example/prettyNormal/')],
|
||||
'https://example.com/': [expect.toMatchURL('https://base.example/percentDecoding/')],
|
||||
'https://example.com/%41': [expect.toMatchURL('https://base.example/noPercentDecoding')]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse built-in module specifier keys, including with a "/"', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"${BLANK}": "/blank",
|
||||
"${BLANK}/": "/blank/",
|
||||
"${BLANK}/foo": "/blank/foo",
|
||||
"${BLANK}\\\\foo": "/blank/backslashfoo"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
[BLANK]: [expect.toMatchURL('https://base.example/blank')],
|
||||
[`${BLANK}/`]: [expect.toMatchURL('https://base.example/blank/')],
|
||||
[`${BLANK}/foo`]: [expect.toMatchURL('https://base.example/blank/foo')],
|
||||
[`${BLANK}\\foo`]: [expect.toMatchURL('https://base.example/blank/backslashfoo')]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,230 @@
|
|||
'use strict';
|
||||
const { URL } = require('url');
|
||||
const { parseFromString } = require('../lib/parser.js');
|
||||
const { resolve } = require('../lib/resolver.js');
|
||||
|
||||
const mapBaseURL = new URL('https://example.com/app/index.html');
|
||||
|
||||
function makeResolveUnderTest(mapString) {
|
||||
const map = parseFromString(mapString, mapBaseURL);
|
||||
return (specifier, baseURL) => resolve(specifier, map, baseURL);
|
||||
}
|
||||
|
||||
describe('Mapped using scope instead of "imports"', () => {
|
||||
const jsNonDirURL = new URL('https://example.com/js');
|
||||
const jsPrefixedURL = new URL('https://example.com/jsiscool');
|
||||
const inJSDirURL = new URL('https://example.com/js/app.mjs');
|
||||
const topLevelURL = new URL('https://example.com/app.mjs');
|
||||
|
||||
it('should fail when the mapping is to an empty array', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"scopes": {
|
||||
"/js/": {
|
||||
"moment": null,
|
||||
"lodash": []
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('lodash', inJSDirURL)).toThrow(TypeError);
|
||||
});
|
||||
|
||||
describe('Exact vs. prefix based matching', () => {
|
||||
it('should match correctly when both are in the map', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"scopes": {
|
||||
"/js": {
|
||||
"moment": "/only-triggered-by-exact/moment",
|
||||
"moment/": "/only-triggered-by-exact/moment/"
|
||||
},
|
||||
"/js/": {
|
||||
"moment": "/triggered-by-any-subpath/moment",
|
||||
"moment/": "/triggered-by-any-subpath/moment/"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(resolveUnderTest('moment', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment');
|
||||
expect(resolveUnderTest('moment/foo', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment/foo');
|
||||
|
||||
expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment');
|
||||
expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment/foo');
|
||||
|
||||
expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should match correctly when only an exact match is in the map', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"scopes": {
|
||||
"/js": {
|
||||
"moment": "/only-triggered-by-exact/moment",
|
||||
"moment/": "/only-triggered-by-exact/moment/"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(resolveUnderTest('moment', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment');
|
||||
expect(resolveUnderTest('moment/foo', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment/foo');
|
||||
|
||||
expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('moment/foo', inJSDirURL)).toThrow(TypeError);
|
||||
|
||||
expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should match correctly when only a prefix match is in the map', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"scopes": {
|
||||
"/js/": {
|
||||
"moment": "/triggered-by-any-subpath/moment",
|
||||
"moment/": "/triggered-by-any-subpath/moment/"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('moment', jsNonDirURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('moment/foo', jsNonDirURL)).toThrow(TypeError);
|
||||
|
||||
expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment');
|
||||
expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment/foo');
|
||||
|
||||
expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Package-like scenarios', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"moment": "/node_modules/moment/src/moment.js",
|
||||
"moment/": "/node_modules/moment/src/",
|
||||
"lodash-dot": "./node_modules/lodash-es/lodash.js",
|
||||
"lodash-dot/": "./node_modules/lodash-es/",
|
||||
"lodash-dotdot": "../node_modules/lodash-es/lodash.js",
|
||||
"lodash-dotdot/": "../node_modules/lodash-es/"
|
||||
},
|
||||
"scopes": {
|
||||
"/": {
|
||||
"moment": "/node_modules_3/moment/src/moment.js",
|
||||
"vue": "/node_modules_3/vue/dist/vue.runtime.esm.js"
|
||||
},
|
||||
"/js/": {
|
||||
"lodash-dot": "./node_modules_2/lodash-es/lodash.js",
|
||||
"lodash-dot/": "./node_modules_2/lodash-es/",
|
||||
"lodash-dotdot": "../node_modules_2/lodash-es/lodash.js",
|
||||
"lodash-dotdot/": "../node_modules_2/lodash-es/"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should resolve scoped', () => {
|
||||
expect(resolveUnderTest('lodash-dot', inJSDirURL)).toMatchURL('https://example.com/app/node_modules_2/lodash-es/lodash.js');
|
||||
expect(resolveUnderTest('lodash-dotdot', inJSDirURL)).toMatchURL('https://example.com/node_modules_2/lodash-es/lodash.js');
|
||||
expect(resolveUnderTest('lodash-dot/foo', inJSDirURL)).toMatchURL('https://example.com/app/node_modules_2/lodash-es/foo');
|
||||
expect(resolveUnderTest('lodash-dotdot/foo', inJSDirURL)).toMatchURL('https://example.com/node_modules_2/lodash-es/foo');
|
||||
});
|
||||
|
||||
it('should apply best scope match', () => {
|
||||
expect(resolveUnderTest('moment', topLevelURL)).toMatchURL('https://example.com/node_modules_3/moment/src/moment.js');
|
||||
expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/node_modules_3/moment/src/moment.js');
|
||||
expect(resolveUnderTest('vue', inJSDirURL)).toMatchURL('https://example.com/node_modules_3/vue/dist/vue.runtime.esm.js');
|
||||
});
|
||||
|
||||
it('should fallback to "imports"', () => {
|
||||
expect(resolveUnderTest('moment/foo', topLevelURL)).toMatchURL('https://example.com/node_modules/moment/src/foo');
|
||||
expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/node_modules/moment/src/foo');
|
||||
expect(resolveUnderTest('lodash-dot', topLevelURL)).toMatchURL('https://example.com/app/node_modules/lodash-es/lodash.js');
|
||||
expect(resolveUnderTest('lodash-dotdot', topLevelURL)).toMatchURL('https://example.com/node_modules/lodash-es/lodash.js');
|
||||
expect(resolveUnderTest('lodash-dot/foo', topLevelURL)).toMatchURL('https://example.com/app/node_modules/lodash-es/foo');
|
||||
expect(resolveUnderTest('lodash-dotdot/foo', topLevelURL)).toMatchURL('https://example.com/node_modules/lodash-es/foo');
|
||||
});
|
||||
|
||||
it('should still fail for package-like specifiers that are not declared', () => {
|
||||
expect(() => resolveUnderTest('underscore/', inJSDirURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('underscore/foo', inJSDirURL)).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('The scope inheritance example from the README', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": "/a-1.mjs",
|
||||
"b": "/b-1.mjs",
|
||||
"c": "/c-1.mjs"
|
||||
},
|
||||
"scopes": {
|
||||
"/scope2/": {
|
||||
"a": "/a-2.mjs"
|
||||
},
|
||||
"/scope2/scope3/": {
|
||||
"b": "/b-3.mjs"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
const scope1URL = new URL('https://example.com/scope1/foo.mjs');
|
||||
const scope2URL = new URL('https://example.com/scope2/foo.mjs');
|
||||
const scope3URL = new URL('https://example.com/scope2/scope3/foo.mjs');
|
||||
|
||||
it('should fall back to "imports" when none match', () => {
|
||||
expect(resolveUnderTest('a', scope1URL)).toMatchURL('https://example.com/a-1.mjs');
|
||||
expect(resolveUnderTest('b', scope1URL)).toMatchURL('https://example.com/b-1.mjs');
|
||||
expect(resolveUnderTest('c', scope1URL)).toMatchURL('https://example.com/c-1.mjs');
|
||||
});
|
||||
|
||||
it('should use a direct scope override', () => {
|
||||
expect(resolveUnderTest('a', scope2URL)).toMatchURL('https://example.com/a-2.mjs');
|
||||
expect(resolveUnderTest('b', scope2URL)).toMatchURL('https://example.com/b-1.mjs');
|
||||
expect(resolveUnderTest('c', scope2URL)).toMatchURL('https://example.com/c-1.mjs');
|
||||
});
|
||||
|
||||
it('should use an indirect scope override', () => {
|
||||
expect(resolveUnderTest('a', scope3URL)).toMatchURL('https://example.com/a-2.mjs');
|
||||
expect(resolveUnderTest('b', scope3URL)).toMatchURL('https://example.com/b-3.mjs');
|
||||
expect(resolveUnderTest('c', scope3URL)).toMatchURL('https://example.com/c-1.mjs');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Relative URL scope keys', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": "/a-1.mjs",
|
||||
"b": "/b-1.mjs",
|
||||
"c": "/c-1.mjs"
|
||||
},
|
||||
"scopes": {
|
||||
"": {
|
||||
"a": "/a-empty-string.mjs"
|
||||
},
|
||||
"./": {
|
||||
"b": "/b-dot-slash.mjs"
|
||||
},
|
||||
"../": {
|
||||
"c": "/c-dot-dot-slash.mjs"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
const inSameDirAsMap = new URL('./foo.mjs', mapBaseURL);
|
||||
const inDirAboveMap = new URL('../foo.mjs', mapBaseURL);
|
||||
|
||||
it('should resolve an empty string scope using the import map URL', () => {
|
||||
expect(resolveUnderTest('a', mapBaseURL)).toMatchURL('https://example.com/a-empty-string.mjs');
|
||||
expect(resolveUnderTest('a', inSameDirAsMap)).toMatchURL('https://example.com/a-1.mjs');
|
||||
});
|
||||
|
||||
it('should resolve a ./ scope using the import map URL\'s directory', () => {
|
||||
expect(resolveUnderTest('b', mapBaseURL)).toMatchURL('https://example.com/b-dot-slash.mjs');
|
||||
expect(resolveUnderTest('b', inSameDirAsMap)).toMatchURL('https://example.com/b-dot-slash.mjs');
|
||||
});
|
||||
|
||||
it('should resolve a ../ scope using the import map URL\'s directory', () => {
|
||||
expect(resolveUnderTest('c', mapBaseURL)).toMatchURL('https://example.com/c-dot-dot-slash.mjs');
|
||||
expect(resolveUnderTest('c', inSameDirAsMap)).toMatchURL('https://example.com/c-dot-dot-slash.mjs');
|
||||
expect(resolveUnderTest('c', inDirAboveMap)).toMatchURL('https://example.com/c-dot-dot-slash.mjs');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
'use strict';
|
||||
const { URL } = require('url');
|
||||
const { parseFromString } = require('../lib/parser.js');
|
||||
const { resolve } = require('../lib/resolver.js');
|
||||
|
||||
const mapBaseURL = new URL('https://example.com/app/index.html');
|
||||
const scriptURL = new URL('https://example.com/js/app.mjs');
|
||||
|
||||
function makeResolveUnderTest(mapString) {
|
||||
const map = parseFromString(mapString, mapBaseURL);
|
||||
return specifier => resolve(specifier, map, scriptURL);
|
||||
}
|
||||
|
||||
describe('Unmapped', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{}`);
|
||||
|
||||
it('should resolve ./ specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('./foo')).toMatchURL('https://example.com/js/foo');
|
||||
expect(resolveUnderTest('./foo/bar')).toMatchURL('https://example.com/js/foo/bar');
|
||||
expect(resolveUnderTest('./foo/../bar')).toMatchURL('https://example.com/js/bar');
|
||||
expect(resolveUnderTest('./foo/../../bar')).toMatchURL('https://example.com/bar');
|
||||
});
|
||||
|
||||
it('should resolve ../ specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('../foo')).toMatchURL('https://example.com/foo');
|
||||
expect(resolveUnderTest('../foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
expect(resolveUnderTest('../../../foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
});
|
||||
|
||||
it('should resolve / specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('/foo')).toMatchURL('https://example.com/foo');
|
||||
expect(resolveUnderTest('/foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
expect(resolveUnderTest('/../../foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
expect(resolveUnderTest('/../foo/../bar')).toMatchURL('https://example.com/bar');
|
||||
});
|
||||
|
||||
it('should parse absolute fetch-scheme URLs', () => {
|
||||
expect(resolveUnderTest('about:good')).toMatchURL('about:good');
|
||||
expect(resolveUnderTest('https://example.net')).toMatchURL('https://example.net/');
|
||||
expect(resolveUnderTest('https://ex%41mple.com/')).toMatchURL('https://example.com/');
|
||||
expect(resolveUnderTest('https:example.org')).toMatchURL('https://example.org/');
|
||||
expect(resolveUnderTest('https://///example.com///')).toMatchURL('https://example.com///');
|
||||
});
|
||||
|
||||
it('should fail for absolute non-fetch-scheme URLs', () => {
|
||||
expect(() => resolveUnderTest('mailto:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('import:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('javascript:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('wss:bad')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should fail for strings not parseable as absolute URLs and not starting with ./ ../ or /', () => {
|
||||
expect(() => resolveUnderTest('foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('\\foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest(':foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('@foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('%2E/foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('%2E%2E/foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('.%2Ffoo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('https://ex ample.org/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('https://example.com:demo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('http://[www.example.com]/')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mapped using the "imports" key only (no scopes)', () => {
|
||||
it('should fail when the mapping is to an empty array', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"moment": null,
|
||||
"lodash": []
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('moment')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('lodash')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
describe('Package-like scenarios', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"moment": "/node_modules/moment/src/moment.js",
|
||||
"moment/": "/node_modules/moment/src/",
|
||||
"lodash-dot": "./node_modules/lodash-es/lodash.js",
|
||||
"lodash-dot/": "./node_modules/lodash-es/",
|
||||
"lodash-dotdot": "../node_modules/lodash-es/lodash.js",
|
||||
"lodash-dotdot/": "../node_modules/lodash-es/",
|
||||
"nowhere/": []
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should work for package main modules', () => {
|
||||
expect(resolveUnderTest('moment')).toMatchURL('https://example.com/node_modules/moment/src/moment.js');
|
||||
expect(resolveUnderTest('lodash-dot')).toMatchURL('https://example.com/app/node_modules/lodash-es/lodash.js');
|
||||
expect(resolveUnderTest('lodash-dotdot')).toMatchURL('https://example.com/node_modules/lodash-es/lodash.js');
|
||||
});
|
||||
|
||||
it('should work for package submodules', () => {
|
||||
expect(resolveUnderTest('moment/foo')).toMatchURL('https://example.com/node_modules/moment/src/foo');
|
||||
expect(resolveUnderTest('lodash-dot/foo')).toMatchURL('https://example.com/app/node_modules/lodash-es/foo');
|
||||
expect(resolveUnderTest('lodash-dotdot/foo')).toMatchURL('https://example.com/node_modules/lodash-es/foo');
|
||||
});
|
||||
|
||||
it('should work for package names that end in a slash by just passing through', () => {
|
||||
// TODO: is this the right behavior, or should we throw?
|
||||
expect(resolveUnderTest('moment/')).toMatchURL('https://example.com/node_modules/moment/src/');
|
||||
});
|
||||
|
||||
it('should still fail for package modules that are not declared', () => {
|
||||
expect(() => resolveUnderTest('underscore/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('underscore/foo')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should fail for package submodules that map to nowhere', () => {
|
||||
expect(() => resolveUnderTest('nowhere/foo')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tricky specifiers', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"package/withslash": "/node_modules/package-with-slash/index.mjs",
|
||||
"not-a-package": "/lib/not-a-package.mjs",
|
||||
".": "/lib/dot.mjs",
|
||||
"..": "/lib/dotdot.mjs",
|
||||
"..\\\\": "/lib/dotdotbackslash.mjs",
|
||||
"%2E": "/lib/percent2e.mjs",
|
||||
"%2F": "/lib/percent2f.mjs"
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should work for explicitly-mapped specifiers that happen to have a slash', () => {
|
||||
expect(resolveUnderTest('package/withslash')).toMatchURL('https://example.com/node_modules/package-with-slash/index.mjs');
|
||||
});
|
||||
|
||||
it('should work when the specifier has punctuation', () => {
|
||||
expect(resolveUnderTest('.')).toMatchURL('https://example.com/lib/dot.mjs');
|
||||
expect(resolveUnderTest('..')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
expect(resolveUnderTest('..\\')).toMatchURL('https://example.com/lib/dotdotbackslash.mjs');
|
||||
expect(resolveUnderTest('%2E')).toMatchURL('https://example.com/lib/percent2e.mjs');
|
||||
expect(resolveUnderTest('%2F')).toMatchURL('https://example.com/lib/percent2f.mjs');
|
||||
});
|
||||
|
||||
it('should fail for attempting to get a submodule of something not declared with a trailing slash', () => {
|
||||
expect(() => resolveUnderTest('not-a-package/foo')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('URL-like specifiers', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"/node_modules/als-polyfill/index.mjs": "std:kv-storage",
|
||||
|
||||
"/lib/foo.mjs": "./more/bar.mjs",
|
||||
"./dotrelative/foo.mjs": "/lib/dot.mjs",
|
||||
"../dotdotrelative/foo.mjs": "/lib/dotdot.mjs",
|
||||
|
||||
"/lib/no.mjs": null,
|
||||
"./dotrelative/no.mjs": [],
|
||||
|
||||
"/": "/lib/slash-only/",
|
||||
"./": "/lib/dotslash-only/",
|
||||
|
||||
"/test/": "/lib/url-trailing-slash/",
|
||||
"./test/": "/lib/url-trailing-slash-dot/",
|
||||
|
||||
"/test": "/lib/test1.mjs",
|
||||
"../test": "/lib/test2.mjs"
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should remap to other URLs', () => {
|
||||
expect(resolveUnderTest('https://example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs');
|
||||
expect(resolveUnderTest('https://///example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs');
|
||||
expect(resolveUnderTest('/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs');
|
||||
|
||||
expect(resolveUnderTest('https://example.com/app/dotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dot.mjs');
|
||||
expect(resolveUnderTest('../app/dotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dot.mjs');
|
||||
|
||||
expect(resolveUnderTest('https://example.com/dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
expect(resolveUnderTest('../dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
});
|
||||
|
||||
it('should fail for URLs that remap to empty arrays', () => {
|
||||
expect(() => resolveUnderTest('https://example.com/lib/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('/lib/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('../lib/no.mjs')).toThrow(TypeError);
|
||||
|
||||
expect(() => resolveUnderTest('https://example.com/app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('/app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('../app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should remap URLs that are just composed from / and .', () => {
|
||||
expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only/');
|
||||
expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only/');
|
||||
expect(resolveUnderTest('../')).toMatchURL('https://example.com/lib/slash-only/');
|
||||
|
||||
expect(resolveUnderTest('https://example.com/app/')).toMatchURL('https://example.com/lib/dotslash-only/');
|
||||
expect(resolveUnderTest('/app/')).toMatchURL('https://example.com/lib/dotslash-only/');
|
||||
expect(resolveUnderTest('../app/')).toMatchURL('https://example.com/lib/dotslash-only/');
|
||||
});
|
||||
|
||||
it('should remap URLs that are prefix-matched by keys with trailing slashes', () => {
|
||||
expect(resolveUnderTest('/test/foo.mjs')).toMatchURL('https://example.com/lib/url-trailing-slash/foo.mjs');
|
||||
expect(resolveUnderTest('https://example.com/app/test/foo.mjs')).toMatchURL('https://example.com/lib/url-trailing-slash-dot/foo.mjs');
|
||||
});
|
||||
|
||||
it('should use the last entry\'s address when URL-like specifiers parse to the same absolute URL', () => {
|
||||
expect(resolveUnderTest('/test')).toMatchURL('https://example.com/lib/test2.mjs');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Overlapping entries with trailing slashes', () => {
|
||||
it('should favor the most-specific key (no empty arrays)', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": "/1",
|
||||
"a/": "/2/",
|
||||
"a/b": "/3",
|
||||
"a/b/": "/4/"
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(resolveUnderTest('a')).toMatchURL('https://example.com/1');
|
||||
expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/');
|
||||
expect(resolveUnderTest('a/b')).toMatchURL('https://example.com/3');
|
||||
expect(resolveUnderTest('a/b/')).toMatchURL('https://example.com/4/');
|
||||
expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c');
|
||||
});
|
||||
|
||||
it('should favor the most-specific key when empty arrays are involved for less-specific keys', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": [],
|
||||
"a/": [],
|
||||
"a/b": "/3",
|
||||
"a/b/": "/4/"
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('a')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('a/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('a/x')).toThrow(TypeError);
|
||||
expect(resolveUnderTest('a/b')).toMatchURL('https://example.com/3');
|
||||
expect(resolveUnderTest('a/b/')).toMatchURL('https://example.com/4/');
|
||||
expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c');
|
||||
expect(() => resolveUnderTest('a/x/c')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should favor the most-specific key when empty arrays are involved for more-specific keys', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": "/1",
|
||||
"a/": "/2/",
|
||||
"a/b": [],
|
||||
"a/b/": []
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(resolveUnderTest('a')).toMatchURL('https://example.com/1');
|
||||
expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/');
|
||||
expect(resolveUnderTest('a/x')).toMatchURL('https://example.com/2/x');
|
||||
expect(() => resolveUnderTest('a/b')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('a/b/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('a/b/c')).toThrow(TypeError);
|
||||
expect(resolveUnderTest('a/x/c')).toMatchURL('https://example.com/2/x/c');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// "bare/..." (i.e. without leading "./") are bare specifiers
|
||||
// (not relative paths).
|
||||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare/bare": "../resources/log.js?pipe=sub&name=bare",
|
||||
"bare/cross-origin-bare": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bare",
|
||||
"bare/to-data": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"bare/to-bare": "bare/bare"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const tests = {
|
||||
// Arrays of expected results for:
|
||||
// - <script src type="module">,
|
||||
// - <script src> (classic script),
|
||||
// - static import, and
|
||||
// - dynamic import.
|
||||
|
||||
// Currently, Chromium's implementation resolves import maps as a part of
|
||||
// specifier resolution, and thus failure in import map resolution causes
|
||||
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
|
||||
// below. https://crbug.com/928435
|
||||
|
||||
// Bare to HTTP(S).
|
||||
"bare/bare":
|
||||
[Result.URL, Result.URL, "log:bare", "log:bare"],
|
||||
"bare/cross-origin-bare":
|
||||
[Result.URL, Result.URL, "log:cross-origin-bare", "log:cross-origin-bare"],
|
||||
|
||||
// Bare to data:
|
||||
"bare/to-data":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// Bare to bare mapping is disabled.
|
||||
"bare/to-bare":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
||||
</script>
|
||||
<body>
|
|
@ -0,0 +1 @@
|
|||
Content-Type: text/javascript
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// "bare/..." (i.e. without leading "./") are bare specifiers
|
||||
// (not relative paths).
|
||||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare": "../resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"data:text/javascript,log.push('data:foo')": "../resources/log.js?pipe=sub&name=foo",
|
||||
"data:text/javascript,log.push('data:cross-origin-foo')": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo",
|
||||
"data:text/javascript,log.push('data:to-data')": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"data:text/javascript,log.push('data:to-bare')": "bare"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const tests = {
|
||||
// Arrays of expected results for:
|
||||
// - <script src type="module">,
|
||||
// - <script src> (classic script),
|
||||
// - static import, and
|
||||
// - dynamic import.
|
||||
|
||||
// Currently, Chromium's implementation resolves import maps as a part of
|
||||
// specifier resolution, and thus failure in import map resolution causes
|
||||
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
|
||||
// below. https://crbug.com/928435
|
||||
|
||||
// data: to HTTP(S).
|
||||
"data:text/javascript,log.push('data:foo')":
|
||||
[Result.URL, Result.URL, "log:foo", "log:foo"],
|
||||
"data:text/javascript,log.push('data:cross-origin-foo')":
|
||||
[Result.URL, Result.URL, "log:cross-origin-foo", "log:cross-origin-foo"],
|
||||
|
||||
// data: to data:
|
||||
"data:text/javascript,log.push('data:to-data')":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// data: to bare mapping is disabled.
|
||||
"data:text/javascript,log.push('data:to-bare')":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
||||
</script>
|
||||
<body>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/test-helper.js"></script>
|
||||
|
||||
<script>
|
||||
// "bare/..." (i.e. without leading "./") are bare specifiers
|
||||
// (not relative paths).
|
||||
const importMap = `
|
||||
{
|
||||
"imports": {
|
||||
"bare": "../resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"../resources/log.js?pipe=sub&name=foo": "../resources/log.js?pipe=sub&name=bar",
|
||||
"../resources/log.js?pipe=sub&name=cross-origin-foo": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bar",
|
||||
"../resources/log.js?pipe=sub&name=to-data": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"../resources/log.js?pipe=sub&name=to-bare": "bare"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const tests = {
|
||||
// Arrays of expected results for:
|
||||
// - <script src type="module">,
|
||||
// - <script src> (classic script),
|
||||
// - static import, and
|
||||
// - dynamic import.
|
||||
|
||||
// Currently, Chromium's implementation resolves import maps as a part of
|
||||
// specifier resolution, and thus failure in import map resolution causes
|
||||
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
|
||||
// below. https://crbug.com/928435
|
||||
|
||||
// HTTP(S) to HTTP(S).
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=foo":
|
||||
[Result.URL, Result.URL, "log:bar", "log:bar"],
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo":
|
||||
[Result.URL, Result.URL, "log:cross-origin-bar", "log:cross-origin-bar"],
|
||||
|
||||
// HTTP(S) to data:
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-data":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// HTTP(S) to bare mapping is disabled.
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-bare":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
||||
</script>
|
||||
<body>
|
|
@ -5,7 +5,7 @@
|
|||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"./resources/log.js?pipe=sub&name=A": "./resources/log.js?pipe=sub&name=B"
|
||||
"../resources/log.js?pipe=sub&name=A": "../resources/log.js?pipe=sub&name=B"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -17,8 +17,8 @@ const log = [];
|
|||
// key will become the URL/specifier BEFORE import map resolution.
|
||||
// https://crbug.com/928435
|
||||
promise_test(() => {
|
||||
return import("./resources/log.js?pipe=sub&name=A")
|
||||
.then(() => import("./resources/log.js?pipe=sub&name=B"))
|
||||
return import("../resources/log.js?pipe=sub&name=A")
|
||||
.then(() => import("../resources/log.js?pipe=sub&name=B"))
|
||||
.then(() => assert_array_equals(log, ["log:B"]))
|
||||
},
|
||||
"Module map's key is the URL after import map resolution");
|
|
@ -0,0 +1 @@
|
|||
import "{{GET[url]}}";
|
|
@ -38,13 +38,7 @@ exports.expectWarnings = (input, baseURL, output, warnings = []) => {
|
|||
};
|
||||
|
||||
function testWarningHandler(expectedWarnings) {
|
||||
const warnings = [];
|
||||
const { warn } = console;
|
||||
console.warn = warning => {
|
||||
warnings.push(warning);
|
||||
};
|
||||
return () => {
|
||||
console.warn = warn;
|
||||
expect(warnings).toEqual(expectedWarnings);
|
||||
};
|
||||
// We don't check warnings on WPT tests, because there are no
|
||||
// ways to catch console warnings from JavaScript.
|
||||
return () => {};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
'use strict';
|
||||
const { expectSpecifierMap } = require('./helpers/parsing.js');
|
||||
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
|
||||
|
||||
describe('Relative URL-like addresses', () => {
|
||||
it('should accept strings prefixed with ./, ../, or /', () => {
|
||||
|
@ -12,9 +11,9 @@ describe('Relative URL-like addresses', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
dotSlash: [expect.toMatchURL('https://base.example/path1/path2/foo')],
|
||||
dotDotSlash: [expect.toMatchURL('https://base.example/path1/foo')],
|
||||
slash: [expect.toMatchURL('https://base.example/foo')]
|
||||
dotSlash: expect.toMatchURL('https://base.example/path1/path2/foo'),
|
||||
dotDotSlash: expect.toMatchURL('https://base.example/path1/foo'),
|
||||
slash: expect.toMatchURL('https://base.example/foo')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -28,9 +27,6 @@ describe('Relative URL-like addresses', () => {
|
|||
}`,
|
||||
'data:text/html,test',
|
||||
{
|
||||
dotSlash: [],
|
||||
dotDotSlash: [],
|
||||
slash: []
|
||||
},
|
||||
[
|
||||
`Invalid address "./foo" for the specifier key "dotSlash".`,
|
||||
|
@ -49,9 +45,9 @@ describe('Relative URL-like addresses', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
dotSlash: [expect.toMatchURL('https://base.example/path1/path2/')],
|
||||
dotDotSlash: [expect.toMatchURL('https://base.example/path1/')],
|
||||
slash: [expect.toMatchURL('https://base.example/')]
|
||||
dotSlash: expect.toMatchURL('https://base.example/path1/path2/'),
|
||||
dotDotSlash: expect.toMatchURL('https://base.example/path1/'),
|
||||
slash: expect.toMatchURL('https://base.example/')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -69,13 +65,6 @@ describe('Relative URL-like addresses', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
dotSlash1: [],
|
||||
dotDotSlash1: [],
|
||||
dotSlash2: [],
|
||||
dotDotSlash2: [],
|
||||
slash2: [],
|
||||
dotSlash3: [],
|
||||
dotDotSlash3: []
|
||||
},
|
||||
[
|
||||
`Invalid address "%2E/" for the specifier key "dotSlash1".`,
|
||||
|
@ -90,49 +79,6 @@ describe('Relative URL-like addresses', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Built-in module addresses', () => {
|
||||
it('should accept URLs using the built-in module scheme', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": "${BUILT_IN_MODULE_SCHEME}:foo"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
foo: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo`)]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore percent-encoded variants of the built-in module scheme', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
foo: []
|
||||
},
|
||||
[`Invalid address "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" for the specifier key "foo".`]
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow built-in module URLs that contain "/" or "\\"', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"slashEnd": "${BUILT_IN_MODULE_SCHEME}:foo/",
|
||||
"slashMiddle": "${BUILT_IN_MODULE_SCHEME}:foo/bar",
|
||||
"backslash": "${BUILT_IN_MODULE_SCHEME}:foo\\\\baz"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
slashEnd: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/`)],
|
||||
slashMiddle: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/bar`)],
|
||||
backslash: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo\\baz`)]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Absolute URL addresses', () => {
|
||||
it('should only accept absolute URL addresses with fetch schemes', () => {
|
||||
expectSpecifierMap(
|
||||
|
@ -141,7 +87,7 @@ describe('Absolute URL addresses', () => {
|
|||
"blob": "blob:good",
|
||||
"data": "data:good",
|
||||
"file": "file:///good",
|
||||
"filesystem": "filesystem:good",
|
||||
"filesystem": "filesystem:http://example.com/good/",
|
||||
"http": "http://good/",
|
||||
"https": "https://good/",
|
||||
"ftp": "ftp://good/",
|
||||
|
@ -152,65 +98,20 @@ describe('Absolute URL addresses', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
about: [expect.toMatchURL('about:good')],
|
||||
blob: [expect.toMatchURL('blob:good')],
|
||||
data: [expect.toMatchURL('data:good')],
|
||||
file: [expect.toMatchURL('file:///good')],
|
||||
filesystem: [expect.toMatchURL('filesystem:good')],
|
||||
http: [expect.toMatchURL('http://good/')],
|
||||
https: [expect.toMatchURL('https://good/')],
|
||||
ftp: [expect.toMatchURL('ftp://good/')],
|
||||
import: [],
|
||||
mailto: [],
|
||||
javascript: [],
|
||||
wss: []
|
||||
about: expect.toMatchURL('about:good'),
|
||||
blob: expect.toMatchURL('blob:good'),
|
||||
data: expect.toMatchURL('data:good'),
|
||||
file: expect.toMatchURL('file:///good'),
|
||||
filesystem: expect.toMatchURL('filesystem:http://example.com/good/'),
|
||||
http: expect.toMatchURL('http://good/'),
|
||||
https: expect.toMatchURL('https://good/'),
|
||||
ftp: expect.toMatchURL('ftp://good/'),
|
||||
import: expect.toMatchURL('import:bad'),
|
||||
javascript: expect.toMatchURL('javascript:bad'),
|
||||
mailto: expect.toMatchURL('mailto:bad'),
|
||||
wss: expect.toMatchURL('wss://bad/')
|
||||
},
|
||||
[
|
||||
`Invalid address "import:bad" for the specifier key "import".`,
|
||||
`Invalid address "mailto:bad" for the specifier key "mailto".`,
|
||||
`Invalid address "javascript:bad" for the specifier key "javascript".`,
|
||||
`Invalid address "wss:bad" for the specifier key "wss".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should only accept absolute URL addresses with fetch schemes inside arrays', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"about": ["about:good"],
|
||||
"blob": ["blob:good"],
|
||||
"data": ["data:good"],
|
||||
"file": ["file:///good"],
|
||||
"filesystem": ["filesystem:good"],
|
||||
"http": ["http://good/"],
|
||||
"https": ["https://good/"],
|
||||
"ftp": ["ftp://good/"],
|
||||
"import": ["import:bad"],
|
||||
"mailto": ["mailto:bad"],
|
||||
"javascript": ["javascript:bad"],
|
||||
"wss": ["wss:bad"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
about: [expect.toMatchURL('about:good')],
|
||||
blob: [expect.toMatchURL('blob:good')],
|
||||
data: [expect.toMatchURL('data:good')],
|
||||
file: [expect.toMatchURL('file:///good')],
|
||||
filesystem: [expect.toMatchURL('filesystem:good')],
|
||||
http: [expect.toMatchURL('http://good/')],
|
||||
https: [expect.toMatchURL('https://good/')],
|
||||
ftp: [expect.toMatchURL('ftp://good/')],
|
||||
import: [],
|
||||
mailto: [],
|
||||
javascript: [],
|
||||
wss: []
|
||||
},
|
||||
[
|
||||
`Invalid address "import:bad" for the specifier key "import".`,
|
||||
`Invalid address "mailto:bad" for the specifier key "mailto".`,
|
||||
`Invalid address "javascript:bad" for the specifier key "javascript".`,
|
||||
`Invalid address "wss:bad" for the specifier key "wss".`
|
||||
]
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -228,45 +129,11 @@ describe('Absolute URL addresses', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
unparseable1: [],
|
||||
unparseable2: [],
|
||||
unparseable3: [],
|
||||
invalidButParseable1: [expect.toMatchURL('https://example.org/')],
|
||||
invalidButParseable2: [expect.toMatchURL('https://example.com///')],
|
||||
prettyNormal: [expect.toMatchURL('https://example.net/')],
|
||||
percentDecoding: [expect.toMatchURL('https://example.com/')],
|
||||
noPercentDecoding: [expect.toMatchURL('https://example.com/%41')]
|
||||
},
|
||||
[
|
||||
`Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`,
|
||||
`Invalid address "https://example.com:demo" for the specifier key "unparseable2".`,
|
||||
`Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse absolute URLs, ignoring unparseable ones inside arrays', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"unparseable1": ["https://ex ample.org/"],
|
||||
"unparseable2": ["https://example.com:demo"],
|
||||
"unparseable3": ["http://[www.example.com]/"],
|
||||
"invalidButParseable1": ["https:example.org"],
|
||||
"invalidButParseable2": ["https://///example.com///"],
|
||||
"prettyNormal": ["https://example.net"],
|
||||
"percentDecoding": ["https://ex%41mple.com/"],
|
||||
"noPercentDecoding": ["https://example.com/%41"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
unparseable1: [],
|
||||
unparseable2: [],
|
||||
unparseable3: [],
|
||||
invalidButParseable1: [expect.toMatchURL('https://example.org/')],
|
||||
invalidButParseable2: [expect.toMatchURL('https://example.com///')],
|
||||
prettyNormal: [expect.toMatchURL('https://example.net/')],
|
||||
percentDecoding: [expect.toMatchURL('https://example.com/')],
|
||||
noPercentDecoding: [expect.toMatchURL('https://example.com/%41')]
|
||||
invalidButParseable1: expect.toMatchURL('https://example.org/'),
|
||||
invalidButParseable2: expect.toMatchURL('https://example.com///'),
|
||||
prettyNormal: expect.toMatchURL('https://example.net/'),
|
||||
percentDecoding: expect.toMatchURL('https://example.com/'),
|
||||
noPercentDecoding: expect.toMatchURL('https://example.com/%41')
|
||||
},
|
||||
[
|
||||
`Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`,
|
||||
|
@ -281,54 +148,12 @@ describe('Failing addresses: mismatched trailing slashes', () => {
|
|||
it('should warn for the simple case', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"trailer/": "/notrailer",
|
||||
"${BUILT_IN_MODULE_SCHEME}:trailer/": "/bim-notrailer"
|
||||
"trailer/": "/notrailer"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'trailer/': [],
|
||||
[`${BUILT_IN_MODULE_SCHEME}:trailer/`]: []
|
||||
},
|
||||
[
|
||||
`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`,
|
||||
`Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for a mismatch alone in an array', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"trailer/": ["/notrailer"],
|
||||
"${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-notrailer"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'trailer/': [],
|
||||
[`${BUILT_IN_MODULE_SCHEME}:trailer/`]: []
|
||||
},
|
||||
[
|
||||
`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`,
|
||||
`Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".`
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for a mismatch alongside non-mismatches in an array', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"trailer/": ["/atrailer/", "/notrailer"],
|
||||
"${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-atrailer/", "/bim-notrailer"]
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'trailer/': [expect.toMatchURL('https://base.example/atrailer/')],
|
||||
[`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [expect.toMatchURL('https://base.example/bim-atrailer/')]
|
||||
},
|
||||
[
|
||||
`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`,
|
||||
`Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".`
|
||||
]
|
||||
[`Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -342,7 +167,6 @@ describe('Other invalid addresses', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
foo: []
|
||||
},
|
||||
[`Invalid address "${bad}" for the specifier key "foo".`]
|
||||
);
|
||||
|
|
|
@ -45,24 +45,20 @@ describe('Mismatching the top-level schema', () => {
|
|||
});
|
||||
|
||||
describe('Mismatching the specifier map schema', () => {
|
||||
const invalidAddressStrings = ['true', '1', '{}'];
|
||||
const invalidInsideArrayStrings = ['null', 'true', '1', '{}', '[]'];
|
||||
const invalidAddressStrings = ['null', 'true', '1', '{}', '[]', '["https://example.com/"]'];
|
||||
|
||||
it('should ignore entries where the address is not a string, array, or null', () => {
|
||||
it('should ignore entries where the address is not a string', () => {
|
||||
for (const invalid of invalidAddressStrings) {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": ${invalid},
|
||||
"bar": ["https://example.com/"]
|
||||
"bar": "https://example.com/"
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
bar: [expect.toMatchURL('https://example.com/')]
|
||||
bar: expect.toMatchURL('https://example.com/')
|
||||
},
|
||||
[
|
||||
`Invalid address ${invalid} for the specifier key "foo". ` +
|
||||
`Addresses must be strings, arrays, or null.`
|
||||
]
|
||||
[`Invalid address ${invalid} for the specifier key "foo". Addresses must be strings.`]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -70,7 +66,7 @@ describe('Mismatching the specifier map schema', () => {
|
|||
it('should ignore entries where the specifier key is an empty string', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"": ["https://example.com/"]
|
||||
"": "https://example.com/"
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{},
|
||||
|
@ -78,26 +74,6 @@ describe('Mismatching the specifier map schema', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should ignore members of an address array that are not strings', () => {
|
||||
for (const invalid of invalidInsideArrayStrings) {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": ["https://example.com/", ${invalid}],
|
||||
"bar": ["https://example.com/"]
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
foo: [expect.toMatchURL('https://example.com/')],
|
||||
bar: [expect.toMatchURL('https://example.com/')]
|
||||
},
|
||||
[
|
||||
`Invalid address ${invalid} inside the address array for the specifier key "foo". ` +
|
||||
`Address arrays must only contain strings.`
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw if a scope\'s value is not an object', () => {
|
||||
for (const invalid of nonObjectStrings) {
|
||||
expectBad(`{ "scopes": { "https://scope.example/": ${invalid} } }`, 'https://base.example/');
|
||||
|
@ -120,20 +96,4 @@ describe('Normalization', () => {
|
|||
expect(parseFromString(`{ "imports": {} }`, 'https://base.example/'))
|
||||
.toEqual({ imports: {}, scopes: {} });
|
||||
});
|
||||
|
||||
it('should normalize addresses to arrays', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"foo": "https://example.com/1",
|
||||
"bar": ["https://example.com/2"],
|
||||
"baz": null
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
foo: [expect.toMatchURL('https://example.com/1')],
|
||||
bar: [expect.toMatchURL('https://example.com/2')],
|
||||
baz: []
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -62,14 +62,14 @@ describe('Relative URL scope keys', () => {
|
|||
});
|
||||
|
||||
describe('Absolute URL scope keys', () => {
|
||||
it('should only accept absolute URL scope keys with fetch schemes', () => {
|
||||
it('should accept all absolute URL scope keys, with or without fetch schemes', () => {
|
||||
expectScopes(
|
||||
[
|
||||
'about:good',
|
||||
'blob:good',
|
||||
'data:good',
|
||||
'file:///good',
|
||||
'filesystem:good',
|
||||
'filesystem:http://example.com/good/',
|
||||
'http://good/',
|
||||
'https://good/',
|
||||
'ftp://good/',
|
||||
|
@ -84,17 +84,16 @@ describe('Absolute URL scope keys', () => {
|
|||
'blob:good',
|
||||
'data:good',
|
||||
'file:///good',
|
||||
'filesystem:good',
|
||||
'filesystem:http://example.com/good/',
|
||||
'http://good/',
|
||||
'https://good/',
|
||||
'ftp://good/'
|
||||
'ftp://good/',
|
||||
'import:bad',
|
||||
'mailto:bad',
|
||||
'javascript:bad',
|
||||
'wss://ba/'
|
||||
],
|
||||
[
|
||||
'Invalid scope "import:bad". Scope URLs must have a fetch scheme.',
|
||||
'Invalid scope "mailto:bad". Scope URLs must have a fetch scheme.',
|
||||
'Invalid scope "javascript:bad". Scope URLs must have a fetch scheme.',
|
||||
'Invalid scope "wss://ba/". Scope URLs must have a fetch scheme.'
|
||||
]
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
'use strict';
|
||||
const { expectSpecifierMap } = require('./helpers/parsing.js');
|
||||
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
|
||||
|
||||
const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`;
|
||||
|
||||
describe('Relative URL-like specifier keys', () => {
|
||||
it('should absolutize strings prefixed with ./, ../, or / into the corresponding URLs', () => {
|
||||
|
@ -14,9 +11,9 @@ describe('Relative URL-like specifier keys', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'https://base.example/path1/path2/foo': [expect.toMatchURL('https://base.example/dotslash')],
|
||||
'https://base.example/path1/foo': [expect.toMatchURL('https://base.example/dotdotslash')],
|
||||
'https://base.example/foo': [expect.toMatchURL('https://base.example/slash')]
|
||||
'https://base.example/path1/path2/foo': expect.toMatchURL('https://base.example/dotslash'),
|
||||
'https://base.example/path1/foo': expect.toMatchURL('https://base.example/dotdotslash'),
|
||||
'https://base.example/foo': expect.toMatchURL('https://base.example/slash')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -30,9 +27,9 @@ describe('Relative URL-like specifier keys', () => {
|
|||
}`,
|
||||
'data:text/html,test',
|
||||
{
|
||||
'./foo': [expect.toMatchURL('https://example.com/dotslash')],
|
||||
'../foo': [expect.toMatchURL('https://example.com/dotdotslash')],
|
||||
'/foo': [expect.toMatchURL('https://example.com/slash')]
|
||||
'./foo': expect.toMatchURL('https://example.com/dotslash'),
|
||||
'../foo': expect.toMatchURL('https://example.com/dotdotslash'),
|
||||
'/foo': expect.toMatchURL('https://example.com/slash')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -46,9 +43,9 @@ describe('Relative URL-like specifier keys', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'https://base.example/path1/path2/': [expect.toMatchURL('https://base.example/dotslash/')],
|
||||
'https://base.example/path1/': [expect.toMatchURL('https://base.example/dotdotslash/')],
|
||||
'https://base.example/': [expect.toMatchURL('https://base.example/slash/')]
|
||||
'https://base.example/path1/path2/': expect.toMatchURL('https://base.example/dotslash/'),
|
||||
'https://base.example/path1/': expect.toMatchURL('https://base.example/dotdotslash/'),
|
||||
'https://base.example/': expect.toMatchURL('https://base.example/slash/')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -66,27 +63,27 @@ describe('Relative URL-like specifier keys', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'%2E/': [expect.toMatchURL('https://base.example/dotSlash1/')],
|
||||
'%2E%2E/': [expect.toMatchURL('https://base.example/dotDotSlash1/')],
|
||||
'.%2F': [expect.toMatchURL('https://base.example/dotSlash2')],
|
||||
'..%2F': [expect.toMatchURL('https://base.example/dotDotSlash2')],
|
||||
'%2F': [expect.toMatchURL('https://base.example/slash2')],
|
||||
'%2E%2F': [expect.toMatchURL('https://base.example/dotSlash3')],
|
||||
'%2E%2E%2F': [expect.toMatchURL('https://base.example/dotDotSlash3')]
|
||||
'%2E/': expect.toMatchURL('https://base.example/dotSlash1/'),
|
||||
'%2E%2E/': expect.toMatchURL('https://base.example/dotDotSlash1/'),
|
||||
'.%2F': expect.toMatchURL('https://base.example/dotSlash2'),
|
||||
'..%2F': expect.toMatchURL('https://base.example/dotDotSlash2'),
|
||||
'%2F': expect.toMatchURL('https://base.example/slash2'),
|
||||
'%2E%2F': expect.toMatchURL('https://base.example/dotSlash3'),
|
||||
'%2E%2E%2F': expect.toMatchURL('https://base.example/dotDotSlash3')
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Absolute URL specifier keys', () => {
|
||||
it('should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers', () => {
|
||||
it('Accept all absolute URL specifier keys even with fetch schemes as URLs', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"about:good": "/about",
|
||||
"blob:good": "/blob",
|
||||
"data:good": "/data",
|
||||
"file:///good": "/file",
|
||||
"filesystem:good": "/filesystem",
|
||||
"filesystem:http://example.com/good/": "/filesystem/",
|
||||
"http://good/": "/http/",
|
||||
"https://good/": "/https/",
|
||||
"ftp://good/": "/ftp/",
|
||||
|
@ -97,18 +94,18 @@ describe('Absolute URL specifier keys', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'about:good': [expect.toMatchURL('https://base.example/about')],
|
||||
'blob:good': [expect.toMatchURL('https://base.example/blob')],
|
||||
'data:good': [expect.toMatchURL('https://base.example/data')],
|
||||
'file:///good': [expect.toMatchURL('https://base.example/file')],
|
||||
'filesystem:good': [expect.toMatchURL('https://base.example/filesystem')],
|
||||
'http://good/': [expect.toMatchURL('https://base.example/http/')],
|
||||
'https://good/': [expect.toMatchURL('https://base.example/https/')],
|
||||
'ftp://good/': [expect.toMatchURL('https://base.example/ftp/')],
|
||||
'import:bad': [expect.toMatchURL('https://base.example/import')],
|
||||
'mailto:bad': [expect.toMatchURL('https://base.example/mailto')],
|
||||
'javascript:bad': [expect.toMatchURL('https://base.example/javascript')],
|
||||
'wss:bad': [expect.toMatchURL('https://base.example/wss')]
|
||||
'about:good': expect.toMatchURL('https://base.example/about'),
|
||||
'blob:good': expect.toMatchURL('https://base.example/blob'),
|
||||
'data:good': expect.toMatchURL('https://base.example/data'),
|
||||
'file:///good': expect.toMatchURL('https://base.example/file'),
|
||||
'filesystem:http://example.com/good/': expect.toMatchURL('https://base.example/filesystem/'),
|
||||
'http://good/': expect.toMatchURL('https://base.example/http/'),
|
||||
'https://good/': expect.toMatchURL('https://base.example/https/'),
|
||||
'ftp://good/': expect.toMatchURL('https://base.example/ftp/'),
|
||||
'import:bad': expect.toMatchURL('https://base.example/import'),
|
||||
'mailto:bad': expect.toMatchURL('https://base.example/mailto'),
|
||||
'javascript:bad': expect.toMatchURL('https://base.example/javascript'),
|
||||
'wss://bad/': expect.toMatchURL('https://base.example/wss')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -127,32 +124,40 @@ describe('Absolute URL specifier keys', () => {
|
|||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
{
|
||||
'https://ex ample.org/': [expect.toMatchURL('https://base.example/unparseable1/')],
|
||||
'https://example.com:demo': [expect.toMatchURL('https://base.example/unparseable2')],
|
||||
'http://[www.example.com]/': [expect.toMatchURL('https://base.example/unparseable3/')],
|
||||
'https://example.org/': [expect.toMatchURL('https://base.example/invalidButParseable1/')],
|
||||
'https://example.com///': [expect.toMatchURL('https://base.example/invalidButParseable2/')],
|
||||
'https://example.net/': [expect.toMatchURL('https://base.example/prettyNormal/')],
|
||||
'https://example.com/': [expect.toMatchURL('https://base.example/percentDecoding/')],
|
||||
'https://example.com/%41': [expect.toMatchURL('https://base.example/noPercentDecoding')]
|
||||
'https://ex ample.org/': expect.toMatchURL('https://base.example/unparseable1/'),
|
||||
'https://example.com:demo': expect.toMatchURL('https://base.example/unparseable2'),
|
||||
'http://[www.example.com]/': expect.toMatchURL('https://base.example/unparseable3/'),
|
||||
'https://example.org/': expect.toMatchURL('https://base.example/invalidButParseable1/'),
|
||||
'https://example.com///': expect.toMatchURL('https://base.example/invalidButParseable2/'),
|
||||
'https://example.net/': expect.toMatchURL('https://base.example/prettyNormal/'),
|
||||
'https://example.com/': expect.toMatchURL('https://base.example/percentDecoding/'),
|
||||
'https://example.com/%41': expect.toMatchURL('https://base.example/noPercentDecoding')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse built-in module specifier keys, including with a "/"', () => {
|
||||
it('should sort correctly (issue #181)', () => {
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"${BLANK}": "/blank",
|
||||
"${BLANK}/": "/blank/",
|
||||
"${BLANK}/foo": "/blank/foo",
|
||||
"${BLANK}\\\\foo": "/blank/backslashfoo"
|
||||
"https://example.com/aaa": "https://example.com/aaa",
|
||||
"https://example.com/a": "https://example.com/a"
|
||||
}`,
|
||||
'https://base.example/path1/path2/path3',
|
||||
'https://base.example/',
|
||||
{
|
||||
[BLANK]: [expect.toMatchURL('https://base.example/blank')],
|
||||
[`${BLANK}/`]: [expect.toMatchURL('https://base.example/blank/')],
|
||||
[`${BLANK}/foo`]: [expect.toMatchURL('https://base.example/blank/foo')],
|
||||
[`${BLANK}\\foo`]: [expect.toMatchURL('https://base.example/blank/backslashfoo')]
|
||||
'https://example.com/aaa': expect.toMatchURL('https://example.com/aaa'),
|
||||
'https://example.com/a': expect.toMatchURL('https://example.com/a')
|
||||
}
|
||||
);
|
||||
|
||||
expectSpecifierMap(
|
||||
`{
|
||||
"https://example.com/a": "https://example.com/a",
|
||||
"https://example.com/aaa": "https://example.com/aaa"
|
||||
}`,
|
||||
'https://base.example/',
|
||||
{
|
||||
'https://example.com/aaa': expect.toMatchURL('https://example.com/aaa'),
|
||||
'https://example.com/a': expect.toMatchURL('https://example.com/a')
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -16,20 +16,6 @@ describe('Mapped using scope instead of "imports"', () => {
|
|||
const inJSDirURL = new URL('https://example.com/js/app.mjs');
|
||||
const topLevelURL = new URL('https://example.com/app.mjs');
|
||||
|
||||
it('should fail when the mapping is to an empty array', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"scopes": {
|
||||
"/js/": {
|
||||
"moment": null,
|
||||
"lodash": []
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('lodash', inJSDirURL)).toThrow(TypeError);
|
||||
});
|
||||
|
||||
describe('Exact vs. prefix based matching', () => {
|
||||
it('should match correctly when both are in the map', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
|
@ -153,14 +139,17 @@ describe('Mapped using scope instead of "imports"', () => {
|
|||
"imports": {
|
||||
"a": "/a-1.mjs",
|
||||
"b": "/b-1.mjs",
|
||||
"c": "/c-1.mjs"
|
||||
"c": "/c-1.mjs",
|
||||
"d": "/d-1.mjs"
|
||||
},
|
||||
"scopes": {
|
||||
"/scope2/": {
|
||||
"a": "/a-2.mjs"
|
||||
"a": "/a-2.mjs",
|
||||
"d": "/d-2.mjs"
|
||||
},
|
||||
"/scope2/scope3/": {
|
||||
"b": "/b-3.mjs"
|
||||
"b": "/b-3.mjs",
|
||||
"d": "/d-3.mjs"
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
@ -173,18 +162,21 @@ describe('Mapped using scope instead of "imports"', () => {
|
|||
expect(resolveUnderTest('a', scope1URL)).toMatchURL('https://example.com/a-1.mjs');
|
||||
expect(resolveUnderTest('b', scope1URL)).toMatchURL('https://example.com/b-1.mjs');
|
||||
expect(resolveUnderTest('c', scope1URL)).toMatchURL('https://example.com/c-1.mjs');
|
||||
expect(resolveUnderTest('d', scope1URL)).toMatchURL('https://example.com/d-1.mjs');
|
||||
});
|
||||
|
||||
it('should use a direct scope override', () => {
|
||||
expect(resolveUnderTest('a', scope2URL)).toMatchURL('https://example.com/a-2.mjs');
|
||||
expect(resolveUnderTest('b', scope2URL)).toMatchURL('https://example.com/b-1.mjs');
|
||||
expect(resolveUnderTest('c', scope2URL)).toMatchURL('https://example.com/c-1.mjs');
|
||||
expect(resolveUnderTest('d', scope2URL)).toMatchURL('https://example.com/d-2.mjs');
|
||||
});
|
||||
|
||||
it('should use an indirect scope override', () => {
|
||||
expect(resolveUnderTest('a', scope3URL)).toMatchURL('https://example.com/a-2.mjs');
|
||||
expect(resolveUnderTest('b', scope3URL)).toMatchURL('https://example.com/b-3.mjs');
|
||||
expect(resolveUnderTest('c', scope3URL)).toMatchURL('https://example.com/c-1.mjs');
|
||||
expect(resolveUnderTest('d', scope3URL)).toMatchURL('https://example.com/d-3.mjs');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -42,11 +42,11 @@ describe('Unmapped', () => {
|
|||
expect(resolveUnderTest('https://///example.com///')).toMatchURL('https://example.com///');
|
||||
});
|
||||
|
||||
it('should fail for absolute non-fetch-scheme URLs', () => {
|
||||
expect(() => resolveUnderTest('mailto:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('import:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('javascript:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('wss:bad')).toThrow(TypeError);
|
||||
it('should parse absolute non-fetch-scheme URLs', () => {
|
||||
expect(resolveUnderTest('mailto:bad')).toMatchURL('mailto:bad');
|
||||
expect(resolveUnderTest('import:bad')).toMatchURL('import:bad');
|
||||
expect(resolveUnderTest('javascript:bad')).toMatchURL('javascript:bad');
|
||||
expect(resolveUnderTest('wss:bad')).toMatchURL('wss://bad/');
|
||||
});
|
||||
|
||||
it('should fail for strings not parseable as absolute URLs and not starting with ./ ../ or /', () => {
|
||||
|
@ -64,18 +64,6 @@ describe('Unmapped', () => {
|
|||
});
|
||||
|
||||
describe('Mapped using the "imports" key only (no scopes)', () => {
|
||||
it('should fail when the mapping is to an empty array', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"moment": null,
|
||||
"lodash": []
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('moment')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('lodash')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
describe('Package-like scenarios', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
|
@ -84,8 +72,7 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
"lodash-dot": "./node_modules/lodash-es/lodash.js",
|
||||
"lodash-dot/": "./node_modules/lodash-es/",
|
||||
"lodash-dotdot": "../node_modules/lodash-es/lodash.js",
|
||||
"lodash-dotdot/": "../node_modules/lodash-es/",
|
||||
"nowhere/": []
|
||||
"lodash-dotdot/": "../node_modules/lodash-es/"
|
||||
}
|
||||
}`);
|
||||
|
||||
|
@ -110,10 +97,6 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
expect(() => resolveUnderTest('underscore/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('underscore/foo')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should fail for package submodules that map to nowhere', () => {
|
||||
expect(() => resolveUnderTest('nowhere/foo')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tricky specifiers', () => {
|
||||
|
@ -121,6 +104,7 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
"imports": {
|
||||
"package/withslash": "/node_modules/package-with-slash/index.mjs",
|
||||
"not-a-package": "/lib/not-a-package.mjs",
|
||||
"only-slash/": "/lib/only-slash/",
|
||||
".": "/lib/dot.mjs",
|
||||
"..": "/lib/dotdot.mjs",
|
||||
"..\\\\": "/lib/dotdotbackslash.mjs",
|
||||
|
@ -144,20 +128,19 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
it('should fail for attempting to get a submodule of something not declared with a trailing slash', () => {
|
||||
expect(() => resolveUnderTest('not-a-package/foo')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should fail for attempting to get a module if only a trailing-slash version is present', () => {
|
||||
expect(() => resolveUnderTest('only-slash')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('URL-like specifiers', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"/node_modules/als-polyfill/index.mjs": "std:kv-storage",
|
||||
|
||||
"/lib/foo.mjs": "./more/bar.mjs",
|
||||
"./dotrelative/foo.mjs": "/lib/dot.mjs",
|
||||
"../dotdotrelative/foo.mjs": "/lib/dotdot.mjs",
|
||||
|
||||
"/lib/no.mjs": null,
|
||||
"./dotrelative/no.mjs": [],
|
||||
|
||||
"/": "/lib/slash-only/",
|
||||
"./": "/lib/dotslash-only/",
|
||||
|
||||
|
@ -181,16 +164,6 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
expect(resolveUnderTest('../dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
});
|
||||
|
||||
it('should fail for URLs that remap to empty arrays', () => {
|
||||
expect(() => resolveUnderTest('https://example.com/lib/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('/lib/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('../lib/no.mjs')).toThrow(TypeError);
|
||||
|
||||
expect(() => resolveUnderTest('https://example.com/app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('/app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('../app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should remap URLs that are just composed from / and .', () => {
|
||||
expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only/');
|
||||
expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only/');
|
||||
|
@ -212,7 +185,7 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
});
|
||||
|
||||
describe('Overlapping entries with trailing slashes', () => {
|
||||
it('should favor the most-specific key (no empty arrays)', () => {
|
||||
it('should favor the most-specific key', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": "/1",
|
||||
|
@ -229,11 +202,9 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c');
|
||||
});
|
||||
|
||||
it('should favor the most-specific key when empty arrays are involved for less-specific keys', () => {
|
||||
it('should favor the most-specific key when there are no mappings for less-specific keys', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": [],
|
||||
"a/": [],
|
||||
"a/b": "/3",
|
||||
"a/b/": "/4/"
|
||||
}
|
||||
|
@ -247,24 +218,15 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
|||
expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c');
|
||||
expect(() => resolveUnderTest('a/x/c')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
it('should favor the most-specific key when empty arrays are involved for more-specific keys', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"a": "/1",
|
||||
"a/": "/2/",
|
||||
"a/b": [],
|
||||
"a/b/": []
|
||||
}
|
||||
}`);
|
||||
it('should deal with data: URL bases', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"foo/": "data:text/javascript,foo/"
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(resolveUnderTest('a')).toMatchURL('https://example.com/1');
|
||||
expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/');
|
||||
expect(resolveUnderTest('a/x')).toMatchURL('https://example.com/2/x');
|
||||
expect(() => resolveUnderTest('a/b')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('a/b/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('a/b/c')).toThrow(TypeError);
|
||||
expect(resolveUnderTest('a/x/c')).toMatchURL('https://example.com/2/x/c');
|
||||
});
|
||||
expect(() => resolveUnderTest('foo/bar')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,6 +15,22 @@ function require(name) {
|
|||
}, exports);
|
||||
}
|
||||
|
||||
// Sort keys and then stringify for comparison.
|
||||
function stringifyImportMap(importMap) {
|
||||
function getKeys(m) {
|
||||
if (typeof m !== 'object')
|
||||
return [];
|
||||
|
||||
let keys = [];
|
||||
for (const key in m) {
|
||||
keys.push(key);
|
||||
keys = keys.concat(getKeys(m[key]));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
return JSON.stringify(importMap, getKeys(importMap).sort());
|
||||
}
|
||||
|
||||
function expect(v) {
|
||||
return {
|
||||
toMatchURL: expected => assert_equals(v, expected),
|
||||
|
@ -34,10 +50,8 @@ function expect(v) {
|
|||
const actualParsedImportMap = JSON.parse(
|
||||
internals.getParsedImportMap(v.contentDocument));
|
||||
assert_equals(
|
||||
JSON.stringify(actualParsedImportMap,
|
||||
Object.keys(actualParsedImportMap).sort()),
|
||||
JSON.stringify(expected.imports,
|
||||
Object.keys(expected.imports).sort())
|
||||
stringifyImportMap(actualParsedImportMap),
|
||||
stringifyImportMap(expected)
|
||||
);
|
||||
} else {
|
||||
assert_object_equals(v, expected);
|
||||
|
@ -75,6 +89,11 @@ function it(message, f) {
|
|||
// Currently document.write() is used to make everything synchronous, which
|
||||
// is just needed for running the existing Jest-based tests easily.
|
||||
function parseFromString(mapString, mapBaseURL) {
|
||||
// We can't test data: base URLs because <base> rejects data: URLs.
|
||||
if (new URL(mapBaseURL).protocol === 'data:') {
|
||||
throw Error('test helper does not support data: base URLs');
|
||||
}
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentDocument.write(`
|
||||
|
|
|
@ -153,7 +153,7 @@ function testStaticImport(importMapString, importMapBaseURL, specifier, expected
|
|||
const script = document.createElement("script");
|
||||
script.setAttribute("type", "module");
|
||||
script.setAttribute("src",
|
||||
"/import-maps/static-import.js?pipe=sub(none)&url=" +
|
||||
"static-import.js?pipe=sub(none)&url=" +
|
||||
encodeURIComponent("${specifier}"));
|
||||
script.addEventListener("load", handlers[Handler.ScriptLoadEvent]);
|
||||
script.addEventListener("error", handlers[Handler.ScriptErrorEvent]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue