-
-
Notifications
You must be signed in to change notification settings - Fork 274
/
common.js
182 lines (182 loc) · 7.23 KB
/
common.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*
* Copyright 2014-2019 Guy Bedford (http://guybedford.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
exports.hasSelf = typeof self !== 'undefined';
const envGlobal = exports.hasSelf ? self : global;
exports.global = envGlobal;
if (typeof location !== 'undefined') {
exports.baseUrl = location.href.split('#')[0].split('?')[0];
const lastSepIndex = exports.baseUrl.lastIndexOf('/');
if (lastSepIndex !== -1)
exports.baseUrl = exports.baseUrl.slice(0, lastSepIndex + 1);
}
const backslashRegEx = /\\/g;
function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
if (relUrl.indexOf('\\') !== -1)
relUrl = relUrl.replace(backslashRegEx, '/');
// protocol-relative
if (relUrl[0] === '/' && relUrl[1] === '/') {
return parentUrl.slice(0, parentUrl.indexOf(':') + 1) + relUrl;
}
// relative-url
else if (relUrl[0] === '.' && (relUrl[1] === '/' || relUrl[1] === '.' && (relUrl[2] === '/' || relUrl.length === 2 && (relUrl += '/')) ||
relUrl.length === 1 && (relUrl += '/')) ||
relUrl[0] === '/') {
const parentProtocol = parentUrl.slice(0, parentUrl.indexOf(':') + 1);
// Disabled, but these cases will give inconsistent results for deep backtracking
//if (parentUrl[parentProtocol.length] !== '/')
// throw new Error('Cannot resolve');
// read pathname from parent URL
// pathname taken to be part after leading "/"
let pathname;
if (parentUrl[parentProtocol.length + 1] === '/') {
// resolving to a :// so we need to read out the auth and host
if (parentProtocol !== 'file:') {
pathname = parentUrl.slice(parentProtocol.length + 2);
pathname = pathname.slice(pathname.indexOf('/') + 1);
}
else {
pathname = parentUrl.slice(8);
}
}
else {
// resolving to :/ so pathname is the /... part
pathname = parentUrl.slice(parentProtocol.length + 1);
}
if (relUrl[0] === '/')
return parentUrl.slice(0, parentUrl.length - pathname.length - 1) + relUrl;
// join together and split for removal of .. and . segments
// looping the string instead of anything fancy for perf reasons
// '../../../../../z' resolved to 'x/y' is just 'z'
const segmented = pathname.slice(0, pathname.lastIndexOf('/') + 1) + relUrl;
const output = [];
let segmentIndex = -1;
for (let i = 0; i < segmented.length; i++) {
// busy reading a segment - only terminate on '/'
if (segmentIndex !== -1) {
if (segmented[i] === '/') {
output.push(segmented.slice(segmentIndex, i + 1));
segmentIndex = -1;
}
}
// new segment - check if it is relative
else if (segmented[i] === '.') {
// ../ segment
if (segmented[i + 1] === '.' && (segmented[i + 2] === '/' || i + 2 === segmented.length)) {
output.pop();
i += 2;
}
// ./ segment
else if (segmented[i + 1] === '/' || i + 1 === segmented.length) {
i += 1;
}
else {
// the start of a new segment as below
segmentIndex = i;
}
}
// it is the start of a new segment
else {
segmentIndex = i;
}
}
// finish reading out the last segment
if (segmentIndex !== -1)
output.push(segmented.slice(segmentIndex));
return parentUrl.slice(0, parentUrl.length - pathname.length) + output.join('');
}
}
exports.resolveIfNotPlainOrUrl = resolveIfNotPlainOrUrl;
/*
* Import maps implementation
*
* To make lookups fast we pre-resolve the entire import map
* and then match based on backtracked hash lookups
*
*/
function resolveUrl(relUrl, parentUrl) {
return resolveIfNotPlainOrUrl(relUrl, parentUrl) ||
relUrl.indexOf(':') !== -1 && relUrl ||
resolveIfNotPlainOrUrl('./' + relUrl, parentUrl);
}
function resolvePackages(pkgs, baseUrl) {
var outPkgs = {};
for (var p in pkgs) {
var value = pkgs[p];
// TODO package fallback support
if (typeof value !== 'string')
continue;
outPkgs[resolveIfNotPlainOrUrl(p, baseUrl) || p] = resolveUrl(value, baseUrl);
}
return outPkgs;
}
function parseImportMap(json, baseUrl) {
const imports = resolvePackages(json.imports, baseUrl) || {};
const scopes = {};
if (json.scopes) {
for (let scopeName in json.scopes) {
const scope = json.scopes[scopeName];
let resolvedScopeName = resolveUrl(scopeName, baseUrl);
if (resolvedScopeName[resolvedScopeName.length - 1] !== '/')
resolvedScopeName += '/';
scopes[resolvedScopeName] = resolvePackages(scope, baseUrl) || {};
}
}
return { imports: imports, scopes: scopes };
}
exports.parseImportMap = parseImportMap;
function getMatch(path, matchObj) {
if (matchObj[path])
return path;
let sepIndex = path.length;
do {
const segment = path.slice(0, sepIndex + 1);
if (segment in matchObj)
return segment;
} while ((sepIndex = path.lastIndexOf('/', sepIndex - 1)) !== -1);
}
function applyPackages(id, packages) {
const pkgName = getMatch(id, packages);
if (pkgName) {
const pkg = packages[pkgName];
if (pkg === null)
return;
if (id.length > pkgName.length && pkg[pkg.length - 1] !== '/')
console.warn("Invalid package target " + pkg + " for '" + pkgName + "' should have a trailing '/'.");
const subpath = id.slice(pkgName.length);
return subpath ? resolveUrl(subpath, pkg) : pkg;
}
}
function resolveImportMap(id, parentUrl, importMap) {
const urlResolved = resolveIfNotPlainOrUrl(id, parentUrl);
if (urlResolved)
id = urlResolved;
const scopeName = getMatch(parentUrl, importMap.scopes);
if (scopeName) {
const scopePackages = importMap.scopes[scopeName];
const packageResolution = applyPackages(id, scopePackages);
if (packageResolution)
return packageResolution;
}
return applyPackages(id, importMap.imports) || urlResolved || throwBare(id, parentUrl);
}
exports.resolveImportMap = resolveImportMap;
function throwBare(id, parentUrl) {
throw new Error('Unable to resolve bare specifier "' + id + (parentUrl ? '" from ' + parentUrl : '"'));
}
exports.throwBare = throwBare;
//# sourceMappingURL=common.js.map