@jsenv/test 1.2.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllable_child_process.mjs +73 -66
- package/dist/controllable_worker_thread.mjs +62 -49
- package/dist/importmap_node_loader.mjs +286 -185
- package/dist/js/execute_using_dynamic_import.js +397 -282
- package/dist/js/v8_coverage.js +91 -98
- package/dist/jsenv_test.js +2603 -1902
- package/dist/no_experimental_warnings.cjs +4 -1
- package/package.json +4 -4
|
@@ -4,129 +4,147 @@ import { pathToFileURL } from "node:url";
|
|
|
4
4
|
// duplicated from @jsenv/log to avoid the dependency
|
|
5
5
|
const createDetailedMessage = (message, details = {}) => {
|
|
6
6
|
let string = `${message}`;
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
Object.keys(details).forEach((key) => {
|
|
8
9
|
const value = details[key];
|
|
9
10
|
string += `
|
|
10
11
|
--- ${key} ---
|
|
11
|
-
${
|
|
12
|
-
|
|
12
|
+
${
|
|
13
|
+
Array.isArray(value)
|
|
14
|
+
? value.join(`
|
|
15
|
+
`)
|
|
16
|
+
: value
|
|
17
|
+
}`;
|
|
13
18
|
});
|
|
14
|
-
|
|
19
|
+
|
|
20
|
+
return string
|
|
15
21
|
};
|
|
16
22
|
|
|
17
|
-
const assertImportMap = value => {
|
|
23
|
+
const assertImportMap = (value) => {
|
|
18
24
|
if (value === null) {
|
|
19
|
-
throw new TypeError(`an importMap must be an object, got null`)
|
|
25
|
+
throw new TypeError(`an importMap must be an object, got null`)
|
|
20
26
|
}
|
|
27
|
+
|
|
21
28
|
const type = typeof value;
|
|
22
29
|
if (type !== "object") {
|
|
23
|
-
throw new TypeError(`an importMap must be an object, received ${value}`)
|
|
30
|
+
throw new TypeError(`an importMap must be an object, received ${value}`)
|
|
24
31
|
}
|
|
32
|
+
|
|
25
33
|
if (Array.isArray(value)) {
|
|
26
|
-
throw new TypeError(
|
|
34
|
+
throw new TypeError(
|
|
35
|
+
`an importMap must be an object, received array ${value}`,
|
|
36
|
+
)
|
|
27
37
|
}
|
|
28
38
|
};
|
|
29
39
|
|
|
30
|
-
const hasScheme = string => {
|
|
31
|
-
return /^[a-zA-Z]{2,}:/.test(string)
|
|
40
|
+
const hasScheme = (string) => {
|
|
41
|
+
return /^[a-zA-Z]{2,}:/.test(string)
|
|
32
42
|
};
|
|
33
43
|
|
|
34
|
-
const urlToScheme = urlString => {
|
|
44
|
+
const urlToScheme = (urlString) => {
|
|
35
45
|
const colonIndex = urlString.indexOf(":");
|
|
36
|
-
if (colonIndex === -1) return ""
|
|
37
|
-
return urlString.slice(0, colonIndex)
|
|
46
|
+
if (colonIndex === -1) return ""
|
|
47
|
+
return urlString.slice(0, colonIndex)
|
|
38
48
|
};
|
|
39
49
|
|
|
40
|
-
const urlToPathname = urlString => {
|
|
41
|
-
return ressourceToPathname(urlToRessource(urlString))
|
|
50
|
+
const urlToPathname = (urlString) => {
|
|
51
|
+
return ressourceToPathname(urlToRessource(urlString))
|
|
42
52
|
};
|
|
43
|
-
|
|
53
|
+
|
|
54
|
+
const urlToRessource = (urlString) => {
|
|
44
55
|
const scheme = urlToScheme(urlString);
|
|
56
|
+
|
|
45
57
|
if (scheme === "file") {
|
|
46
|
-
return urlString.slice("file://".length)
|
|
58
|
+
return urlString.slice("file://".length)
|
|
47
59
|
}
|
|
60
|
+
|
|
48
61
|
if (scheme === "https" || scheme === "http") {
|
|
49
62
|
// remove origin
|
|
50
63
|
const afterProtocol = urlString.slice(scheme.length + "://".length);
|
|
51
64
|
const pathnameSlashIndex = afterProtocol.indexOf("/", "://".length);
|
|
52
|
-
return afterProtocol.slice(pathnameSlashIndex)
|
|
65
|
+
return afterProtocol.slice(pathnameSlashIndex)
|
|
53
66
|
}
|
|
54
|
-
|
|
67
|
+
|
|
68
|
+
return urlString.slice(scheme.length + 1)
|
|
55
69
|
};
|
|
56
|
-
|
|
70
|
+
|
|
71
|
+
const ressourceToPathname = (ressource) => {
|
|
57
72
|
const searchSeparatorIndex = ressource.indexOf("?");
|
|
58
|
-
return searchSeparatorIndex === -1
|
|
73
|
+
return searchSeparatorIndex === -1
|
|
74
|
+
? ressource
|
|
75
|
+
: ressource.slice(0, searchSeparatorIndex)
|
|
59
76
|
};
|
|
60
77
|
|
|
61
|
-
const urlToOrigin = urlString => {
|
|
78
|
+
const urlToOrigin = (urlString) => {
|
|
62
79
|
const scheme = urlToScheme(urlString);
|
|
80
|
+
|
|
63
81
|
if (scheme === "file") {
|
|
64
|
-
return "file://"
|
|
82
|
+
return "file://"
|
|
65
83
|
}
|
|
84
|
+
|
|
66
85
|
if (scheme === "http" || scheme === "https") {
|
|
67
86
|
const secondProtocolSlashIndex = scheme.length + "://".length;
|
|
68
87
|
const pathnameSlashIndex = urlString.indexOf("/", secondProtocolSlashIndex);
|
|
69
|
-
|
|
70
|
-
|
|
88
|
+
|
|
89
|
+
if (pathnameSlashIndex === -1) return urlString
|
|
90
|
+
return urlString.slice(0, pathnameSlashIndex)
|
|
71
91
|
}
|
|
72
|
-
|
|
92
|
+
|
|
93
|
+
return urlString.slice(0, scheme.length + 1)
|
|
73
94
|
};
|
|
74
95
|
|
|
75
|
-
const pathnameToParentPathname = pathname => {
|
|
96
|
+
const pathnameToParentPathname = (pathname) => {
|
|
76
97
|
const slashLastIndex = pathname.lastIndexOf("/");
|
|
77
98
|
if (slashLastIndex === -1) {
|
|
78
|
-
return "/"
|
|
99
|
+
return "/"
|
|
79
100
|
}
|
|
80
|
-
|
|
101
|
+
|
|
102
|
+
return pathname.slice(0, slashLastIndex + 1)
|
|
81
103
|
};
|
|
82
104
|
|
|
83
105
|
// could be useful: https://url.spec.whatwg.org/#url-miscellaneous
|
|
84
106
|
|
|
107
|
+
|
|
85
108
|
const resolveUrl = (specifier, baseUrl) => {
|
|
86
109
|
if (baseUrl) {
|
|
87
110
|
if (typeof baseUrl !== "string") {
|
|
88
|
-
throw new TypeError(writeBaseUrlMustBeAString({
|
|
89
|
-
baseUrl,
|
|
90
|
-
specifier
|
|
91
|
-
}));
|
|
111
|
+
throw new TypeError(writeBaseUrlMustBeAString({ baseUrl, specifier }))
|
|
92
112
|
}
|
|
93
113
|
if (!hasScheme(baseUrl)) {
|
|
94
|
-
throw new Error(writeBaseUrlMustBeAbsolute({
|
|
95
|
-
baseUrl,
|
|
96
|
-
specifier
|
|
97
|
-
}));
|
|
114
|
+
throw new Error(writeBaseUrlMustBeAbsolute({ baseUrl, specifier }))
|
|
98
115
|
}
|
|
99
116
|
}
|
|
117
|
+
|
|
100
118
|
if (hasScheme(specifier)) {
|
|
101
|
-
return specifier
|
|
119
|
+
return specifier
|
|
102
120
|
}
|
|
121
|
+
|
|
103
122
|
if (!baseUrl) {
|
|
104
|
-
throw new Error(writeBaseUrlRequired({
|
|
105
|
-
baseUrl,
|
|
106
|
-
specifier
|
|
107
|
-
}));
|
|
123
|
+
throw new Error(writeBaseUrlRequired({ baseUrl, specifier }))
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
// scheme relative
|
|
111
127
|
if (specifier.slice(0, 2) === "//") {
|
|
112
|
-
return `${urlToScheme(baseUrl)}:${specifier}
|
|
128
|
+
return `${urlToScheme(baseUrl)}:${specifier}`
|
|
113
129
|
}
|
|
114
130
|
|
|
115
131
|
// origin relative
|
|
116
132
|
if (specifier[0] === "/") {
|
|
117
|
-
return `${urlToOrigin(baseUrl)}${specifier}
|
|
133
|
+
return `${urlToOrigin(baseUrl)}${specifier}`
|
|
118
134
|
}
|
|
135
|
+
|
|
119
136
|
const baseOrigin = urlToOrigin(baseUrl);
|
|
120
137
|
const basePathname = urlToPathname(baseUrl);
|
|
138
|
+
|
|
121
139
|
if (specifier === ".") {
|
|
122
140
|
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
123
|
-
return `${baseOrigin}${baseDirectoryPathname}
|
|
141
|
+
return `${baseOrigin}${baseDirectoryPathname}`
|
|
124
142
|
}
|
|
125
143
|
|
|
126
144
|
// pathname relative inside
|
|
127
145
|
if (specifier.slice(0, 2) === "./") {
|
|
128
146
|
const baseDirectoryPathname = pathnameToParentPathname(basePathname);
|
|
129
|
-
return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}
|
|
147
|
+
return `${baseOrigin}${baseDirectoryPathname}${specifier.slice(2)}`
|
|
130
148
|
}
|
|
131
149
|
|
|
132
150
|
// pathname relative outside
|
|
@@ -134,6 +152,7 @@ const resolveUrl = (specifier, baseUrl) => {
|
|
|
134
152
|
let unresolvedPathname = specifier;
|
|
135
153
|
const importerFolders = basePathname.split("/");
|
|
136
154
|
importerFolders.pop();
|
|
155
|
+
|
|
137
156
|
while (unresolvedPathname.slice(0, 3) === "../") {
|
|
138
157
|
unresolvedPathname = unresolvedPathname.slice(3);
|
|
139
158
|
// when there is no folder left to resolved
|
|
@@ -142,38 +161,44 @@ const resolveUrl = (specifier, baseUrl) => {
|
|
|
142
161
|
importerFolders.pop();
|
|
143
162
|
}
|
|
144
163
|
}
|
|
145
|
-
|
|
146
|
-
|
|
164
|
+
|
|
165
|
+
const resolvedPathname = `${importerFolders.join(
|
|
166
|
+
"/",
|
|
167
|
+
)}/${unresolvedPathname}`;
|
|
168
|
+
return `${baseOrigin}${resolvedPathname}`
|
|
147
169
|
}
|
|
148
170
|
|
|
149
171
|
// bare
|
|
150
172
|
if (basePathname === "") {
|
|
151
|
-
return `${baseOrigin}/${specifier}
|
|
173
|
+
return `${baseOrigin}/${specifier}`
|
|
152
174
|
}
|
|
153
175
|
if (basePathname[basePathname.length] === "/") {
|
|
154
|
-
return `${baseOrigin}${basePathname}${specifier}
|
|
176
|
+
return `${baseOrigin}${basePathname}${specifier}`
|
|
155
177
|
}
|
|
156
|
-
return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}
|
|
178
|
+
return `${baseOrigin}${pathnameToParentPathname(basePathname)}${specifier}`
|
|
157
179
|
};
|
|
180
|
+
|
|
158
181
|
const writeBaseUrlMustBeAString = ({
|
|
159
182
|
baseUrl,
|
|
160
|
-
specifier
|
|
183
|
+
specifier,
|
|
161
184
|
}) => `baseUrl must be a string.
|
|
162
185
|
--- base url ---
|
|
163
186
|
${baseUrl}
|
|
164
187
|
--- specifier ---
|
|
165
188
|
${specifier}`;
|
|
189
|
+
|
|
166
190
|
const writeBaseUrlMustBeAbsolute = ({
|
|
167
191
|
baseUrl,
|
|
168
|
-
specifier
|
|
192
|
+
specifier,
|
|
169
193
|
}) => `baseUrl must be absolute.
|
|
170
194
|
--- base url ---
|
|
171
195
|
${baseUrl}
|
|
172
196
|
--- specifier ---
|
|
173
197
|
${specifier}`;
|
|
198
|
+
|
|
174
199
|
const writeBaseUrlRequired = ({
|
|
175
200
|
baseUrl,
|
|
176
|
-
specifier
|
|
201
|
+
specifier,
|
|
177
202
|
}) => `baseUrl required to resolve relative specifier.
|
|
178
203
|
--- base url ---
|
|
179
204
|
${baseUrl}
|
|
@@ -182,91 +207,123 @@ ${specifier}`;
|
|
|
182
207
|
|
|
183
208
|
const tryUrlResolution = (string, url) => {
|
|
184
209
|
const result = resolveUrl(string, url);
|
|
185
|
-
return hasScheme(result) ? result : null
|
|
210
|
+
return hasScheme(result) ? result : null
|
|
186
211
|
};
|
|
187
212
|
|
|
188
213
|
const resolveSpecifier = (specifier, importer) => {
|
|
189
|
-
if (
|
|
190
|
-
|
|
214
|
+
if (
|
|
215
|
+
specifier === "." ||
|
|
216
|
+
specifier[0] === "/" ||
|
|
217
|
+
specifier.startsWith("./") ||
|
|
218
|
+
specifier.startsWith("../")
|
|
219
|
+
) {
|
|
220
|
+
return resolveUrl(specifier, importer)
|
|
191
221
|
}
|
|
222
|
+
|
|
192
223
|
if (hasScheme(specifier)) {
|
|
193
|
-
return specifier
|
|
224
|
+
return specifier
|
|
194
225
|
}
|
|
195
|
-
|
|
226
|
+
|
|
227
|
+
return null
|
|
196
228
|
};
|
|
197
229
|
|
|
198
230
|
const applyImportMap = ({
|
|
199
231
|
importMap,
|
|
200
232
|
specifier,
|
|
201
233
|
importer,
|
|
202
|
-
createBareSpecifierError = ({
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}));
|
|
234
|
+
createBareSpecifierError = ({ specifier, importer }) => {
|
|
235
|
+
return new Error(
|
|
236
|
+
createDetailedMessage(`Unmapped bare specifier.`, {
|
|
237
|
+
specifier,
|
|
238
|
+
importer,
|
|
239
|
+
}),
|
|
240
|
+
)
|
|
210
241
|
},
|
|
211
|
-
onImportMapping = () => {}
|
|
242
|
+
onImportMapping = () => {},
|
|
212
243
|
}) => {
|
|
213
244
|
assertImportMap(importMap);
|
|
214
245
|
if (typeof specifier !== "string") {
|
|
215
|
-
throw new TypeError(
|
|
216
|
-
specifier,
|
|
217
|
-
|
|
218
|
-
|
|
246
|
+
throw new TypeError(
|
|
247
|
+
createDetailedMessage("specifier must be a string.", {
|
|
248
|
+
specifier,
|
|
249
|
+
importer,
|
|
250
|
+
}),
|
|
251
|
+
)
|
|
219
252
|
}
|
|
220
253
|
if (importer) {
|
|
221
254
|
if (typeof importer !== "string") {
|
|
222
|
-
throw new TypeError(
|
|
223
|
-
importer,
|
|
224
|
-
|
|
225
|
-
|
|
255
|
+
throw new TypeError(
|
|
256
|
+
createDetailedMessage("importer must be a string.", {
|
|
257
|
+
importer,
|
|
258
|
+
specifier,
|
|
259
|
+
}),
|
|
260
|
+
)
|
|
226
261
|
}
|
|
227
262
|
if (!hasScheme(importer)) {
|
|
228
|
-
throw new Error(
|
|
229
|
-
importer
|
|
230
|
-
|
|
231
|
-
|
|
263
|
+
throw new Error(
|
|
264
|
+
createDetailedMessage(`importer must be an absolute url.`, {
|
|
265
|
+
importer,
|
|
266
|
+
specifier,
|
|
267
|
+
}),
|
|
268
|
+
)
|
|
232
269
|
}
|
|
233
270
|
}
|
|
271
|
+
|
|
234
272
|
const specifierUrl = resolveSpecifier(specifier, importer);
|
|
235
273
|
const specifierNormalized = specifierUrl || specifier;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
} = importMap;
|
|
274
|
+
|
|
275
|
+
const { scopes } = importMap;
|
|
239
276
|
if (scopes && importer) {
|
|
240
|
-
const scopeSpecifierMatching = Object.keys(scopes).find(
|
|
241
|
-
|
|
242
|
-
|
|
277
|
+
const scopeSpecifierMatching = Object.keys(scopes).find(
|
|
278
|
+
(scopeSpecifier) => {
|
|
279
|
+
return (
|
|
280
|
+
scopeSpecifier === importer ||
|
|
281
|
+
specifierIsPrefixOf(scopeSpecifier, importer)
|
|
282
|
+
)
|
|
283
|
+
},
|
|
284
|
+
);
|
|
243
285
|
if (scopeSpecifierMatching) {
|
|
244
286
|
const scopeMappings = scopes[scopeSpecifierMatching];
|
|
245
|
-
const mappingFromScopes = applyMappings(
|
|
287
|
+
const mappingFromScopes = applyMappings(
|
|
288
|
+
scopeMappings,
|
|
289
|
+
specifierNormalized,
|
|
290
|
+
scopeSpecifierMatching,
|
|
291
|
+
onImportMapping,
|
|
292
|
+
);
|
|
246
293
|
if (mappingFromScopes !== null) {
|
|
247
|
-
return mappingFromScopes
|
|
294
|
+
return mappingFromScopes
|
|
248
295
|
}
|
|
249
296
|
}
|
|
250
297
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
} = importMap;
|
|
298
|
+
|
|
299
|
+
const { imports } = importMap;
|
|
254
300
|
if (imports) {
|
|
255
|
-
const mappingFromImports = applyMappings(
|
|
301
|
+
const mappingFromImports = applyMappings(
|
|
302
|
+
imports,
|
|
303
|
+
specifierNormalized,
|
|
304
|
+
undefined,
|
|
305
|
+
onImportMapping,
|
|
306
|
+
);
|
|
256
307
|
if (mappingFromImports !== null) {
|
|
257
|
-
return mappingFromImports
|
|
308
|
+
return mappingFromImports
|
|
258
309
|
}
|
|
259
310
|
}
|
|
311
|
+
|
|
260
312
|
if (specifierUrl) {
|
|
261
|
-
return specifierUrl
|
|
313
|
+
return specifierUrl
|
|
262
314
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
importer
|
|
266
|
-
});
|
|
315
|
+
|
|
316
|
+
throw createBareSpecifierError({ specifier, importer })
|
|
267
317
|
};
|
|
268
|
-
|
|
318
|
+
|
|
319
|
+
const applyMappings = (
|
|
320
|
+
mappings,
|
|
321
|
+
specifierNormalized,
|
|
322
|
+
scope,
|
|
323
|
+
onImportMapping,
|
|
324
|
+
) => {
|
|
269
325
|
const specifierCandidates = Object.keys(mappings);
|
|
326
|
+
|
|
270
327
|
let i = 0;
|
|
271
328
|
while (i < specifierCandidates.length) {
|
|
272
329
|
const specifierCandidate = specifierCandidates[i];
|
|
@@ -278,140 +335,179 @@ const applyMappings = (mappings, specifierNormalized, scope, onImportMapping) =>
|
|
|
278
335
|
from: specifierCandidate,
|
|
279
336
|
to: address,
|
|
280
337
|
before: specifierNormalized,
|
|
281
|
-
after: address
|
|
338
|
+
after: address,
|
|
282
339
|
});
|
|
283
|
-
return address
|
|
340
|
+
return address
|
|
284
341
|
}
|
|
285
342
|
if (specifierIsPrefixOf(specifierCandidate, specifierNormalized)) {
|
|
286
343
|
const address = mappings[specifierCandidate];
|
|
287
|
-
const afterSpecifier = specifierNormalized.slice(
|
|
344
|
+
const afterSpecifier = specifierNormalized.slice(
|
|
345
|
+
specifierCandidate.length,
|
|
346
|
+
);
|
|
288
347
|
const addressFinal = tryUrlResolution(afterSpecifier, address);
|
|
289
348
|
onImportMapping({
|
|
290
349
|
scope,
|
|
291
350
|
from: specifierCandidate,
|
|
292
351
|
to: address,
|
|
293
352
|
before: specifierNormalized,
|
|
294
|
-
after: addressFinal
|
|
353
|
+
after: addressFinal,
|
|
295
354
|
});
|
|
296
|
-
return addressFinal
|
|
355
|
+
return addressFinal
|
|
297
356
|
}
|
|
298
357
|
}
|
|
299
|
-
|
|
358
|
+
|
|
359
|
+
return null
|
|
300
360
|
};
|
|
361
|
+
|
|
301
362
|
const specifierIsPrefixOf = (specifierHref, href) => {
|
|
302
|
-
return
|
|
363
|
+
return (
|
|
364
|
+
specifierHref[specifierHref.length - 1] === "/" &&
|
|
365
|
+
href.startsWith(specifierHref)
|
|
366
|
+
)
|
|
303
367
|
};
|
|
304
368
|
|
|
305
|
-
const sortImports = imports => {
|
|
369
|
+
const sortImports = (imports) => {
|
|
306
370
|
const mappingsSorted = {};
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
371
|
+
|
|
372
|
+
Object.keys(imports)
|
|
373
|
+
.sort(compareLengthOrLocaleCompare)
|
|
374
|
+
.forEach((name) => {
|
|
375
|
+
mappingsSorted[name] = imports[name];
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
return mappingsSorted
|
|
311
379
|
};
|
|
312
|
-
|
|
380
|
+
|
|
381
|
+
const sortScopes = (scopes) => {
|
|
313
382
|
const scopesSorted = {};
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
383
|
+
|
|
384
|
+
Object.keys(scopes)
|
|
385
|
+
.sort(compareLengthOrLocaleCompare)
|
|
386
|
+
.forEach((scopeSpecifier) => {
|
|
387
|
+
scopesSorted[scopeSpecifier] = sortImports(scopes[scopeSpecifier]);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
return scopesSorted
|
|
318
391
|
};
|
|
392
|
+
|
|
319
393
|
const compareLengthOrLocaleCompare = (a, b) => {
|
|
320
|
-
return b.length - a.length || a.localeCompare(b)
|
|
394
|
+
return b.length - a.length || a.localeCompare(b)
|
|
321
395
|
};
|
|
322
396
|
|
|
323
397
|
const normalizeImportMap = (importMap, baseUrl) => {
|
|
324
398
|
assertImportMap(importMap);
|
|
399
|
+
|
|
325
400
|
if (!isStringOrUrl(baseUrl)) {
|
|
326
|
-
throw new TypeError(formulateBaseUrlMustBeStringOrUrl({
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
imports,
|
|
332
|
-
scopes
|
|
333
|
-
} = importMap;
|
|
401
|
+
throw new TypeError(formulateBaseUrlMustBeStringOrUrl({ baseUrl }))
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const { imports, scopes } = importMap;
|
|
405
|
+
|
|
334
406
|
return {
|
|
335
407
|
imports: imports ? normalizeMappings(imports, baseUrl) : undefined,
|
|
336
|
-
scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined
|
|
337
|
-
}
|
|
408
|
+
scopes: scopes ? normalizeScopes(scopes, baseUrl) : undefined,
|
|
409
|
+
}
|
|
338
410
|
};
|
|
339
|
-
|
|
411
|
+
|
|
412
|
+
const isStringOrUrl = (value) => {
|
|
340
413
|
if (typeof value === "string") {
|
|
341
|
-
return true
|
|
414
|
+
return true
|
|
342
415
|
}
|
|
416
|
+
|
|
343
417
|
if (typeof URL === "function" && value instanceof URL) {
|
|
344
|
-
return true
|
|
418
|
+
return true
|
|
345
419
|
}
|
|
346
|
-
|
|
420
|
+
|
|
421
|
+
return false
|
|
347
422
|
};
|
|
423
|
+
|
|
348
424
|
const normalizeMappings = (mappings, baseUrl) => {
|
|
349
425
|
const mappingsNormalized = {};
|
|
350
|
-
|
|
426
|
+
|
|
427
|
+
Object.keys(mappings).forEach((specifier) => {
|
|
351
428
|
const address = mappings[specifier];
|
|
429
|
+
|
|
352
430
|
if (typeof address !== "string") {
|
|
353
|
-
console.warn(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
431
|
+
console.warn(
|
|
432
|
+
formulateAddressMustBeAString({
|
|
433
|
+
address,
|
|
434
|
+
specifier,
|
|
435
|
+
}),
|
|
436
|
+
);
|
|
437
|
+
return
|
|
358
438
|
}
|
|
439
|
+
|
|
359
440
|
const specifierResolved = resolveSpecifier(specifier, baseUrl) || specifier;
|
|
441
|
+
|
|
360
442
|
const addressUrl = tryUrlResolution(address, baseUrl);
|
|
361
443
|
if (addressUrl === null) {
|
|
362
|
-
console.warn(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
444
|
+
console.warn(
|
|
445
|
+
formulateAdressResolutionFailed({
|
|
446
|
+
address,
|
|
447
|
+
baseUrl,
|
|
448
|
+
specifier,
|
|
449
|
+
}),
|
|
450
|
+
);
|
|
451
|
+
return
|
|
368
452
|
}
|
|
453
|
+
|
|
369
454
|
if (specifier.endsWith("/") && !addressUrl.endsWith("/")) {
|
|
370
|
-
console.warn(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
455
|
+
console.warn(
|
|
456
|
+
formulateAddressUrlRequiresTrailingSlash({
|
|
457
|
+
addressUrl,
|
|
458
|
+
address,
|
|
459
|
+
specifier,
|
|
460
|
+
}),
|
|
461
|
+
);
|
|
462
|
+
return
|
|
376
463
|
}
|
|
377
464
|
mappingsNormalized[specifierResolved] = addressUrl;
|
|
378
465
|
});
|
|
379
|
-
|
|
466
|
+
|
|
467
|
+
return sortImports(mappingsNormalized)
|
|
380
468
|
};
|
|
469
|
+
|
|
381
470
|
const normalizeScopes = (scopes, baseUrl) => {
|
|
382
471
|
const scopesNormalized = {};
|
|
383
|
-
|
|
472
|
+
|
|
473
|
+
Object.keys(scopes).forEach((scopeSpecifier) => {
|
|
384
474
|
const scopeMappings = scopes[scopeSpecifier];
|
|
385
475
|
const scopeUrl = tryUrlResolution(scopeSpecifier, baseUrl);
|
|
386
476
|
if (scopeUrl === null) {
|
|
387
|
-
console.warn(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
477
|
+
console.warn(
|
|
478
|
+
formulateScopeResolutionFailed({
|
|
479
|
+
scope: scopeSpecifier,
|
|
480
|
+
baseUrl,
|
|
481
|
+
}),
|
|
482
|
+
);
|
|
483
|
+
return
|
|
392
484
|
}
|
|
393
485
|
const scopeValueNormalized = normalizeMappings(scopeMappings, baseUrl);
|
|
394
486
|
scopesNormalized[scopeUrl] = scopeValueNormalized;
|
|
395
487
|
});
|
|
396
|
-
|
|
488
|
+
|
|
489
|
+
return sortScopes(scopesNormalized)
|
|
397
490
|
};
|
|
491
|
+
|
|
398
492
|
const formulateBaseUrlMustBeStringOrUrl = ({
|
|
399
|
-
baseUrl
|
|
493
|
+
baseUrl,
|
|
400
494
|
}) => `baseUrl must be a string or an url.
|
|
401
495
|
--- base url ---
|
|
402
496
|
${baseUrl}`;
|
|
497
|
+
|
|
403
498
|
const formulateAddressMustBeAString = ({
|
|
404
499
|
specifier,
|
|
405
|
-
address
|
|
500
|
+
address,
|
|
406
501
|
}) => `Address must be a string.
|
|
407
502
|
--- address ---
|
|
408
503
|
${address}
|
|
409
504
|
--- specifier ---
|
|
410
505
|
${specifier}`;
|
|
506
|
+
|
|
411
507
|
const formulateAdressResolutionFailed = ({
|
|
412
508
|
address,
|
|
413
509
|
baseUrl,
|
|
414
|
-
specifier
|
|
510
|
+
specifier,
|
|
415
511
|
}) => `Address url resolution failed.
|
|
416
512
|
--- address ---
|
|
417
513
|
${address}
|
|
@@ -419,10 +515,11 @@ ${address}
|
|
|
419
515
|
${baseUrl}
|
|
420
516
|
--- specifier ---
|
|
421
517
|
${specifier}`;
|
|
518
|
+
|
|
422
519
|
const formulateAddressUrlRequiresTrailingSlash = ({
|
|
423
520
|
addressURL,
|
|
424
521
|
address,
|
|
425
|
-
specifier
|
|
522
|
+
specifier,
|
|
426
523
|
}) => `Address must end with /.
|
|
427
524
|
--- address url ---
|
|
428
525
|
${addressURL}
|
|
@@ -430,24 +527,26 @@ ${addressURL}
|
|
|
430
527
|
${address}
|
|
431
528
|
--- specifier ---
|
|
432
529
|
${specifier}`;
|
|
530
|
+
|
|
433
531
|
const formulateScopeResolutionFailed = ({
|
|
434
532
|
scope,
|
|
435
|
-
baseUrl
|
|
533
|
+
baseUrl,
|
|
436
534
|
}) => `Scope url resolution failed.
|
|
437
535
|
--- scope ---
|
|
438
536
|
${scope}
|
|
439
537
|
--- base url ---
|
|
440
538
|
${baseUrl}`;
|
|
441
539
|
|
|
442
|
-
const pathnameToExtension = pathname => {
|
|
540
|
+
const pathnameToExtension = (pathname) => {
|
|
443
541
|
const slashLastIndex = pathname.lastIndexOf("/");
|
|
444
542
|
if (slashLastIndex !== -1) {
|
|
445
543
|
pathname = pathname.slice(slashLastIndex + 1);
|
|
446
544
|
}
|
|
545
|
+
|
|
447
546
|
const dotLastIndex = pathname.lastIndexOf(".");
|
|
448
|
-
if (dotLastIndex === -1) return ""
|
|
547
|
+
if (dotLastIndex === -1) return ""
|
|
449
548
|
// if (dotLastIndex === pathname.length - 1) return ""
|
|
450
|
-
return pathname.slice(dotLastIndex)
|
|
549
|
+
return pathname.slice(dotLastIndex)
|
|
451
550
|
};
|
|
452
551
|
|
|
453
552
|
const resolveImport = ({
|
|
@@ -456,7 +555,7 @@ const resolveImport = ({
|
|
|
456
555
|
importMap,
|
|
457
556
|
defaultExtension = false,
|
|
458
557
|
createBareSpecifierError,
|
|
459
|
-
onImportMapping = () => {}
|
|
558
|
+
onImportMapping = () => {},
|
|
460
559
|
}) => {
|
|
461
560
|
let url;
|
|
462
561
|
if (importMap) {
|
|
@@ -465,48 +564,48 @@ const resolveImport = ({
|
|
|
465
564
|
specifier,
|
|
466
565
|
importer,
|
|
467
566
|
createBareSpecifierError,
|
|
468
|
-
onImportMapping
|
|
567
|
+
onImportMapping,
|
|
469
568
|
});
|
|
470
569
|
} else {
|
|
471
570
|
url = resolveUrl(specifier, importer);
|
|
472
571
|
}
|
|
572
|
+
|
|
473
573
|
if (defaultExtension) {
|
|
474
|
-
url = applyDefaultExtension({
|
|
475
|
-
url,
|
|
476
|
-
importer,
|
|
477
|
-
defaultExtension
|
|
478
|
-
});
|
|
574
|
+
url = applyDefaultExtension({ url, importer, defaultExtension });
|
|
479
575
|
}
|
|
480
|
-
|
|
576
|
+
|
|
577
|
+
return url
|
|
481
578
|
};
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
importer,
|
|
485
|
-
defaultExtension
|
|
486
|
-
}) => {
|
|
579
|
+
|
|
580
|
+
const applyDefaultExtension = ({ url, importer, defaultExtension }) => {
|
|
487
581
|
if (urlToPathname(url).endsWith("/")) {
|
|
488
|
-
return url
|
|
582
|
+
return url
|
|
489
583
|
}
|
|
584
|
+
|
|
490
585
|
if (typeof defaultExtension === "string") {
|
|
491
586
|
const extension = pathnameToExtension(url);
|
|
492
587
|
if (extension === "") {
|
|
493
|
-
return `${url}${defaultExtension}
|
|
588
|
+
return `${url}${defaultExtension}`
|
|
494
589
|
}
|
|
495
|
-
return url
|
|
590
|
+
return url
|
|
496
591
|
}
|
|
592
|
+
|
|
497
593
|
if (defaultExtension === true) {
|
|
498
594
|
const extension = pathnameToExtension(url);
|
|
499
595
|
if (extension === "" && importer) {
|
|
500
596
|
const importerPathname = urlToPathname(importer);
|
|
501
597
|
const importerExtension = pathnameToExtension(importerPathname);
|
|
502
|
-
return `${url}${importerExtension}
|
|
598
|
+
return `${url}${importerExtension}`
|
|
503
599
|
}
|
|
504
600
|
}
|
|
505
|
-
|
|
601
|
+
|
|
602
|
+
return url
|
|
506
603
|
};
|
|
507
604
|
|
|
508
605
|
let importMap;
|
|
606
|
+
|
|
509
607
|
const cwdUrl = `${String(pathToFileURL(process.cwd()))}/`;
|
|
608
|
+
|
|
510
609
|
if (process.env.IMPORT_MAP) {
|
|
511
610
|
importMap = JSON.parse(process.env.IMPORT_MAP);
|
|
512
611
|
} else if (process.env.IMPORT_MAP_PATH) {
|
|
@@ -518,8 +617,10 @@ if (process.env.IMPORT_MAP) {
|
|
|
518
617
|
const importmapFileContentAsString = readFileSync(importmapFileUrl, "utf8");
|
|
519
618
|
importMap = JSON.parse(importmapFileContentAsString);
|
|
520
619
|
}
|
|
620
|
+
|
|
521
621
|
const importMapBaseUrl = process.env.IMPORT_MAP_BASE_URL || cwdUrl;
|
|
522
622
|
importMap = normalizeImportMap(importMap, importMapBaseUrl);
|
|
623
|
+
|
|
523
624
|
const resolve = (specifier, context, nextResolve) => {
|
|
524
625
|
try {
|
|
525
626
|
let mapped;
|
|
@@ -531,12 +632,12 @@ const resolve = (specifier, context, nextResolve) => {
|
|
|
531
632
|
defaultExtension: ".js",
|
|
532
633
|
onImportMapping: () => {
|
|
533
634
|
mapped = true;
|
|
534
|
-
}
|
|
635
|
+
},
|
|
535
636
|
});
|
|
536
637
|
if (mapped) {
|
|
537
638
|
return {
|
|
538
639
|
shortCircuit: true,
|
|
539
|
-
url: resolved
|
|
640
|
+
url: resolved,
|
|
540
641
|
};
|
|
541
642
|
}
|
|
542
643
|
} catch (e) {
|