-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathresolver.js
79 lines (62 loc) · 2.7 KB
/
resolver.js
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
'use strict';
const assert = require('assert');
const { tryURLLikeSpecifierParse, tryURLParse, isSpecial } = require('./utils.js');
exports.resolve = (specifier, parsedImportMap, scriptURL) => {
const asURL = tryURLLikeSpecifierParse(specifier, scriptURL);
const normalizedSpecifier = asURL ? asURL.href : specifier;
const scriptURLString = scriptURL.href;
for (const [scopePrefix, scopeImports] of Object.entries(parsedImportMap.scopes)) {
if (scopePrefix === scriptURLString ||
(scopePrefix.endsWith('/') && scriptURLString.startsWith(scopePrefix))) {
const scopeImportsMatch = resolveImportsMatch(normalizedSpecifier, asURL, scopeImports);
if (scopeImportsMatch !== null) {
return scopeImportsMatch;
}
}
}
const topLevelImportsMatch = resolveImportsMatch(normalizedSpecifier, asURL, parsedImportMap.imports);
if (topLevelImportsMatch !== null) {
return topLevelImportsMatch;
}
// The specifier was able to be turned into a URL, but wasn't remapped into anything.
if (asURL) {
return asURL;
}
throw new TypeError(`Unmapped bare specifier "${specifier}"`);
};
function resolveImportsMatch(normalizedSpecifier, asURL, specifierMap) {
for (const [specifierKey, resolutionResult] of Object.entries(specifierMap)) {
// Exact-match case
if (specifierKey === normalizedSpecifier) {
if (resolutionResult === null) {
throw new TypeError(`Blocked by a null entry for "${specifierKey}"`);
}
assert(resolutionResult instanceof URL);
return resolutionResult;
}
// Package prefix-match case
if (specifierKey.endsWith('/') &&
normalizedSpecifier.startsWith(specifierKey) &&
(!asURL || isSpecial(asURL))) {
if (resolutionResult === null) {
throw new TypeError(`Blocked by a null entry for "${specifierKey}"`);
}
assert(resolutionResult instanceof URL);
const afterPrefix = normalizedSpecifier.substring(specifierKey.length);
// Enforced by parsing
assert(resolutionResult.href.endsWith('/'));
const url = tryURLParse(afterPrefix, resolutionResult);
if (url === null) {
throw new TypeError(`Failed to resolve the specifier "${normalizedSpecifier}" as its after-prefix portion ` +
`"${afterPrefix}" could not be URL-parsed relative to the URL prefix ` +
`"${resolutionResult.href}" mapped to by the prefix "${specifierKey}"`);
}
if (!url.href.startsWith(resolutionResult.href)) {
throw new TypeError(`The specifier "${normalizedSpecifier}" backtracks above its prefix "${specifierKey}"`);
}
assert(url instanceof URL);
return url;
}
}
return null;
}