@jsenv/core 40.7.0 → 40.7.2
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/build/browserslist_index/browserslist_index.js +62 -48
- package/dist/build/build.js +95 -63
- package/dist/build/jsenv_core_packages.js +3 -3
- package/dist/client/directory_listing/js/directory_listing.js +41 -26
- package/dist/client/ribbon/ribbon.js +40 -37
- package/dist/start_dev_server/jsenv_core_packages.js +3 -3
- package/dist/start_dev_server/start_dev_server.js +92 -59
- package/package.json +21 -12
- package/src/build/build.js +9 -9
- package/src/build/build_specifier_manager.js +3 -3
- package/src/build/build_urls_generator.js +2 -2
- package/src/dev/start_dev_server.js +8 -7
- package/src/helpers/web_url_converter.js +2 -2
- package/src/kitchen/errors.js +6 -1
- package/src/kitchen/out_directory_url.js +2 -2
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +2 -2
- package/src/plugins/chrome_devtools_json/jsenv_plugin_chrome_devtools_json.js +1 -0
- package/src/plugins/plugin_controller.js +25 -7
- package/src/plugins/protocol_file/client/directory_listing.jsx +42 -23
- package/src/plugins/protocol_file/file_and_server_urls_converter.js +2 -5
- package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +45 -30
- package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +5 -10
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +2 -1
- package/src/plugins/ribbon/client/ribbon.js +40 -37
|
@@ -31,7 +31,7 @@ import { pickContentType, WebSocketResponse } from "@jsenv/server";
|
|
|
31
31
|
import {
|
|
32
32
|
asUrlWithoutSearch,
|
|
33
33
|
ensurePathnameTrailingSlash,
|
|
34
|
-
|
|
34
|
+
urlIsOrIsInsideOf,
|
|
35
35
|
urlToFilename,
|
|
36
36
|
urlToRelativeUrl,
|
|
37
37
|
} from "@jsenv/urls";
|
|
@@ -44,6 +44,7 @@ const htmlFileUrlForDirectory = import.meta.resolve(
|
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
export const jsenvPluginDirectoryListing = ({
|
|
47
|
+
spa,
|
|
47
48
|
urlMocks = false,
|
|
48
49
|
autoreload = true,
|
|
49
50
|
directoryContentMagicName,
|
|
@@ -85,7 +86,7 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
85
86
|
return null;
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
|
-
return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(
|
|
89
|
+
return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(requestedUrl)}&enoent`;
|
|
89
90
|
}
|
|
90
91
|
const isDirectory = fsStat?.isDirectory();
|
|
91
92
|
if (!isDirectory) {
|
|
@@ -111,21 +112,22 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
111
112
|
if (urlWithoutSearch !== String(htmlFileUrlForDirectory)) {
|
|
112
113
|
return null;
|
|
113
114
|
}
|
|
114
|
-
const
|
|
115
|
-
if (!
|
|
115
|
+
const urlNotFound = urlInfo.searchParams.get("url");
|
|
116
|
+
if (!urlNotFound) {
|
|
116
117
|
return null;
|
|
117
118
|
}
|
|
119
|
+
|
|
118
120
|
urlInfo.headers["cache-control"] = "no-cache";
|
|
119
121
|
const enoent = urlInfo.searchParams.has("enoent");
|
|
120
122
|
if (enoent) {
|
|
121
123
|
urlInfo.status = 404;
|
|
122
|
-
urlInfo.headers["cache-control"] = "no-cache";
|
|
123
124
|
}
|
|
124
125
|
const request = urlInfo.context.request;
|
|
125
126
|
const { rootDirectoryUrl, mainFilePath } = urlInfo.context;
|
|
126
127
|
const directoryListingInjections = generateDirectoryListingInjection(
|
|
127
|
-
|
|
128
|
+
urlNotFound,
|
|
128
129
|
{
|
|
130
|
+
spa,
|
|
129
131
|
autoreload,
|
|
130
132
|
request,
|
|
131
133
|
urlMocks,
|
|
@@ -219,8 +221,9 @@ export const jsenvPluginDirectoryListing = ({
|
|
|
219
221
|
};
|
|
220
222
|
|
|
221
223
|
const generateDirectoryListingInjection = (
|
|
222
|
-
|
|
224
|
+
urlNotFound,
|
|
223
225
|
{
|
|
226
|
+
spa,
|
|
224
227
|
rootDirectoryUrl,
|
|
225
228
|
mainFilePath,
|
|
226
229
|
packageDirectory,
|
|
@@ -233,13 +236,13 @@ const generateDirectoryListingInjection = (
|
|
|
233
236
|
) => {
|
|
234
237
|
let serverRootDirectoryUrl = rootDirectoryUrl;
|
|
235
238
|
const firstExistingDirectoryUrl = getFirstExistingDirectoryUrl(
|
|
236
|
-
|
|
239
|
+
urlNotFound,
|
|
237
240
|
serverRootDirectoryUrl,
|
|
238
241
|
);
|
|
239
242
|
const directoryContentItems = getDirectoryContentItems({
|
|
240
243
|
serverRootDirectoryUrl,
|
|
241
244
|
mainFilePath,
|
|
242
|
-
requestedUrl,
|
|
245
|
+
requestedUrl: urlNotFound,
|
|
243
246
|
firstExistingDirectoryUrl,
|
|
244
247
|
});
|
|
245
248
|
package_workspaces: {
|
|
@@ -285,8 +288,8 @@ const generateDirectoryListingInjection = (
|
|
|
285
288
|
const { host } = new URL(request.url);
|
|
286
289
|
const websocketUrl = `${websocketScheme}://${host}/.internal/directory_content.websocket?directory=${encodeURIComponent(directoryUrlRelativeToServer)}`;
|
|
287
290
|
|
|
288
|
-
const
|
|
289
|
-
|
|
291
|
+
const generateBreadcrumb = () => {
|
|
292
|
+
const breadcrumb = [];
|
|
290
293
|
const lastItemUrl = firstExistingDirectoryUrl;
|
|
291
294
|
const lastItemRelativeUrl = urlToRelativeUrl(lastItemUrl, rootDirectoryUrl);
|
|
292
295
|
const rootDirectoryUrlName = urlToFilename(rootDirectoryUrl);
|
|
@@ -296,7 +299,6 @@ const generateDirectoryListingInjection = (
|
|
|
296
299
|
} else {
|
|
297
300
|
parts = [rootDirectoryUrlName];
|
|
298
301
|
}
|
|
299
|
-
|
|
300
302
|
let i = 0;
|
|
301
303
|
while (i < parts.length) {
|
|
302
304
|
const part = parts[i];
|
|
@@ -317,7 +319,7 @@ const generateDirectoryListingInjection = (
|
|
|
317
319
|
navItemUrl,
|
|
318
320
|
serverRootDirectoryUrl,
|
|
319
321
|
);
|
|
320
|
-
let urlRelativeToDocument = urlToRelativeUrl(navItemUrl,
|
|
322
|
+
let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, urlNotFound);
|
|
321
323
|
const isServerRootDirectory = navItemUrl === serverRootDirectoryUrl;
|
|
322
324
|
if (isServerRootDirectory) {
|
|
323
325
|
urlRelativeToServer = `/${directoryContentMagicName}`;
|
|
@@ -325,7 +327,7 @@ const generateDirectoryListingInjection = (
|
|
|
325
327
|
}
|
|
326
328
|
const name = part;
|
|
327
329
|
const isCurrent = navItemUrl === String(firstExistingDirectoryUrl);
|
|
328
|
-
|
|
330
|
+
breadcrumb.push({
|
|
329
331
|
url: navItemUrl,
|
|
330
332
|
urlRelativeToServer,
|
|
331
333
|
urlRelativeToDocument,
|
|
@@ -335,34 +337,47 @@ const generateDirectoryListingInjection = (
|
|
|
335
337
|
});
|
|
336
338
|
i++;
|
|
337
339
|
}
|
|
338
|
-
|
|
340
|
+
return breadcrumb;
|
|
341
|
+
};
|
|
342
|
+
const breadcrumb = generateBreadcrumb(urlNotFound);
|
|
339
343
|
|
|
340
344
|
let enoentDetails = null;
|
|
341
345
|
if (enoent) {
|
|
346
|
+
const buildEnoentPathInfo = (urlBase, closestExistingUrl) => {
|
|
347
|
+
let filePathExisting;
|
|
348
|
+
let filePathNotFound;
|
|
349
|
+
const existingIndex = String(closestExistingUrl).length;
|
|
350
|
+
filePathExisting = urlToRelativeUrl(
|
|
351
|
+
closestExistingUrl,
|
|
352
|
+
serverRootDirectoryUrl,
|
|
353
|
+
);
|
|
354
|
+
filePathNotFound = urlBase.slice(existingIndex);
|
|
355
|
+
return [filePathExisting, filePathNotFound];
|
|
356
|
+
};
|
|
342
357
|
const fileRelativeUrl = urlToRelativeUrl(
|
|
343
|
-
|
|
344
|
-
serverRootDirectoryUrl,
|
|
345
|
-
);
|
|
346
|
-
let filePathExisting;
|
|
347
|
-
let filePathNotFound;
|
|
348
|
-
const existingIndex = String(firstExistingDirectoryUrl).length;
|
|
349
|
-
filePathExisting = urlToRelativeUrl(
|
|
350
|
-
firstExistingDirectoryUrl,
|
|
358
|
+
urlNotFound,
|
|
351
359
|
serverRootDirectoryUrl,
|
|
352
360
|
);
|
|
353
|
-
filePathNotFound = requestedUrl.slice(existingIndex);
|
|
354
361
|
enoentDetails = {
|
|
355
|
-
fileUrl:
|
|
362
|
+
fileUrl: urlNotFound,
|
|
356
363
|
fileRelativeUrl,
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const [filePathExisting, filePathNotFound] = buildEnoentPathInfo(
|
|
367
|
+
urlNotFound,
|
|
368
|
+
firstExistingDirectoryUrl,
|
|
369
|
+
);
|
|
370
|
+
Object.assign(enoentDetails, {
|
|
357
371
|
filePathExisting: `/${filePathExisting}`,
|
|
358
372
|
filePathNotFound,
|
|
359
|
-
};
|
|
373
|
+
});
|
|
360
374
|
}
|
|
361
375
|
|
|
362
376
|
return {
|
|
363
377
|
__DIRECTORY_LISTING__: {
|
|
378
|
+
spa,
|
|
364
379
|
enoentDetails,
|
|
365
|
-
|
|
380
|
+
breadcrumb,
|
|
366
381
|
urlMocks,
|
|
367
382
|
directoryContentMagicName,
|
|
368
383
|
directoryUrl: firstExistingDirectoryUrl,
|
|
@@ -375,11 +390,11 @@ const generateDirectoryListingInjection = (
|
|
|
375
390
|
},
|
|
376
391
|
};
|
|
377
392
|
};
|
|
378
|
-
const getFirstExistingDirectoryUrl = (
|
|
379
|
-
let directoryUrlCandidate = new URL("./",
|
|
393
|
+
const getFirstExistingDirectoryUrl = (urlBase, serverRootDirectoryUrl) => {
|
|
394
|
+
let directoryUrlCandidate = new URL("./", urlBase);
|
|
380
395
|
while (!existsSync(directoryUrlCandidate)) {
|
|
381
396
|
directoryUrlCandidate = new URL("../", directoryUrlCandidate);
|
|
382
|
-
if (!
|
|
397
|
+
if (!urlIsOrIsInsideOf(directoryUrlCandidate, serverRootDirectoryUrl)) {
|
|
383
398
|
directoryUrlCandidate = new URL(serverRootDirectoryUrl);
|
|
384
399
|
break;
|
|
385
400
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getExtensionsToTry,
|
|
5
5
|
} from "@jsenv/node-esm-resolution";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
urlIsOrIsInsideOf,
|
|
8
8
|
urlToExtension,
|
|
9
9
|
urlToFilename,
|
|
10
10
|
urlToPathname,
|
|
@@ -13,7 +13,7 @@ import { existsSync, realpathSync } from "node:fs";
|
|
|
13
13
|
import { pathToFileURL } from "node:url";
|
|
14
14
|
|
|
15
15
|
export const jsenvPluginFsRedirection = ({
|
|
16
|
-
spa
|
|
16
|
+
spa,
|
|
17
17
|
directoryContentMagicName,
|
|
18
18
|
magicExtensions = ["inherit", ".js"],
|
|
19
19
|
magicDirectoryIndex = true,
|
|
@@ -172,17 +172,12 @@ const getClosestHtmlRootFile = (requestedUrl, serverRootDirectoryUrl) => {
|
|
|
172
172
|
if (existsSync(indexHtmlFileUrl)) {
|
|
173
173
|
return indexHtmlFileUrl.href;
|
|
174
174
|
}
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
directoryUrl,
|
|
178
|
-
);
|
|
175
|
+
const filename = urlToFilename(directoryUrl);
|
|
176
|
+
const htmlFileUrlCandidate = new URL(`${filename}.html`, directoryUrl);
|
|
179
177
|
if (existsSync(htmlFileUrlCandidate)) {
|
|
180
178
|
return htmlFileUrlCandidate.href;
|
|
181
179
|
}
|
|
182
|
-
if (
|
|
183
|
-
!urlIsInsideOf(directoryUrl, serverRootDirectoryUrl) ||
|
|
184
|
-
directoryUrl.href === serverRootDirectoryUrl
|
|
185
|
-
) {
|
|
180
|
+
if (!urlIsOrIsInsideOf(directoryUrl, serverRootDirectoryUrl)) {
|
|
186
181
|
return null;
|
|
187
182
|
}
|
|
188
183
|
directoryUrl = new URL("../", directoryUrl);
|
|
@@ -9,7 +9,7 @@ import { jsenvPluginFsRedirection } from "./jsenv_plugin_fs_redirection.js";
|
|
|
9
9
|
const directoryContentMagicName = "...";
|
|
10
10
|
|
|
11
11
|
export const jsenvPluginProtocolFile = ({
|
|
12
|
-
spa,
|
|
12
|
+
spa = true,
|
|
13
13
|
magicExtensions,
|
|
14
14
|
magicDirectoryIndex,
|
|
15
15
|
preserveSymlinks,
|
|
@@ -77,6 +77,7 @@ export const jsenvPluginProtocolFile = ({
|
|
|
77
77
|
...(directoryListing
|
|
78
78
|
? [
|
|
79
79
|
jsenvPluginDirectoryListing({
|
|
80
|
+
spa,
|
|
80
81
|
...directoryListing,
|
|
81
82
|
directoryContentMagicName,
|
|
82
83
|
rootDirectoryUrl,
|
|
@@ -1,43 +1,46 @@
|
|
|
1
1
|
export const injectRibbon = ({ text }) => {
|
|
2
2
|
const css = /* css */ `
|
|
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
|
-
|
|
3
|
+
#jsenv_ribbon_container {
|
|
4
|
+
position: fixed;
|
|
5
|
+
z-index: 1001;
|
|
6
|
+
top: 0;
|
|
7
|
+
right: 0;
|
|
8
|
+
width: 100px;
|
|
9
|
+
height: 100px;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
opacity: 0.5;
|
|
12
|
+
pointer-events: none;
|
|
13
|
+
}
|
|
14
|
+
#jsenv_ribbon {
|
|
15
|
+
position: absolute;
|
|
16
|
+
top: -10px;
|
|
17
|
+
right: -10px;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 100%;
|
|
20
|
+
}
|
|
21
|
+
#jsenv_ribbon_text {
|
|
22
|
+
position: absolute;
|
|
23
|
+
left: 0px;
|
|
24
|
+
top: 20px;
|
|
25
|
+
transform: rotate(45deg);
|
|
26
|
+
display: block;
|
|
27
|
+
width: 125px;
|
|
28
|
+
line-height: 36px;
|
|
29
|
+
background-color: orange;
|
|
30
|
+
color: rgb(55, 7, 7);
|
|
31
|
+
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
|
|
32
|
+
font-weight: 700;
|
|
33
|
+
font-size: 16px;
|
|
34
|
+
font-family: "Lato", sans-serif;
|
|
35
|
+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
|
36
|
+
text-align: center;
|
|
37
|
+
user-select: none;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
39
40
|
const html = /* html */ `<div id="jsenv_ribbon_container">
|
|
40
|
-
<style
|
|
41
|
+
<style>
|
|
42
|
+
${css}
|
|
43
|
+
</style>
|
|
41
44
|
<div id="jsenv_ribbon">
|
|
42
45
|
<div id="jsenv_ribbon_text">${text}</div>
|
|
43
46
|
</div>
|