-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
assertImportMap.mjs
100 lines (86 loc) · 3.14 KB
/
assertImportMap.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// @ts-check
/**
* Asserts a value is a standard import map.
* @see https://wicg.github.io/import-maps/#parsing
* @param {any} value Supposed import map.
* @returns {asserts value is ImportMap} `void` for JavaScript and the assertion
* for TypeScript.
*/
export default function assertImportMap(value) {
try {
// Todo: Deeper validation of URL strings, etc.
if (typeof value !== "object" || !value) {
throw new TypeError("Import map must be an object.");
}
if ("imports" in value) {
if (typeof value.imports !== "object" || !value.imports) {
throw new TypeError("Import map property `imports` must be an object.");
}
for (const [importsKey, importsValue] of Object.entries(value.imports)) {
if (!importsKey.length) {
throw new TypeError(
`Import map property \`imports\` mustn’t contain an empty key.`,
);
}
if (typeof importsValue !== "string") {
throw new TypeError(
`Import map property \`imports\` property \`${importsKey}\` must be a string.`,
);
}
if (!importsValue.length) {
throw new TypeError(
`Import map property \`imports\` property \`${importsKey}\` must be a non empty string.`,
);
}
}
}
if ("scopes" in value) {
if (typeof value.scopes !== "object" || !value.scopes) {
throw new TypeError("Import map property `scopes` must be an object.");
}
for (const [scopesKey, scopesValue] of Object.entries(value.scopes)) {
if (!scopesKey.length) {
throw new TypeError(
`Import map property \`scopes\` mustn’t contain an empty key.`,
);
}
if (typeof scopesValue !== "object" || !scopesValue) {
throw new TypeError(
`Import map property \`scopes\` property \`${scopesKey}\` must be an object.`,
);
}
for (const [scopeKey, scopeValue] of Object.entries(scopesValue)) {
if (!scopeKey.length) {
throw new TypeError(
`Import map property \`scopes\` property \`${scopesKey}\` mustn’t contain an empty key.`,
);
}
if (typeof scopeValue !== "string") {
throw new TypeError(
`Import map property \`scopes\` property \`${scopesKey}\` property \`${scopeKey}\` must be a string.`,
);
}
if (!scopeValue.length) {
throw new TypeError(
`Import map property \`scopes\` property \`${scopesKey}\` property \`${scopeKey}\` must be a non empty string.`,
);
}
}
}
}
} catch (cause) {
throw new TypeError("Invalid import map.", { cause });
}
}
/**
* A standard import map.
* @see https://github.com/WICG/import-maps
* @typedef {object} ImportMap
* @prop {ImportMapSpecifierMap} [imports] Import specifier map.
* @prop {Record<string, ImportMapSpecifierMap>} [scopes] Ordered map of URLs
* to import specifier maps.
*/
/**
* Ordered map of import specifiers to absolute or relative URL addresses.
* @typedef {Record<string, string>} ImportMapSpecifierMap
*/