@jsenv/core 39.9.6 → 39.10.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/jsenv_core.js +177 -123
- package/package.json +10 -10
- package/src/build/build_specifier_manager.js +2 -1
- package/src/build/start_build_server.js +20 -12
- package/src/kitchen/url_graph/references.js +5 -0
- package/src/plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js +1 -1
- package/src/plugins/plugins.js +1 -1
- package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +8 -0
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +9 -1
- package/src/plugins/resolution_node_esm/node_esm_resolver.js +1 -1
- package/src/plugins/resolution_web/jsenv_plugin_web_resolution.js +1 -1
package/dist/jsenv_core.js
CHANGED
|
@@ -1485,6 +1485,14 @@ const isValidUrl$1 = (url) => {
|
|
|
1485
1485
|
}
|
|
1486
1486
|
};
|
|
1487
1487
|
|
|
1488
|
+
const asSpecifierWithoutSearch = (specifier) => {
|
|
1489
|
+
if (isValidUrl$1(specifier)) {
|
|
1490
|
+
return asUrlWithoutSearch(specifier);
|
|
1491
|
+
}
|
|
1492
|
+
const [beforeQuestion] = specifier.split("?");
|
|
1493
|
+
return beforeQuestion;
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1488
1496
|
// normalize url search params:
|
|
1489
1497
|
// Using URLSearchParams to alter the url search params
|
|
1490
1498
|
// can result into "file:///file.css?css_module"
|
|
@@ -6973,6 +6981,14 @@ const startServer = async ({
|
|
|
6973
6981
|
nodeResponse.end();
|
|
6974
6982
|
return;
|
|
6975
6983
|
}
|
|
6984
|
+
try {
|
|
6985
|
+
// eslint-disable-next-line no-new
|
|
6986
|
+
new URL(nodeRequest.url, "http://example.com/");
|
|
6987
|
+
} catch {
|
|
6988
|
+
nodeResponse.writeHead(400, "Request url is not supported");
|
|
6989
|
+
nodeResponse.end();
|
|
6990
|
+
return;
|
|
6991
|
+
}
|
|
6976
6992
|
|
|
6977
6993
|
const receiveRequestOperation = Abort.startOperation();
|
|
6978
6994
|
receiveRequestOperation.addAbortSource((abort) => {
|
|
@@ -8045,6 +8061,7 @@ const fetchFileSystem = async (
|
|
|
8045
8061
|
: "no-store",
|
|
8046
8062
|
canReadDirectory = false,
|
|
8047
8063
|
rootDirectoryUrl, // = `${pathToFileURL(process.cwd())}/`,
|
|
8064
|
+
ENOENTFallback = () => {},
|
|
8048
8065
|
} = {},
|
|
8049
8066
|
) => {
|
|
8050
8067
|
const urlString = asUrlString(filesystemUrl);
|
|
@@ -8102,100 +8119,109 @@ const fetchFileSystem = async (
|
|
|
8102
8119
|
};
|
|
8103
8120
|
}
|
|
8104
8121
|
|
|
8105
|
-
const
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8122
|
+
const serveFile = async (fileUrl) => {
|
|
8123
|
+
try {
|
|
8124
|
+
const [readStatTiming, fileStat] = timeFunction(
|
|
8125
|
+
"file service>read file stat",
|
|
8126
|
+
() => statSync(new URL(fileUrl)),
|
|
8127
|
+
);
|
|
8128
|
+
if (fileStat.isDirectory()) {
|
|
8129
|
+
if (canReadDirectory) {
|
|
8130
|
+
return serveDirectory(fileUrl, {
|
|
8131
|
+
headers,
|
|
8132
|
+
canReadDirectory,
|
|
8133
|
+
rootDirectoryUrl,
|
|
8134
|
+
});
|
|
8135
|
+
}
|
|
8136
|
+
return {
|
|
8137
|
+
status: 403,
|
|
8138
|
+
statusText: "not allowed to read directory",
|
|
8139
|
+
};
|
|
8140
|
+
}
|
|
8141
|
+
// not a file, give up
|
|
8142
|
+
if (!fileStat.isFile()) {
|
|
8143
|
+
return {
|
|
8144
|
+
status: 404,
|
|
8145
|
+
timing: readStatTiming,
|
|
8146
|
+
};
|
|
8147
|
+
}
|
|
8148
|
+
|
|
8149
|
+
const clientCacheResponse = await getClientCacheResponse({
|
|
8150
|
+
headers,
|
|
8151
|
+
etagEnabled,
|
|
8152
|
+
etagMemory,
|
|
8153
|
+
etagMemoryMaxSize,
|
|
8154
|
+
mtimeEnabled,
|
|
8155
|
+
fileStat,
|
|
8156
|
+
fileUrl,
|
|
8157
|
+
});
|
|
8158
|
+
|
|
8159
|
+
// send 304 (redirect response to client cache)
|
|
8160
|
+
// because the response body does not have to be transmitted
|
|
8161
|
+
if (clientCacheResponse.status === 304) {
|
|
8162
|
+
return composeTwoResponses(
|
|
8163
|
+
{
|
|
8164
|
+
timing: readStatTiming,
|
|
8165
|
+
headers: {
|
|
8166
|
+
...(cacheControl ? { "cache-control": cacheControl } : {}),
|
|
8167
|
+
},
|
|
8168
|
+
},
|
|
8169
|
+
clientCacheResponse,
|
|
8170
|
+
);
|
|
8171
|
+
}
|
|
8172
|
+
|
|
8173
|
+
let response;
|
|
8174
|
+
if (compressionEnabled && fileStat.size >= compressionSizeThreshold) {
|
|
8175
|
+
const compressedResponse = await getCompressedResponse({
|
|
8114
8176
|
headers,
|
|
8115
|
-
|
|
8116
|
-
|
|
8177
|
+
fileUrl,
|
|
8178
|
+
});
|
|
8179
|
+
if (compressedResponse) {
|
|
8180
|
+
response = compressedResponse;
|
|
8181
|
+
}
|
|
8182
|
+
}
|
|
8183
|
+
if (!response) {
|
|
8184
|
+
response = await getRawResponse({
|
|
8185
|
+
fileStat,
|
|
8186
|
+
fileUrl,
|
|
8117
8187
|
});
|
|
8118
8188
|
}
|
|
8119
|
-
return {
|
|
8120
|
-
status: 403,
|
|
8121
|
-
statusText: "not allowed to read directory",
|
|
8122
|
-
};
|
|
8123
|
-
}
|
|
8124
|
-
// not a file, give up
|
|
8125
|
-
if (!sourceStat.isFile()) {
|
|
8126
|
-
return {
|
|
8127
|
-
status: 404,
|
|
8128
|
-
timing: readStatTiming,
|
|
8129
|
-
};
|
|
8130
|
-
}
|
|
8131
|
-
|
|
8132
|
-
const clientCacheResponse = await getClientCacheResponse({
|
|
8133
|
-
headers,
|
|
8134
|
-
etagEnabled,
|
|
8135
|
-
etagMemory,
|
|
8136
|
-
etagMemoryMaxSize,
|
|
8137
|
-
mtimeEnabled,
|
|
8138
|
-
sourceStat,
|
|
8139
|
-
sourceUrl,
|
|
8140
|
-
});
|
|
8141
8189
|
|
|
8142
|
-
|
|
8143
|
-
// because the response body does not have to be transmitted
|
|
8144
|
-
if (clientCacheResponse.status === 304) {
|
|
8145
|
-
return composeTwoResponses(
|
|
8190
|
+
const intermediateResponse = composeTwoResponses(
|
|
8146
8191
|
{
|
|
8147
8192
|
timing: readStatTiming,
|
|
8148
8193
|
headers: {
|
|
8149
8194
|
...(cacheControl ? { "cache-control": cacheControl } : {}),
|
|
8195
|
+
// even if client cache is disabled, server can still
|
|
8196
|
+
// send his own cache control but client should just ignore it
|
|
8197
|
+
// and keep sending cache-control: 'no-store'
|
|
8198
|
+
// if not, uncomment the line below to preserve client
|
|
8199
|
+
// desire to ignore cache
|
|
8200
|
+
// ...(headers["cache-control"] === "no-store" ? { "cache-control": "no-store" } : {}),
|
|
8150
8201
|
},
|
|
8151
8202
|
},
|
|
8152
|
-
|
|
8203
|
+
response,
|
|
8153
8204
|
);
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
});
|
|
8162
|
-
if (compressedResponse) {
|
|
8163
|
-
response = compressedResponse;
|
|
8205
|
+
return composeTwoResponses(intermediateResponse, clientCacheResponse);
|
|
8206
|
+
} catch (e) {
|
|
8207
|
+
if (e.code === "ENOENT") {
|
|
8208
|
+
const fallbackFileUrl = ENOENTFallback();
|
|
8209
|
+
if (fallbackFileUrl) {
|
|
8210
|
+
return serveFile(fallbackFileUrl);
|
|
8211
|
+
}
|
|
8164
8212
|
}
|
|
8213
|
+
return composeTwoResponses(
|
|
8214
|
+
{
|
|
8215
|
+
headers: {
|
|
8216
|
+
...(cacheControl ? { "cache-control": cacheControl } : {}),
|
|
8217
|
+
},
|
|
8218
|
+
},
|
|
8219
|
+
convertFileSystemErrorToResponseProperties(e) || {},
|
|
8220
|
+
);
|
|
8165
8221
|
}
|
|
8166
|
-
|
|
8167
|
-
response = await getRawResponse({
|
|
8168
|
-
sourceStat,
|
|
8169
|
-
sourceUrl,
|
|
8170
|
-
});
|
|
8171
|
-
}
|
|
8222
|
+
};
|
|
8172
8223
|
|
|
8173
|
-
|
|
8174
|
-
{
|
|
8175
|
-
timing: readStatTiming,
|
|
8176
|
-
headers: {
|
|
8177
|
-
...(cacheControl ? { "cache-control": cacheControl } : {}),
|
|
8178
|
-
// even if client cache is disabled, server can still
|
|
8179
|
-
// send his own cache control but client should just ignore it
|
|
8180
|
-
// and keep sending cache-control: 'no-store'
|
|
8181
|
-
// if not, uncomment the line below to preserve client
|
|
8182
|
-
// desire to ignore cache
|
|
8183
|
-
// ...(headers["cache-control"] === "no-store" ? { "cache-control": "no-store" } : {}),
|
|
8184
|
-
},
|
|
8185
|
-
},
|
|
8186
|
-
response,
|
|
8187
|
-
);
|
|
8188
|
-
return composeTwoResponses(intermediateResponse, clientCacheResponse);
|
|
8189
|
-
} catch (e) {
|
|
8190
|
-
return composeTwoResponses(
|
|
8191
|
-
{
|
|
8192
|
-
headers: {
|
|
8193
|
-
...(cacheControl ? { "cache-control": cacheControl } : {}),
|
|
8194
|
-
},
|
|
8195
|
-
},
|
|
8196
|
-
convertFileSystemErrorToResponseProperties(e) || {},
|
|
8197
|
-
);
|
|
8198
|
-
}
|
|
8224
|
+
return serveFile(`file://${new URL(urlString).pathname}`);
|
|
8199
8225
|
};
|
|
8200
8226
|
|
|
8201
8227
|
const create500Response = (message) => {
|
|
@@ -8215,8 +8241,8 @@ const getClientCacheResponse = async ({
|
|
|
8215
8241
|
etagMemory,
|
|
8216
8242
|
etagMemoryMaxSize,
|
|
8217
8243
|
mtimeEnabled,
|
|
8218
|
-
|
|
8219
|
-
|
|
8244
|
+
fileStat,
|
|
8245
|
+
fileUrl,
|
|
8220
8246
|
}) => {
|
|
8221
8247
|
// here you might be tempted to add || headers["cache-control"] === "no-cache"
|
|
8222
8248
|
// but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
|
|
@@ -8235,15 +8261,15 @@ const getClientCacheResponse = async ({
|
|
|
8235
8261
|
headers,
|
|
8236
8262
|
etagMemory,
|
|
8237
8263
|
etagMemoryMaxSize,
|
|
8238
|
-
|
|
8239
|
-
|
|
8264
|
+
fileStat,
|
|
8265
|
+
fileUrl,
|
|
8240
8266
|
});
|
|
8241
8267
|
}
|
|
8242
8268
|
|
|
8243
8269
|
if (mtimeEnabled) {
|
|
8244
8270
|
return getMtimeResponse({
|
|
8245
8271
|
headers,
|
|
8246
|
-
|
|
8272
|
+
fileStat,
|
|
8247
8273
|
});
|
|
8248
8274
|
}
|
|
8249
8275
|
|
|
@@ -8254,8 +8280,8 @@ const getEtagResponse = async ({
|
|
|
8254
8280
|
headers,
|
|
8255
8281
|
etagMemory,
|
|
8256
8282
|
etagMemoryMaxSize,
|
|
8257
|
-
|
|
8258
|
-
|
|
8283
|
+
fileUrl,
|
|
8284
|
+
fileStat,
|
|
8259
8285
|
}) => {
|
|
8260
8286
|
const [computeEtagTiming, fileContentEtag] = await timeFunction(
|
|
8261
8287
|
"file service>generate file etag",
|
|
@@ -8263,8 +8289,8 @@ const getEtagResponse = async ({
|
|
|
8263
8289
|
computeEtag({
|
|
8264
8290
|
etagMemory,
|
|
8265
8291
|
etagMemoryMaxSize,
|
|
8266
|
-
|
|
8267
|
-
|
|
8292
|
+
fileUrl,
|
|
8293
|
+
fileStat,
|
|
8268
8294
|
}),
|
|
8269
8295
|
);
|
|
8270
8296
|
|
|
@@ -8292,20 +8318,20 @@ const ETAG_MEMORY_MAP = new Map();
|
|
|
8292
8318
|
const computeEtag = async ({
|
|
8293
8319
|
etagMemory,
|
|
8294
8320
|
etagMemoryMaxSize,
|
|
8295
|
-
|
|
8296
|
-
|
|
8321
|
+
fileUrl,
|
|
8322
|
+
fileStat,
|
|
8297
8323
|
}) => {
|
|
8298
8324
|
if (etagMemory) {
|
|
8299
|
-
const etagMemoryEntry = ETAG_MEMORY_MAP.get(
|
|
8325
|
+
const etagMemoryEntry = ETAG_MEMORY_MAP.get(fileUrl);
|
|
8300
8326
|
if (
|
|
8301
8327
|
etagMemoryEntry &&
|
|
8302
|
-
fileStatAreTheSame(etagMemoryEntry.
|
|
8328
|
+
fileStatAreTheSame(etagMemoryEntry.fileStat, fileStat)
|
|
8303
8329
|
) {
|
|
8304
8330
|
return etagMemoryEntry.eTag;
|
|
8305
8331
|
}
|
|
8306
8332
|
}
|
|
8307
8333
|
const fileContentAsBuffer = await new Promise((resolve, reject) => {
|
|
8308
|
-
readFile(new URL(
|
|
8334
|
+
readFile(new URL(fileUrl), (error, buffer) => {
|
|
8309
8335
|
if (error) {
|
|
8310
8336
|
reject(error);
|
|
8311
8337
|
} else {
|
|
@@ -8319,7 +8345,7 @@ const computeEtag = async ({
|
|
|
8319
8345
|
const firstKey = Array.from(ETAG_MEMORY_MAP.keys())[0];
|
|
8320
8346
|
ETAG_MEMORY_MAP.delete(firstKey);
|
|
8321
8347
|
}
|
|
8322
|
-
ETAG_MEMORY_MAP.set(
|
|
8348
|
+
ETAG_MEMORY_MAP.set(fileUrl, { fileStat, eTag });
|
|
8323
8349
|
}
|
|
8324
8350
|
return eTag;
|
|
8325
8351
|
};
|
|
@@ -8344,7 +8370,7 @@ const fileStatKeysToCompare = [
|
|
|
8344
8370
|
"blksize",
|
|
8345
8371
|
];
|
|
8346
8372
|
|
|
8347
|
-
const getMtimeResponse = async ({ headers,
|
|
8373
|
+
const getMtimeResponse = async ({ headers, fileStat }) => {
|
|
8348
8374
|
if ("if-modified-since" in headers) {
|
|
8349
8375
|
let cachedModificationDate;
|
|
8350
8376
|
try {
|
|
@@ -8356,7 +8382,7 @@ const getMtimeResponse = async ({ headers, sourceStat }) => {
|
|
|
8356
8382
|
};
|
|
8357
8383
|
}
|
|
8358
8384
|
|
|
8359
|
-
const actualModificationDate = dateToSecondsPrecision(
|
|
8385
|
+
const actualModificationDate = dateToSecondsPrecision(fileStat.mtime);
|
|
8360
8386
|
if (Number(cachedModificationDate) >= Number(actualModificationDate)) {
|
|
8361
8387
|
return {
|
|
8362
8388
|
status: 304,
|
|
@@ -8367,12 +8393,12 @@ const getMtimeResponse = async ({ headers, sourceStat }) => {
|
|
|
8367
8393
|
return {
|
|
8368
8394
|
status: 200,
|
|
8369
8395
|
headers: {
|
|
8370
|
-
"last-modified": dateToUTCString(
|
|
8396
|
+
"last-modified": dateToUTCString(fileStat.mtime),
|
|
8371
8397
|
},
|
|
8372
8398
|
};
|
|
8373
8399
|
};
|
|
8374
8400
|
|
|
8375
|
-
const getCompressedResponse = async ({
|
|
8401
|
+
const getCompressedResponse = async ({ fileUrl, headers }) => {
|
|
8376
8402
|
const acceptedCompressionFormat = pickContentEncoding(
|
|
8377
8403
|
{ headers },
|
|
8378
8404
|
Object.keys(availableCompressionFormats),
|
|
@@ -8381,7 +8407,7 @@ const getCompressedResponse = async ({ sourceUrl, headers }) => {
|
|
|
8381
8407
|
return null;
|
|
8382
8408
|
}
|
|
8383
8409
|
|
|
8384
|
-
const fileReadableStream = fileUrlToReadableStream(
|
|
8410
|
+
const fileReadableStream = fileUrlToReadableStream(fileUrl);
|
|
8385
8411
|
const body =
|
|
8386
8412
|
await availableCompressionFormats[acceptedCompressionFormat](
|
|
8387
8413
|
fileReadableStream,
|
|
@@ -8390,7 +8416,7 @@ const getCompressedResponse = async ({ sourceUrl, headers }) => {
|
|
|
8390
8416
|
return {
|
|
8391
8417
|
status: 200,
|
|
8392
8418
|
headers: {
|
|
8393
|
-
"content-type": CONTENT_TYPE.fromUrlExtension(
|
|
8419
|
+
"content-type": CONTENT_TYPE.fromUrlExtension(fileUrl),
|
|
8394
8420
|
"content-encoding": acceptedCompressionFormat,
|
|
8395
8421
|
"vary": "accept-encoding",
|
|
8396
8422
|
},
|
|
@@ -8420,14 +8446,14 @@ const availableCompressionFormats = {
|
|
|
8420
8446
|
},
|
|
8421
8447
|
};
|
|
8422
8448
|
|
|
8423
|
-
const getRawResponse = async ({
|
|
8449
|
+
const getRawResponse = async ({ fileUrl, fileStat }) => {
|
|
8424
8450
|
return {
|
|
8425
8451
|
status: 200,
|
|
8426
8452
|
headers: {
|
|
8427
|
-
"content-type": CONTENT_TYPE.fromUrlExtension(
|
|
8428
|
-
"content-length":
|
|
8453
|
+
"content-type": CONTENT_TYPE.fromUrlExtension(fileUrl),
|
|
8454
|
+
"content-length": fileStat.size,
|
|
8429
8455
|
},
|
|
8430
|
-
body: fileUrlToReadableStream(
|
|
8456
|
+
body: fileUrlToReadableStream(fileUrl),
|
|
8431
8457
|
};
|
|
8432
8458
|
};
|
|
8433
8459
|
|
|
@@ -13085,6 +13111,7 @@ const createReference = ({
|
|
|
13085
13111
|
);
|
|
13086
13112
|
}
|
|
13087
13113
|
}
|
|
13114
|
+
|
|
13088
13115
|
const reference = {
|
|
13089
13116
|
id: ++referenceId,
|
|
13090
13117
|
ownerUrlInfo,
|
|
@@ -13107,6 +13134,9 @@ const createReference = ({
|
|
|
13107
13134
|
integrity,
|
|
13108
13135
|
crossorigin,
|
|
13109
13136
|
specifier,
|
|
13137
|
+
get specifierPathname() {
|
|
13138
|
+
return asSpecifierWithoutSearch(reference.specifier);
|
|
13139
|
+
},
|
|
13110
13140
|
specifierStart,
|
|
13111
13141
|
specifierEnd,
|
|
13112
13142
|
specifierLine,
|
|
@@ -15602,7 +15632,7 @@ const jsenvPluginDirectoryReferenceEffect = (
|
|
|
15602
15632
|
reference.filenameHint = `${
|
|
15603
15633
|
reference.ownerUrlInfo.filenameHint
|
|
15604
15634
|
}${urlToFilename$1(reference.url)}/`;
|
|
15605
|
-
} else if (reference.
|
|
15635
|
+
} else if (reference.specifierPathname.endsWith("./")) ; else {
|
|
15606
15636
|
reference.filenameHint = `${urlToFilename$1(reference.url)}/`;
|
|
15607
15637
|
}
|
|
15608
15638
|
let actionForDirectory;
|
|
@@ -18890,7 +18920,7 @@ const createNodeEsmResolver = ({
|
|
|
18890
18920
|
return reference.specifier;
|
|
18891
18921
|
}
|
|
18892
18922
|
const { ownerUrlInfo } = reference;
|
|
18893
|
-
if (reference.
|
|
18923
|
+
if (reference.specifierPathname[0] === "/") {
|
|
18894
18924
|
const url = new URL(
|
|
18895
18925
|
reference.specifier.slice(1),
|
|
18896
18926
|
ownerUrlInfo.context.rootDirectoryUrl,
|
|
@@ -19092,7 +19122,7 @@ const jsenvPluginWebResolution = () => {
|
|
|
19092
19122
|
appliesDuring: "*",
|
|
19093
19123
|
resolveReference: (reference) => {
|
|
19094
19124
|
const { ownerUrlInfo } = reference;
|
|
19095
|
-
if (reference.
|
|
19125
|
+
if (reference.specifierPathname[0] === "/") {
|
|
19096
19126
|
const url = new URL(
|
|
19097
19127
|
reference.specifier.slice(1),
|
|
19098
19128
|
ownerUrlInfo.context.rootDirectoryUrl,
|
|
@@ -19168,6 +19198,14 @@ const jsenvPluginFsRedirection = ({
|
|
|
19168
19198
|
if (reference.subtype === "new_url_second_arg") {
|
|
19169
19199
|
return `ignore:${reference.url}`;
|
|
19170
19200
|
}
|
|
19201
|
+
if (reference.specifierPathname.endsWith("/...")) {
|
|
19202
|
+
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
|
|
19203
|
+
const directoryUrl = new URL(
|
|
19204
|
+
reference.specifierPathname.replace("/...", "/").slice(1),
|
|
19205
|
+
rootDirectoryUrl,
|
|
19206
|
+
).href;
|
|
19207
|
+
return directoryUrl;
|
|
19208
|
+
}
|
|
19171
19209
|
// ignore "./" on new URL("./")
|
|
19172
19210
|
// if (
|
|
19173
19211
|
// reference.subtype === "new_url_first_arg" &&
|
|
@@ -19319,6 +19357,14 @@ const jsenvPluginProtocolFile = ({
|
|
|
19319
19357
|
if (!generatedUrl.startsWith("file:")) {
|
|
19320
19358
|
return null;
|
|
19321
19359
|
}
|
|
19360
|
+
if (reference.original) {
|
|
19361
|
+
const originalSpecifierPathname =
|
|
19362
|
+
reference.original.specifierPathname;
|
|
19363
|
+
|
|
19364
|
+
if (originalSpecifierPathname.endsWith("/...")) {
|
|
19365
|
+
return originalSpecifierPathname;
|
|
19366
|
+
}
|
|
19367
|
+
}
|
|
19322
19368
|
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
|
|
19323
19369
|
if (urlIsInsideOf(generatedUrl, rootDirectoryUrl)) {
|
|
19324
19370
|
const result = `/${urlToRelativeUrl(generatedUrl, rootDirectoryUrl)}`;
|
|
@@ -19475,7 +19521,7 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
19475
19521
|
let i = 0;
|
|
19476
19522
|
while (i < parts.length) {
|
|
19477
19523
|
const part = parts[i];
|
|
19478
|
-
const href = i === 0 ? "
|
|
19524
|
+
const href = i === 0 ? "/..." : `/${parts.slice(1, i + 1).join("/")}/`;
|
|
19479
19525
|
const text = part;
|
|
19480
19526
|
const isLastPart = i === parts.length - 1;
|
|
19481
19527
|
if (isLastPart) {
|
|
@@ -21133,7 +21179,7 @@ const getCorePlugins = ({
|
|
|
21133
21179
|
appliesDuring: "*",
|
|
21134
21180
|
resolveReference: (reference) => {
|
|
21135
21181
|
const { ownerUrlInfo } = reference;
|
|
21136
|
-
if (reference.
|
|
21182
|
+
if (reference.specifierPathname === "/") {
|
|
21137
21183
|
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
21138
21184
|
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
21139
21185
|
return url;
|
|
@@ -21586,7 +21632,7 @@ const createBuildSpecifierManager = ({
|
|
|
21586
21632
|
const url = new URL(reference.specifier, ownerRawUrl).href;
|
|
21587
21633
|
return url;
|
|
21588
21634
|
}
|
|
21589
|
-
if (reference.
|
|
21635
|
+
if (reference.specifierPathname[0] === "/") {
|
|
21590
21636
|
const url = new URL(reference.specifier.slice(1), sourceDirectoryUrl)
|
|
21591
21637
|
.href;
|
|
21592
21638
|
return url;
|
|
@@ -21711,6 +21757,7 @@ const createBuildSpecifierManager = ({
|
|
|
21711
21757
|
type: reference.type,
|
|
21712
21758
|
expectedType: reference.expectedType,
|
|
21713
21759
|
specifier: reference.specifier,
|
|
21760
|
+
specifierPathname: reference.specifierPathname,
|
|
21714
21761
|
specifierLine: reference.specifierLine,
|
|
21715
21762
|
specifierColumn: reference.specifierColumn,
|
|
21716
21763
|
specifierStart: reference.specifierStart,
|
|
@@ -24484,19 +24531,26 @@ const createBuildFilesService = ({ buildDirectoryUrl, buildMainFilePath }) => {
|
|
|
24484
24531
|
resource: `/${buildMainFilePath}`,
|
|
24485
24532
|
};
|
|
24486
24533
|
}
|
|
24487
|
-
|
|
24488
|
-
|
|
24489
|
-
|
|
24490
|
-
|
|
24491
|
-
|
|
24492
|
-
|
|
24493
|
-
|
|
24494
|
-
|
|
24495
|
-
|
|
24496
|
-
|
|
24497
|
-
|
|
24534
|
+
const urlObject = new URL(request.resource.slice(1), buildDirectoryUrl);
|
|
24535
|
+
return fetchFileSystem(urlObject, {
|
|
24536
|
+
headers: request.headers,
|
|
24537
|
+
cacheControl: urlIsVersioned
|
|
24538
|
+
? `private,max-age=${SECONDS_IN_30_DAYS},immutable`
|
|
24539
|
+
: "private,max-age=0,must-revalidate",
|
|
24540
|
+
etagEnabled: true,
|
|
24541
|
+
compressionEnabled: !request.pathname.endsWith(".mp4"),
|
|
24542
|
+
rootDirectoryUrl: buildDirectoryUrl,
|
|
24543
|
+
canReadDirectory: true,
|
|
24544
|
+
ENOENTFallback: () => {
|
|
24545
|
+
if (
|
|
24546
|
+
!urlToExtension$1(urlObject) &&
|
|
24547
|
+
!urlToPathname$1(urlObject).endsWith("/")
|
|
24548
|
+
) {
|
|
24549
|
+
return new URL(buildMainFilePath, buildDirectoryUrl);
|
|
24550
|
+
}
|
|
24551
|
+
return null;
|
|
24498
24552
|
},
|
|
24499
|
-
);
|
|
24553
|
+
});
|
|
24500
24554
|
};
|
|
24501
24555
|
};
|
|
24502
24556
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "39.
|
|
3
|
+
"version": "39.10.0",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -69,22 +69,22 @@
|
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
71
71
|
"@jsenv/abort": "4.3.0",
|
|
72
|
-
"@jsenv/ast": "6.4.
|
|
73
|
-
"@jsenv/filesystem": "4.13.
|
|
72
|
+
"@jsenv/ast": "6.4.4",
|
|
73
|
+
"@jsenv/filesystem": "4.13.2",
|
|
74
74
|
"@jsenv/humanize": "1.2.8",
|
|
75
75
|
"@jsenv/importmap": "1.2.1",
|
|
76
76
|
"@jsenv/integrity": "0.0.2",
|
|
77
|
-
"@jsenv/js-module-fallback": "1.3.
|
|
77
|
+
"@jsenv/js-module-fallback": "1.3.56",
|
|
78
78
|
"@jsenv/node-esm-resolution": "1.0.6",
|
|
79
|
-
"@jsenv/plugin-bundling": "2.7.
|
|
79
|
+
"@jsenv/plugin-bundling": "2.7.24",
|
|
80
80
|
"@jsenv/plugin-minification": "1.5.13",
|
|
81
|
-
"@jsenv/plugin-supervisor": "1.6.
|
|
82
|
-
"@jsenv/plugin-transpilation": "1.4.
|
|
81
|
+
"@jsenv/plugin-supervisor": "1.6.3",
|
|
82
|
+
"@jsenv/plugin-transpilation": "1.4.92",
|
|
83
83
|
"@jsenv/runtime-compat": "1.3.1",
|
|
84
|
-
"@jsenv/server": "15.
|
|
85
|
-
"@jsenv/sourcemap": "1.2.
|
|
84
|
+
"@jsenv/server": "15.4.0",
|
|
85
|
+
"@jsenv/sourcemap": "1.2.30",
|
|
86
86
|
"@jsenv/url-meta": "8.5.2",
|
|
87
|
-
"@jsenv/urls": "2.
|
|
87
|
+
"@jsenv/urls": "2.6.0",
|
|
88
88
|
"@jsenv/utils": "2.1.2",
|
|
89
89
|
"string-width": "7.2.0"
|
|
90
90
|
},
|
|
@@ -170,7 +170,7 @@ export const createBuildSpecifierManager = ({
|
|
|
170
170
|
const url = new URL(reference.specifier, ownerRawUrl).href;
|
|
171
171
|
return url;
|
|
172
172
|
}
|
|
173
|
-
if (reference.
|
|
173
|
+
if (reference.specifierPathname[0] === "/") {
|
|
174
174
|
const url = new URL(reference.specifier.slice(1), sourceDirectoryUrl)
|
|
175
175
|
.href;
|
|
176
176
|
return url;
|
|
@@ -295,6 +295,7 @@ export const createBuildSpecifierManager = ({
|
|
|
295
295
|
type: reference.type,
|
|
296
296
|
expectedType: reference.expectedType,
|
|
297
297
|
specifier: reference.specifier,
|
|
298
|
+
specifierPathname: reference.specifierPathname,
|
|
298
299
|
specifierLine: reference.specifierLine,
|
|
299
300
|
specifierColumn: reference.specifierColumn,
|
|
300
301
|
specifierStart: reference.specifierStart,
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
jsenvServiceErrorHandler,
|
|
24
24
|
startServer,
|
|
25
25
|
} from "@jsenv/server";
|
|
26
|
+
import { urlToExtension, urlToPathname } from "@jsenv/urls";
|
|
26
27
|
import { existsSync } from "node:fs";
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -168,19 +169,26 @@ const createBuildFilesService = ({ buildDirectoryUrl, buildMainFilePath }) => {
|
|
|
168
169
|
resource: `/${buildMainFilePath}`,
|
|
169
170
|
};
|
|
170
171
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
const urlObject = new URL(request.resource.slice(1), buildDirectoryUrl);
|
|
173
|
+
return fetchFileSystem(urlObject, {
|
|
174
|
+
headers: request.headers,
|
|
175
|
+
cacheControl: urlIsVersioned
|
|
176
|
+
? `private,max-age=${SECONDS_IN_30_DAYS},immutable`
|
|
177
|
+
: "private,max-age=0,must-revalidate",
|
|
178
|
+
etagEnabled: true,
|
|
179
|
+
compressionEnabled: !request.pathname.endsWith(".mp4"),
|
|
180
|
+
rootDirectoryUrl: buildDirectoryUrl,
|
|
181
|
+
canReadDirectory: true,
|
|
182
|
+
ENOENTFallback: () => {
|
|
183
|
+
if (
|
|
184
|
+
!urlToExtension(urlObject) &&
|
|
185
|
+
!urlToPathname(urlObject).endsWith("/")
|
|
186
|
+
) {
|
|
187
|
+
return new URL(buildMainFilePath, buildDirectoryUrl);
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
182
190
|
},
|
|
183
|
-
);
|
|
191
|
+
});
|
|
184
192
|
};
|
|
185
193
|
};
|
|
186
194
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { generateUrlForInlineContent } from "@jsenv/ast";
|
|
2
2
|
import { generateContentFrame } from "@jsenv/humanize";
|
|
3
3
|
import {
|
|
4
|
+
asSpecifierWithoutSearch,
|
|
4
5
|
getCallerPosition,
|
|
5
6
|
stringifyUrlSite,
|
|
6
7
|
urlToBasename,
|
|
@@ -315,6 +316,7 @@ const createReference = ({
|
|
|
315
316
|
);
|
|
316
317
|
}
|
|
317
318
|
}
|
|
319
|
+
|
|
318
320
|
const reference = {
|
|
319
321
|
id: ++referenceId,
|
|
320
322
|
ownerUrlInfo,
|
|
@@ -337,6 +339,9 @@ const createReference = ({
|
|
|
337
339
|
integrity,
|
|
338
340
|
crossorigin,
|
|
339
341
|
specifier,
|
|
342
|
+
get specifierPathname() {
|
|
343
|
+
return asSpecifierWithoutSearch(reference.specifier);
|
|
344
|
+
},
|
|
340
345
|
specifierStart,
|
|
341
346
|
specifierEnd,
|
|
342
347
|
specifierLine,
|
|
@@ -30,7 +30,7 @@ export const jsenvPluginDirectoryReferenceEffect = (
|
|
|
30
30
|
reference.filenameHint = `${
|
|
31
31
|
reference.ownerUrlInfo.filenameHint
|
|
32
32
|
}${urlToFilename(reference.url)}/`;
|
|
33
|
-
} else if (reference.
|
|
33
|
+
} else if (reference.specifierPathname.endsWith("./")) {
|
|
34
34
|
} else {
|
|
35
35
|
reference.filenameHint = `${urlToFilename(reference.url)}/`;
|
|
36
36
|
}
|
package/src/plugins/plugins.js
CHANGED
|
@@ -86,7 +86,7 @@ export const getCorePlugins = ({
|
|
|
86
86
|
appliesDuring: "*",
|
|
87
87
|
resolveReference: (reference) => {
|
|
88
88
|
const { ownerUrlInfo } = reference;
|
|
89
|
-
if (reference.
|
|
89
|
+
if (reference.specifierPathname === "/") {
|
|
90
90
|
const { mainFilePath, rootDirectoryUrl } = ownerUrlInfo.context;
|
|
91
91
|
const url = new URL(mainFilePath, rootDirectoryUrl);
|
|
92
92
|
return url;
|
|
@@ -30,6 +30,14 @@ export const jsenvPluginFsRedirection = ({
|
|
|
30
30
|
if (reference.subtype === "new_url_second_arg") {
|
|
31
31
|
return `ignore:${reference.url}`;
|
|
32
32
|
}
|
|
33
|
+
if (reference.specifierPathname.endsWith("/...")) {
|
|
34
|
+
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
|
|
35
|
+
const directoryUrl = new URL(
|
|
36
|
+
reference.specifierPathname.replace("/...", "/").slice(1),
|
|
37
|
+
rootDirectoryUrl,
|
|
38
|
+
).href;
|
|
39
|
+
return directoryUrl;
|
|
40
|
+
}
|
|
33
41
|
// ignore "./" on new URL("./")
|
|
34
42
|
// if (
|
|
35
43
|
// reference.subtype === "new_url_first_arg" &&
|
|
@@ -69,6 +69,14 @@ export const jsenvPluginProtocolFile = ({
|
|
|
69
69
|
if (!generatedUrl.startsWith("file:")) {
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
|
+
if (reference.original) {
|
|
73
|
+
const originalSpecifierPathname =
|
|
74
|
+
reference.original.specifierPathname;
|
|
75
|
+
|
|
76
|
+
if (originalSpecifierPathname.endsWith("/...")) {
|
|
77
|
+
return originalSpecifierPathname;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
72
80
|
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
|
|
73
81
|
if (urlIsInsideOf(generatedUrl, rootDirectoryUrl)) {
|
|
74
82
|
const result = `/${urlToRelativeUrl(generatedUrl, rootDirectoryUrl)}`;
|
|
@@ -225,7 +233,7 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
225
233
|
let i = 0;
|
|
226
234
|
while (i < parts.length) {
|
|
227
235
|
const part = parts[i];
|
|
228
|
-
const href = i === 0 ? "
|
|
236
|
+
const href = i === 0 ? "/..." : `/${parts.slice(1, i + 1).join("/")}/`;
|
|
229
237
|
const text = part;
|
|
230
238
|
const isLastPart = i === parts.length - 1;
|
|
231
239
|
if (isLastPart) {
|
|
@@ -33,7 +33,7 @@ export const createNodeEsmResolver = ({
|
|
|
33
33
|
return reference.specifier;
|
|
34
34
|
}
|
|
35
35
|
const { ownerUrlInfo } = reference;
|
|
36
|
-
if (reference.
|
|
36
|
+
if (reference.specifierPathname[0] === "/") {
|
|
37
37
|
const url = new URL(
|
|
38
38
|
reference.specifier.slice(1),
|
|
39
39
|
ownerUrlInfo.context.rootDirectoryUrl,
|
|
@@ -4,7 +4,7 @@ export const jsenvPluginWebResolution = () => {
|
|
|
4
4
|
appliesDuring: "*",
|
|
5
5
|
resolveReference: (reference) => {
|
|
6
6
|
const { ownerUrlInfo } = reference;
|
|
7
|
-
if (reference.
|
|
7
|
+
if (reference.specifierPathname[0] === "/") {
|
|
8
8
|
const url = new URL(
|
|
9
9
|
reference.specifier.slice(1),
|
|
10
10
|
ownerUrlInfo.context.rootDirectoryUrl,
|