@jsenv/core 39.10.1 → 39.11.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/html/directory.html +6 -0
- package/dist/html/html_404_and_ancestor_dir.html +7 -1
- package/dist/jsenv_core.js +117 -66
- package/package.json +1 -1
- package/src/helpers/event_emitter.js +2 -2
- package/src/kitchen/url_graph/references.js +9 -4
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +5 -0
- package/src/plugins/protocol_file/client/assets/directory.css +5 -0
- package/src/plugins/protocol_file/client/html_404_and_ancestor_dir.html +1 -1
- package/src/plugins/protocol_file/jsenv_plugin_fs_redirection.js +7 -2
- package/src/plugins/protocol_file/jsenv_plugin_protocol_file.js +94 -58
package/dist/html/directory.html
CHANGED
|
@@ -27,6 +27,12 @@
|
|
|
27
27
|
position: relative;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
.directory_empty_message {
|
|
31
|
+
color: #bbb;
|
|
32
|
+
margin: 1em;
|
|
33
|
+
padding: .5em;
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
.directory_content {
|
|
31
37
|
border-radius: 3px;
|
|
32
38
|
margin: 10px 15px;
|
|
@@ -188,7 +194,7 @@
|
|
|
188
194
|
No entry on the filesystem for <code>/${fileRelativeUrl}</code> (at
|
|
189
195
|
${fileUrl})
|
|
190
196
|
<br>
|
|
191
|
-
Content of
|
|
197
|
+
Content of first ancestor directory is listed below:
|
|
192
198
|
</span>
|
|
193
199
|
</p>
|
|
194
200
|
<h1 class="directory_nav">${ancestorDirectoryNav}</h1>
|
package/dist/jsenv_core.js
CHANGED
|
@@ -12648,9 +12648,9 @@ const createEventEmitter = () => {
|
|
|
12648
12648
|
callbackSet.delete(callback);
|
|
12649
12649
|
};
|
|
12650
12650
|
const emit = (...args) => {
|
|
12651
|
-
|
|
12651
|
+
for (const callback of callbackSet) {
|
|
12652
12652
|
callback(...args);
|
|
12653
|
-
}
|
|
12653
|
+
}
|
|
12654
12654
|
};
|
|
12655
12655
|
return { on, off, emit };
|
|
12656
12656
|
};
|
|
@@ -12817,7 +12817,7 @@ const createDependencies = (ownerUrlInfo) => {
|
|
|
12817
12817
|
|
|
12818
12818
|
const stopCollecting = () => {
|
|
12819
12819
|
for (const prevReferenceToOther of prevReferenceToOthersSet) {
|
|
12820
|
-
|
|
12820
|
+
checkForDependencyRemovalEffects(prevReferenceToOther);
|
|
12821
12821
|
}
|
|
12822
12822
|
prevReferenceToOthersSet.clear();
|
|
12823
12823
|
};
|
|
@@ -13322,7 +13322,7 @@ ${ownerUrlInfo.url}`,
|
|
|
13322
13322
|
implicitRef.remove();
|
|
13323
13323
|
}
|
|
13324
13324
|
ownerUrlInfo.referenceToOthersSet.delete(reference);
|
|
13325
|
-
return
|
|
13325
|
+
return checkForDependencyRemovalEffects(reference);
|
|
13326
13326
|
};
|
|
13327
13327
|
|
|
13328
13328
|
const canAddOrRemoveReference = (reference) => {
|
|
@@ -13351,7 +13351,7 @@ const canAddOrRemoveReference = (reference) => {
|
|
|
13351
13351
|
return false;
|
|
13352
13352
|
};
|
|
13353
13353
|
|
|
13354
|
-
const
|
|
13354
|
+
const checkForDependencyRemovalEffects = (reference) => {
|
|
13355
13355
|
const { ownerUrlInfo } = reference;
|
|
13356
13356
|
const { referenceToOthersSet } = ownerUrlInfo;
|
|
13357
13357
|
if (reference.isImplicit && !reference.isInline) {
|
|
@@ -13386,6 +13386,7 @@ const applyDependencyRemovalEffects = (reference) => {
|
|
|
13386
13386
|
referencedUrlInfo.referenceFromOthersSet.delete(reference);
|
|
13387
13387
|
|
|
13388
13388
|
let firstReferenceFromOther;
|
|
13389
|
+
let wasInlined;
|
|
13389
13390
|
for (const referenceFromOther of referencedUrlInfo.referenceFromOthersSet) {
|
|
13390
13391
|
if (referenceFromOther.urlInfo !== referencedUrlInfo) {
|
|
13391
13392
|
continue;
|
|
@@ -13400,7 +13401,8 @@ const applyDependencyRemovalEffects = (reference) => {
|
|
|
13400
13401
|
if (referenceFromOther.type === "http_request") {
|
|
13401
13402
|
continue;
|
|
13402
13403
|
}
|
|
13403
|
-
|
|
13404
|
+
wasInlined = referenceFromOther.gotInlined();
|
|
13405
|
+
if (wasInlined) {
|
|
13404
13406
|
// the url info was inlined, an other reference is required
|
|
13405
13407
|
// to consider the non-inlined urlInfo as used
|
|
13406
13408
|
continue;
|
|
@@ -13418,6 +13420,9 @@ const applyDependencyRemovalEffects = (reference) => {
|
|
|
13418
13420
|
}
|
|
13419
13421
|
return false;
|
|
13420
13422
|
}
|
|
13423
|
+
if (wasInlined) {
|
|
13424
|
+
return false;
|
|
13425
|
+
}
|
|
13421
13426
|
// referencedUrlInfo.firstReference = null;
|
|
13422
13427
|
// referencedUrlInfo.lastReference = null;
|
|
13423
13428
|
referencedUrlInfo.onDereferenced(reference);
|
|
@@ -19176,6 +19181,7 @@ const jsenvPluginVersionSearchParam = () => {
|
|
|
19176
19181
|
};
|
|
19177
19182
|
|
|
19178
19183
|
const jsenvPluginFsRedirection = ({
|
|
19184
|
+
directoryContentMagicName,
|
|
19179
19185
|
magicExtensions = ["inherit", ".js"],
|
|
19180
19186
|
magicDirectoryIndex = true,
|
|
19181
19187
|
preserveSymlinks = false,
|
|
@@ -19198,10 +19204,14 @@ const jsenvPluginFsRedirection = ({
|
|
|
19198
19204
|
if (reference.subtype === "new_url_second_arg") {
|
|
19199
19205
|
return `ignore:${reference.url}`;
|
|
19200
19206
|
}
|
|
19201
|
-
if (
|
|
19207
|
+
if (
|
|
19208
|
+
reference.specifierPathname.endsWith(`/${directoryContentMagicName}`)
|
|
19209
|
+
) {
|
|
19202
19210
|
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
|
|
19203
19211
|
const directoryUrl = new URL(
|
|
19204
|
-
reference.specifierPathname
|
|
19212
|
+
reference.specifierPathname
|
|
19213
|
+
.replace(`/${directoryContentMagicName}`, "/")
|
|
19214
|
+
.slice(1),
|
|
19205
19215
|
rootDirectoryUrl,
|
|
19206
19216
|
).href;
|
|
19207
19217
|
return directoryUrl;
|
|
@@ -19312,6 +19322,7 @@ const htmlFileUrlForDirectory = new URL(
|
|
|
19312
19322
|
"./html/directory.html",
|
|
19313
19323
|
import.meta.url,
|
|
19314
19324
|
);
|
|
19325
|
+
const directoryContentMagicName = "...";
|
|
19315
19326
|
|
|
19316
19327
|
const jsenvPluginProtocolFile = ({
|
|
19317
19328
|
magicExtensions,
|
|
@@ -19321,6 +19332,7 @@ const jsenvPluginProtocolFile = ({
|
|
|
19321
19332
|
}) => {
|
|
19322
19333
|
return [
|
|
19323
19334
|
jsenvPluginFsRedirection({
|
|
19335
|
+
directoryContentMagicName,
|
|
19324
19336
|
magicExtensions,
|
|
19325
19337
|
magicDirectoryIndex,
|
|
19326
19338
|
preserveSymlinks,
|
|
@@ -19360,8 +19372,9 @@ const jsenvPluginProtocolFile = ({
|
|
|
19360
19372
|
if (reference.original) {
|
|
19361
19373
|
const originalSpecifierPathname =
|
|
19362
19374
|
reference.original.specifierPathname;
|
|
19363
|
-
|
|
19364
|
-
|
|
19375
|
+
if (
|
|
19376
|
+
originalSpecifierPathname.endsWith(`/${directoryContentMagicName}`)
|
|
19377
|
+
) {
|
|
19365
19378
|
return originalSpecifierPathname;
|
|
19366
19379
|
}
|
|
19367
19380
|
}
|
|
@@ -19467,11 +19480,14 @@ const generateHtmlForDirectory = (directoryContentItems) => {
|
|
|
19467
19480
|
directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
19468
19481
|
|
|
19469
19482
|
const htmlForDirectory = String(readFileSync(htmlFileUrlForDirectory));
|
|
19470
|
-
const directoryRelativeUrl = urlToRelativeUrl(directoryUrl, rootDirectoryUrl);
|
|
19471
19483
|
const replacers = {
|
|
19472
19484
|
directoryUrl,
|
|
19473
19485
|
directoryNav: () =>
|
|
19474
|
-
generateDirectoryNav(
|
|
19486
|
+
generateDirectoryNav(directoryUrl, {
|
|
19487
|
+
rootDirectoryUrl,
|
|
19488
|
+
rootDirectoryUrlForServer:
|
|
19489
|
+
directoryContentItems.rootDirectoryUrlForServer,
|
|
19490
|
+
}),
|
|
19475
19491
|
directoryContent: () => generateDirectoryContent(directoryContentItems),
|
|
19476
19492
|
};
|
|
19477
19493
|
const html = replacePlaceholders$1(htmlForDirectory, replacers);
|
|
@@ -19501,44 +19517,60 @@ const generateHtmlForENOENT = (
|
|
|
19501
19517
|
ancestorDirectoryUrl,
|
|
19502
19518
|
ancestorDirectoryRelativeUrl,
|
|
19503
19519
|
ancestorDirectoryNav: () =>
|
|
19504
|
-
generateDirectoryNav(
|
|
19520
|
+
generateDirectoryNav(ancestorDirectoryUrl, {
|
|
19521
|
+
rootDirectoryUrl,
|
|
19522
|
+
rootDirectoryUrlForServer:
|
|
19523
|
+
directoryContentItems.rootDirectoryUrlForServer,
|
|
19524
|
+
}),
|
|
19505
19525
|
ancestorDirectoryContent: () =>
|
|
19506
19526
|
generateDirectoryContent(directoryContentItems),
|
|
19507
19527
|
};
|
|
19508
19528
|
const html = replacePlaceholders$1(htmlFor404AndAncestorDir, replacers);
|
|
19509
19529
|
return html;
|
|
19510
19530
|
};
|
|
19511
|
-
const generateDirectoryNav = (
|
|
19531
|
+
const generateDirectoryNav = (
|
|
19532
|
+
entryDirectoryUrl,
|
|
19533
|
+
{ rootDirectoryUrl, rootDirectoryUrlForServer },
|
|
19534
|
+
) => {
|
|
19535
|
+
const entryDirectoryRelativeUrl = urlToRelativeUrl(
|
|
19536
|
+
entryDirectoryUrl,
|
|
19537
|
+
rootDirectoryUrl,
|
|
19538
|
+
);
|
|
19539
|
+
const isDir = entryDirectoryRelativeUrl.endsWith("/");
|
|
19512
19540
|
const rootDirectoryUrlName = urlToFilename$1(rootDirectoryUrl);
|
|
19513
|
-
const relativeUrlWithRoot = relativeUrl
|
|
19514
|
-
? `${rootDirectoryUrlName}/${relativeUrl}`
|
|
19515
|
-
: `${rootDirectoryUrlName}/`;
|
|
19516
|
-
const isDir = relativeUrlWithRoot.endsWith("/");
|
|
19517
|
-
const parts = isDir
|
|
19518
|
-
? relativeUrlWithRoot.slice(0, -1).split("/")
|
|
19519
|
-
: relativeUrlWithRoot.split("/");
|
|
19520
19541
|
const items = [];
|
|
19521
|
-
items.push({
|
|
19522
|
-
href: "/",
|
|
19523
|
-
text: "/",
|
|
19524
|
-
});
|
|
19525
19542
|
let dirPartsHtml = "";
|
|
19543
|
+
const parts =
|
|
19544
|
+
`${rootDirectoryUrlName}/${entryDirectoryRelativeUrl.slice(0, -1)}`.split(
|
|
19545
|
+
"/",
|
|
19546
|
+
);
|
|
19526
19547
|
let i = 0;
|
|
19527
19548
|
while (i < parts.length) {
|
|
19528
19549
|
const part = parts[i];
|
|
19529
|
-
const
|
|
19550
|
+
const directoryRelativeUrl = `${parts.slice(1, i + 1).join("/")}`;
|
|
19551
|
+
const directoryUrl =
|
|
19552
|
+
directoryRelativeUrl === ""
|
|
19553
|
+
? rootDirectoryUrl
|
|
19554
|
+
: new URL(`${directoryRelativeUrl}/`, rootDirectoryUrl).href;
|
|
19555
|
+
let href =
|
|
19556
|
+
directoryUrl === rootDirectoryUrlForServer ||
|
|
19557
|
+
urlIsInsideOf(directoryUrl, rootDirectoryUrlForServer)
|
|
19558
|
+
? urlToRelativeUrl(directoryUrl, rootDirectoryUrlForServer)
|
|
19559
|
+
: directoryUrl;
|
|
19560
|
+
if (href === "") {
|
|
19561
|
+
href = `/${directoryContentMagicName}`;
|
|
19562
|
+
}
|
|
19530
19563
|
const text = part;
|
|
19531
|
-
const isLastPart = i === parts.length - 1;
|
|
19532
19564
|
items.push({
|
|
19533
19565
|
href,
|
|
19534
19566
|
text,
|
|
19535
|
-
isCurrent: isLastPart,
|
|
19536
19567
|
});
|
|
19537
19568
|
i++;
|
|
19538
19569
|
}
|
|
19539
19570
|
i = 0;
|
|
19540
|
-
for (const { href, text
|
|
19541
|
-
|
|
19571
|
+
for (const { href, text } of items) {
|
|
19572
|
+
const isLastPart = i === parts.length - 1;
|
|
19573
|
+
if (isLastPart) {
|
|
19542
19574
|
dirPartsHtml += `
|
|
19543
19575
|
<span class="directory_nav_item" data-current>
|
|
19544
19576
|
${text}
|
|
@@ -19549,10 +19581,8 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
19549
19581
|
<a class="directory_nav_item" href="${href}">
|
|
19550
19582
|
${text}
|
|
19551
19583
|
</a>`;
|
|
19552
|
-
|
|
19553
|
-
dirPartsHtml += `
|
|
19584
|
+
dirPartsHtml += `
|
|
19554
19585
|
<span class="directory_separator">/</span>`;
|
|
19555
|
-
}
|
|
19556
19586
|
i++;
|
|
19557
19587
|
}
|
|
19558
19588
|
if (isDir) {
|
|
@@ -19561,12 +19591,15 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
19561
19591
|
}
|
|
19562
19592
|
return dirPartsHtml;
|
|
19563
19593
|
};
|
|
19564
|
-
const generateDirectoryContentItems = (
|
|
19594
|
+
const generateDirectoryContentItems = (
|
|
19595
|
+
directoryUrl,
|
|
19596
|
+
rootDirectoryUrlForServer,
|
|
19597
|
+
) => {
|
|
19565
19598
|
let firstExistingDirectoryUrl = new URL("./", directoryUrl);
|
|
19566
19599
|
while (!existsSync(firstExistingDirectoryUrl)) {
|
|
19567
19600
|
firstExistingDirectoryUrl = new URL("../", firstExistingDirectoryUrl);
|
|
19568
|
-
if (!urlIsInsideOf(firstExistingDirectoryUrl,
|
|
19569
|
-
firstExistingDirectoryUrl = new URL(
|
|
19601
|
+
if (!urlIsInsideOf(firstExistingDirectoryUrl, rootDirectoryUrlForServer)) {
|
|
19602
|
+
firstExistingDirectoryUrl = new URL(rootDirectoryUrlForServer);
|
|
19570
19603
|
break;
|
|
19571
19604
|
}
|
|
19572
19605
|
}
|
|
@@ -19576,37 +19609,42 @@ const generateDirectoryContentItems = (directoryUrl, rootDirectoryUrl) => {
|
|
|
19576
19609
|
const fileUrlObject = new URL(filename, firstExistingDirectoryUrl);
|
|
19577
19610
|
fileUrls.push(fileUrlObject);
|
|
19578
19611
|
}
|
|
19612
|
+
let rootDirectoryUrl = rootDirectoryUrlForServer;
|
|
19579
19613
|
package_workspaces: {
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
const packageDirectoryUrl = lookupPackageDirectory(rootDirectoryUrl);
|
|
19614
|
+
const packageDirectoryUrl = lookupPackageDirectory(
|
|
19615
|
+
rootDirectoryUrlForServer,
|
|
19616
|
+
);
|
|
19584
19617
|
if (!packageDirectoryUrl) {
|
|
19585
19618
|
break package_workspaces;
|
|
19586
19619
|
}
|
|
19587
|
-
if (String(packageDirectoryUrl) === String(
|
|
19620
|
+
if (String(packageDirectoryUrl) === String(rootDirectoryUrlForServer)) {
|
|
19588
19621
|
break package_workspaces;
|
|
19589
19622
|
}
|
|
19590
|
-
|
|
19591
|
-
|
|
19592
|
-
|
|
19593
|
-
|
|
19594
|
-
|
|
19595
|
-
|
|
19596
|
-
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
|
|
19609
|
-
|
|
19623
|
+
rootDirectoryUrl = packageDirectoryUrl;
|
|
19624
|
+
if (
|
|
19625
|
+
String(firstExistingDirectoryUrl) === String(rootDirectoryUrlForServer)
|
|
19626
|
+
) {
|
|
19627
|
+
let packageContent;
|
|
19628
|
+
try {
|
|
19629
|
+
packageContent = JSON.parse(
|
|
19630
|
+
readFileSync(new URL("package.json", packageDirectoryUrl), "utf8"),
|
|
19631
|
+
);
|
|
19632
|
+
} catch {
|
|
19633
|
+
break package_workspaces;
|
|
19634
|
+
}
|
|
19635
|
+
const { workspaces } = packageContent;
|
|
19636
|
+
if (Array.isArray(workspaces)) {
|
|
19637
|
+
for (const workspace of workspaces) {
|
|
19638
|
+
const workspaceUrlObject = new URL(workspace, packageDirectoryUrl);
|
|
19639
|
+
const workspaceUrl = workspaceUrlObject.href;
|
|
19640
|
+
if (workspaceUrl.endsWith("*")) {
|
|
19641
|
+
const directoryUrl = ensurePathnameTrailingSlash(
|
|
19642
|
+
workspaceUrl.slice(0, -1),
|
|
19643
|
+
);
|
|
19644
|
+
fileUrls.push(new URL(directoryUrl));
|
|
19645
|
+
} else {
|
|
19646
|
+
fileUrls.push(ensurePathnameTrailingSlash(workspaceUrlObject));
|
|
19647
|
+
}
|
|
19610
19648
|
}
|
|
19611
19649
|
}
|
|
19612
19650
|
}
|
|
@@ -19630,29 +19668,37 @@ const generateDirectoryContentItems = (directoryUrl, rootDirectoryUrl) => {
|
|
|
19630
19668
|
sortedUrl,
|
|
19631
19669
|
firstExistingDirectoryUrl,
|
|
19632
19670
|
);
|
|
19633
|
-
const
|
|
19671
|
+
const fileUrlRelativeToServer = urlToRelativeUrl(
|
|
19672
|
+
sortedUrl,
|
|
19673
|
+
rootDirectoryUrlForServer,
|
|
19674
|
+
);
|
|
19634
19675
|
const type = fileUrlRelativeToParent.endsWith("/") ? "dir" : "file";
|
|
19635
19676
|
items.push({
|
|
19636
19677
|
type,
|
|
19637
19678
|
fileUrlRelativeToParent,
|
|
19638
|
-
|
|
19679
|
+
fileUrlRelativeToServer,
|
|
19639
19680
|
});
|
|
19640
19681
|
}
|
|
19682
|
+
items.rootDirectoryUrlForServer = rootDirectoryUrlForServer;
|
|
19641
19683
|
items.rootDirectoryUrl = rootDirectoryUrl;
|
|
19642
19684
|
items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
|
|
19643
19685
|
return items;
|
|
19644
19686
|
};
|
|
19645
19687
|
const generateDirectoryContent = (directoryContentItems) => {
|
|
19646
19688
|
if (directoryContentItems.length === 0) {
|
|
19647
|
-
return `<p>Directory is empty</p>`;
|
|
19689
|
+
return `<p class="directory_empty_message">Directory is empty</p>`;
|
|
19648
19690
|
}
|
|
19649
19691
|
let html = `<ul class="directory_content">`;
|
|
19650
19692
|
for (const directoryContentItem of directoryContentItems) {
|
|
19651
|
-
const { type, fileUrlRelativeToParent,
|
|
19693
|
+
const { type, fileUrlRelativeToParent, fileUrlRelativeToServer } =
|
|
19652
19694
|
directoryContentItem;
|
|
19695
|
+
let href = fileUrlRelativeToServer;
|
|
19696
|
+
if (href === "") {
|
|
19697
|
+
href = `${directoryContentMagicName}`;
|
|
19698
|
+
}
|
|
19653
19699
|
html += `
|
|
19654
19700
|
<li class="directory_child" data-type="${type}">
|
|
19655
|
-
<a href="/${
|
|
19701
|
+
<a href="/${href}">${fileUrlRelativeToParent}</a>
|
|
19656
19702
|
</li>`;
|
|
19657
19703
|
}
|
|
19658
19704
|
html += `\n </ul>`;
|
|
@@ -20827,6 +20873,11 @@ const jsenvPluginAutoreloadServer = ({
|
|
|
20827
20873
|
// are lost and sourcemap is considered as pruned
|
|
20828
20874
|
continue;
|
|
20829
20875
|
}
|
|
20876
|
+
if (lastReferenceFromOther.type === "http_request") {
|
|
20877
|
+
// no need to tell client to reload when a http request is pruned
|
|
20878
|
+
// happens when reloading the current html page for instance
|
|
20879
|
+
continue;
|
|
20880
|
+
}
|
|
20830
20881
|
const { ownerUrlInfo } = lastReferenceFromOther;
|
|
20831
20882
|
if (!ownerUrlInfo.isUsed()) {
|
|
20832
20883
|
continue;
|
package/package.json
CHANGED
|
@@ -10,9 +10,9 @@ export const createEventEmitter = () => {
|
|
|
10
10
|
callbackSet.delete(callback);
|
|
11
11
|
};
|
|
12
12
|
const emit = (...args) => {
|
|
13
|
-
|
|
13
|
+
for (const callback of callbackSet) {
|
|
14
14
|
callback(...args);
|
|
15
|
-
}
|
|
15
|
+
}
|
|
16
16
|
};
|
|
17
17
|
return { on, off, emit };
|
|
18
18
|
};
|
|
@@ -22,7 +22,7 @@ export const createDependencies = (ownerUrlInfo) => {
|
|
|
22
22
|
|
|
23
23
|
const stopCollecting = () => {
|
|
24
24
|
for (const prevReferenceToOther of prevReferenceToOthersSet) {
|
|
25
|
-
|
|
25
|
+
checkForDependencyRemovalEffects(prevReferenceToOther);
|
|
26
26
|
}
|
|
27
27
|
prevReferenceToOthersSet.clear();
|
|
28
28
|
};
|
|
@@ -527,7 +527,7 @@ ${ownerUrlInfo.url}`,
|
|
|
527
527
|
implicitRef.remove();
|
|
528
528
|
}
|
|
529
529
|
ownerUrlInfo.referenceToOthersSet.delete(reference);
|
|
530
|
-
return
|
|
530
|
+
return checkForDependencyRemovalEffects(reference);
|
|
531
531
|
};
|
|
532
532
|
|
|
533
533
|
const canAddOrRemoveReference = (reference) => {
|
|
@@ -556,7 +556,7 @@ const canAddOrRemoveReference = (reference) => {
|
|
|
556
556
|
return false;
|
|
557
557
|
};
|
|
558
558
|
|
|
559
|
-
const
|
|
559
|
+
const checkForDependencyRemovalEffects = (reference) => {
|
|
560
560
|
const { ownerUrlInfo } = reference;
|
|
561
561
|
const { referenceToOthersSet } = ownerUrlInfo;
|
|
562
562
|
if (reference.isImplicit && !reference.isInline) {
|
|
@@ -591,6 +591,7 @@ const applyDependencyRemovalEffects = (reference) => {
|
|
|
591
591
|
referencedUrlInfo.referenceFromOthersSet.delete(reference);
|
|
592
592
|
|
|
593
593
|
let firstReferenceFromOther;
|
|
594
|
+
let wasInlined;
|
|
594
595
|
for (const referenceFromOther of referencedUrlInfo.referenceFromOthersSet) {
|
|
595
596
|
if (referenceFromOther.urlInfo !== referencedUrlInfo) {
|
|
596
597
|
continue;
|
|
@@ -605,7 +606,8 @@ const applyDependencyRemovalEffects = (reference) => {
|
|
|
605
606
|
if (referenceFromOther.type === "http_request") {
|
|
606
607
|
continue;
|
|
607
608
|
}
|
|
608
|
-
|
|
609
|
+
wasInlined = referenceFromOther.gotInlined();
|
|
610
|
+
if (wasInlined) {
|
|
609
611
|
// the url info was inlined, an other reference is required
|
|
610
612
|
// to consider the non-inlined urlInfo as used
|
|
611
613
|
continue;
|
|
@@ -623,6 +625,9 @@ const applyDependencyRemovalEffects = (reference) => {
|
|
|
623
625
|
}
|
|
624
626
|
return false;
|
|
625
627
|
}
|
|
628
|
+
if (wasInlined) {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
626
631
|
// referencedUrlInfo.firstReference = null;
|
|
627
632
|
// referencedUrlInfo.lastReference = null;
|
|
628
633
|
referencedUrlInfo.onDereferenced(reference);
|
|
@@ -238,6 +238,11 @@ export const jsenvPluginAutoreloadServer = ({
|
|
|
238
238
|
// are lost and sourcemap is considered as pruned
|
|
239
239
|
continue;
|
|
240
240
|
}
|
|
241
|
+
if (lastReferenceFromOther.type === "http_request") {
|
|
242
|
+
// no need to tell client to reload when a http request is pruned
|
|
243
|
+
// happens when reloading the current html page for instance
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
241
246
|
const { ownerUrlInfo } = lastReferenceFromOther;
|
|
242
247
|
if (!ownerUrlInfo.isUsed()) {
|
|
243
248
|
continue;
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
No entry on the filesystem for <code>/${fileRelativeUrl}</code> (at
|
|
46
46
|
${fileUrl})
|
|
47
47
|
<br />
|
|
48
|
-
Content of
|
|
48
|
+
Content of first ancestor directory is listed below:
|
|
49
49
|
</span>
|
|
50
50
|
</p>
|
|
51
51
|
<h1 class="directory_nav">${ancestorDirectoryNav}</h1>
|
|
@@ -8,6 +8,7 @@ import { realpathSync } from "node:fs";
|
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
9
|
|
|
10
10
|
export const jsenvPluginFsRedirection = ({
|
|
11
|
+
directoryContentMagicName,
|
|
11
12
|
magicExtensions = ["inherit", ".js"],
|
|
12
13
|
magicDirectoryIndex = true,
|
|
13
14
|
preserveSymlinks = false,
|
|
@@ -30,10 +31,14 @@ export const jsenvPluginFsRedirection = ({
|
|
|
30
31
|
if (reference.subtype === "new_url_second_arg") {
|
|
31
32
|
return `ignore:${reference.url}`;
|
|
32
33
|
}
|
|
33
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
reference.specifierPathname.endsWith(`/${directoryContentMagicName}`)
|
|
36
|
+
) {
|
|
34
37
|
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
|
|
35
38
|
const directoryUrl = new URL(
|
|
36
|
-
reference.specifierPathname
|
|
39
|
+
reference.specifierPathname
|
|
40
|
+
.replace(`/${directoryContentMagicName}`, "/")
|
|
41
|
+
.slice(1),
|
|
37
42
|
rootDirectoryUrl,
|
|
38
43
|
).href;
|
|
39
44
|
return directoryUrl;
|
|
@@ -24,6 +24,7 @@ const htmlFileUrlForDirectory = new URL(
|
|
|
24
24
|
"./client/directory.html",
|
|
25
25
|
import.meta.url,
|
|
26
26
|
);
|
|
27
|
+
const directoryContentMagicName = "...";
|
|
27
28
|
|
|
28
29
|
export const jsenvPluginProtocolFile = ({
|
|
29
30
|
magicExtensions,
|
|
@@ -33,6 +34,7 @@ export const jsenvPluginProtocolFile = ({
|
|
|
33
34
|
}) => {
|
|
34
35
|
return [
|
|
35
36
|
jsenvPluginFsRedirection({
|
|
37
|
+
directoryContentMagicName,
|
|
36
38
|
magicExtensions,
|
|
37
39
|
magicDirectoryIndex,
|
|
38
40
|
preserveSymlinks,
|
|
@@ -72,8 +74,9 @@ export const jsenvPluginProtocolFile = ({
|
|
|
72
74
|
if (reference.original) {
|
|
73
75
|
const originalSpecifierPathname =
|
|
74
76
|
reference.original.specifierPathname;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
if (
|
|
78
|
+
originalSpecifierPathname.endsWith(`/${directoryContentMagicName}`)
|
|
79
|
+
) {
|
|
77
80
|
return originalSpecifierPathname;
|
|
78
81
|
}
|
|
79
82
|
}
|
|
@@ -179,11 +182,14 @@ const generateHtmlForDirectory = (directoryContentItems) => {
|
|
|
179
182
|
directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
180
183
|
|
|
181
184
|
const htmlForDirectory = String(readFileSync(htmlFileUrlForDirectory));
|
|
182
|
-
const directoryRelativeUrl = urlToRelativeUrl(directoryUrl, rootDirectoryUrl);
|
|
183
185
|
const replacers = {
|
|
184
186
|
directoryUrl,
|
|
185
187
|
directoryNav: () =>
|
|
186
|
-
generateDirectoryNav(
|
|
188
|
+
generateDirectoryNav(directoryUrl, {
|
|
189
|
+
rootDirectoryUrl,
|
|
190
|
+
rootDirectoryUrlForServer:
|
|
191
|
+
directoryContentItems.rootDirectoryUrlForServer,
|
|
192
|
+
}),
|
|
187
193
|
directoryContent: () => generateDirectoryContent(directoryContentItems),
|
|
188
194
|
};
|
|
189
195
|
const html = replacePlaceholders(htmlForDirectory, replacers);
|
|
@@ -213,44 +219,60 @@ const generateHtmlForENOENT = (
|
|
|
213
219
|
ancestorDirectoryUrl,
|
|
214
220
|
ancestorDirectoryRelativeUrl,
|
|
215
221
|
ancestorDirectoryNav: () =>
|
|
216
|
-
generateDirectoryNav(
|
|
222
|
+
generateDirectoryNav(ancestorDirectoryUrl, {
|
|
223
|
+
rootDirectoryUrl,
|
|
224
|
+
rootDirectoryUrlForServer:
|
|
225
|
+
directoryContentItems.rootDirectoryUrlForServer,
|
|
226
|
+
}),
|
|
217
227
|
ancestorDirectoryContent: () =>
|
|
218
228
|
generateDirectoryContent(directoryContentItems),
|
|
219
229
|
};
|
|
220
230
|
const html = replacePlaceholders(htmlFor404AndAncestorDir, replacers);
|
|
221
231
|
return html;
|
|
222
232
|
};
|
|
223
|
-
const generateDirectoryNav = (
|
|
233
|
+
const generateDirectoryNav = (
|
|
234
|
+
entryDirectoryUrl,
|
|
235
|
+
{ rootDirectoryUrl, rootDirectoryUrlForServer },
|
|
236
|
+
) => {
|
|
237
|
+
const entryDirectoryRelativeUrl = urlToRelativeUrl(
|
|
238
|
+
entryDirectoryUrl,
|
|
239
|
+
rootDirectoryUrl,
|
|
240
|
+
);
|
|
241
|
+
const isDir = entryDirectoryRelativeUrl.endsWith("/");
|
|
224
242
|
const rootDirectoryUrlName = urlToFilename(rootDirectoryUrl);
|
|
225
|
-
const relativeUrlWithRoot = relativeUrl
|
|
226
|
-
? `${rootDirectoryUrlName}/${relativeUrl}`
|
|
227
|
-
: `${rootDirectoryUrlName}/`;
|
|
228
|
-
const isDir = relativeUrlWithRoot.endsWith("/");
|
|
229
|
-
const parts = isDir
|
|
230
|
-
? relativeUrlWithRoot.slice(0, -1).split("/")
|
|
231
|
-
: relativeUrlWithRoot.split("/");
|
|
232
243
|
const items = [];
|
|
233
|
-
items.push({
|
|
234
|
-
href: "/",
|
|
235
|
-
text: "/",
|
|
236
|
-
});
|
|
237
244
|
let dirPartsHtml = "";
|
|
245
|
+
const parts =
|
|
246
|
+
`${rootDirectoryUrlName}/${entryDirectoryRelativeUrl.slice(0, -1)}`.split(
|
|
247
|
+
"/",
|
|
248
|
+
);
|
|
238
249
|
let i = 0;
|
|
239
250
|
while (i < parts.length) {
|
|
240
251
|
const part = parts[i];
|
|
241
|
-
const
|
|
252
|
+
const directoryRelativeUrl = `${parts.slice(1, i + 1).join("/")}`;
|
|
253
|
+
const directoryUrl =
|
|
254
|
+
directoryRelativeUrl === ""
|
|
255
|
+
? rootDirectoryUrl
|
|
256
|
+
: new URL(`${directoryRelativeUrl}/`, rootDirectoryUrl).href;
|
|
257
|
+
let href =
|
|
258
|
+
directoryUrl === rootDirectoryUrlForServer ||
|
|
259
|
+
urlIsInsideOf(directoryUrl, rootDirectoryUrlForServer)
|
|
260
|
+
? urlToRelativeUrl(directoryUrl, rootDirectoryUrlForServer)
|
|
261
|
+
: directoryUrl;
|
|
262
|
+
if (href === "") {
|
|
263
|
+
href = `/${directoryContentMagicName}`;
|
|
264
|
+
}
|
|
242
265
|
const text = part;
|
|
243
|
-
const isLastPart = i === parts.length - 1;
|
|
244
266
|
items.push({
|
|
245
267
|
href,
|
|
246
268
|
text,
|
|
247
|
-
isCurrent: isLastPart,
|
|
248
269
|
});
|
|
249
270
|
i++;
|
|
250
271
|
}
|
|
251
272
|
i = 0;
|
|
252
|
-
for (const { href, text
|
|
253
|
-
|
|
273
|
+
for (const { href, text } of items) {
|
|
274
|
+
const isLastPart = i === parts.length - 1;
|
|
275
|
+
if (isLastPart) {
|
|
254
276
|
dirPartsHtml += `
|
|
255
277
|
<span class="directory_nav_item" data-current>
|
|
256
278
|
${text}
|
|
@@ -261,10 +283,8 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
261
283
|
<a class="directory_nav_item" href="${href}">
|
|
262
284
|
${text}
|
|
263
285
|
</a>`;
|
|
264
|
-
|
|
265
|
-
dirPartsHtml += `
|
|
286
|
+
dirPartsHtml += `
|
|
266
287
|
<span class="directory_separator">/</span>`;
|
|
267
|
-
}
|
|
268
288
|
i++;
|
|
269
289
|
}
|
|
270
290
|
if (isDir) {
|
|
@@ -273,12 +293,15 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
273
293
|
}
|
|
274
294
|
return dirPartsHtml;
|
|
275
295
|
};
|
|
276
|
-
const generateDirectoryContentItems = (
|
|
296
|
+
const generateDirectoryContentItems = (
|
|
297
|
+
directoryUrl,
|
|
298
|
+
rootDirectoryUrlForServer,
|
|
299
|
+
) => {
|
|
277
300
|
let firstExistingDirectoryUrl = new URL("./", directoryUrl);
|
|
278
301
|
while (!existsSync(firstExistingDirectoryUrl)) {
|
|
279
302
|
firstExistingDirectoryUrl = new URL("../", firstExistingDirectoryUrl);
|
|
280
|
-
if (!urlIsInsideOf(firstExistingDirectoryUrl,
|
|
281
|
-
firstExistingDirectoryUrl = new URL(
|
|
303
|
+
if (!urlIsInsideOf(firstExistingDirectoryUrl, rootDirectoryUrlForServer)) {
|
|
304
|
+
firstExistingDirectoryUrl = new URL(rootDirectoryUrlForServer);
|
|
282
305
|
break;
|
|
283
306
|
}
|
|
284
307
|
}
|
|
@@ -288,37 +311,42 @@ const generateDirectoryContentItems = (directoryUrl, rootDirectoryUrl) => {
|
|
|
288
311
|
const fileUrlObject = new URL(filename, firstExistingDirectoryUrl);
|
|
289
312
|
fileUrls.push(fileUrlObject);
|
|
290
313
|
}
|
|
314
|
+
let rootDirectoryUrl = rootDirectoryUrlForServer;
|
|
291
315
|
package_workspaces: {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const packageDirectoryUrl = lookupPackageDirectory(rootDirectoryUrl);
|
|
316
|
+
const packageDirectoryUrl = lookupPackageDirectory(
|
|
317
|
+
rootDirectoryUrlForServer,
|
|
318
|
+
);
|
|
296
319
|
if (!packageDirectoryUrl) {
|
|
297
320
|
break package_workspaces;
|
|
298
321
|
}
|
|
299
|
-
if (String(packageDirectoryUrl) === String(
|
|
300
|
-
break package_workspaces;
|
|
301
|
-
}
|
|
302
|
-
let packageContent;
|
|
303
|
-
try {
|
|
304
|
-
packageContent = JSON.parse(
|
|
305
|
-
readFileSync(new URL("package.json", packageDirectoryUrl), "utf8"),
|
|
306
|
-
);
|
|
307
|
-
} catch {
|
|
322
|
+
if (String(packageDirectoryUrl) === String(rootDirectoryUrlForServer)) {
|
|
308
323
|
break package_workspaces;
|
|
309
324
|
}
|
|
310
|
-
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
325
|
+
rootDirectoryUrl = packageDirectoryUrl;
|
|
326
|
+
if (
|
|
327
|
+
String(firstExistingDirectoryUrl) === String(rootDirectoryUrlForServer)
|
|
328
|
+
) {
|
|
329
|
+
let packageContent;
|
|
330
|
+
try {
|
|
331
|
+
packageContent = JSON.parse(
|
|
332
|
+
readFileSync(new URL("package.json", packageDirectoryUrl), "utf8"),
|
|
333
|
+
);
|
|
334
|
+
} catch {
|
|
335
|
+
break package_workspaces;
|
|
336
|
+
}
|
|
337
|
+
const { workspaces } = packageContent;
|
|
338
|
+
if (Array.isArray(workspaces)) {
|
|
339
|
+
for (const workspace of workspaces) {
|
|
340
|
+
const workspaceUrlObject = new URL(workspace, packageDirectoryUrl);
|
|
341
|
+
const workspaceUrl = workspaceUrlObject.href;
|
|
342
|
+
if (workspaceUrl.endsWith("*")) {
|
|
343
|
+
const directoryUrl = ensurePathnameTrailingSlash(
|
|
344
|
+
workspaceUrl.slice(0, -1),
|
|
345
|
+
);
|
|
346
|
+
fileUrls.push(new URL(directoryUrl));
|
|
347
|
+
} else {
|
|
348
|
+
fileUrls.push(ensurePathnameTrailingSlash(workspaceUrlObject));
|
|
349
|
+
}
|
|
322
350
|
}
|
|
323
351
|
}
|
|
324
352
|
}
|
|
@@ -342,29 +370,37 @@ const generateDirectoryContentItems = (directoryUrl, rootDirectoryUrl) => {
|
|
|
342
370
|
sortedUrl,
|
|
343
371
|
firstExistingDirectoryUrl,
|
|
344
372
|
);
|
|
345
|
-
const
|
|
373
|
+
const fileUrlRelativeToServer = urlToRelativeUrl(
|
|
374
|
+
sortedUrl,
|
|
375
|
+
rootDirectoryUrlForServer,
|
|
376
|
+
);
|
|
346
377
|
const type = fileUrlRelativeToParent.endsWith("/") ? "dir" : "file";
|
|
347
378
|
items.push({
|
|
348
379
|
type,
|
|
349
380
|
fileUrlRelativeToParent,
|
|
350
|
-
|
|
381
|
+
fileUrlRelativeToServer,
|
|
351
382
|
});
|
|
352
383
|
}
|
|
384
|
+
items.rootDirectoryUrlForServer = rootDirectoryUrlForServer;
|
|
353
385
|
items.rootDirectoryUrl = rootDirectoryUrl;
|
|
354
386
|
items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
|
|
355
387
|
return items;
|
|
356
388
|
};
|
|
357
389
|
const generateDirectoryContent = (directoryContentItems) => {
|
|
358
390
|
if (directoryContentItems.length === 0) {
|
|
359
|
-
return `<p>Directory is empty</p>`;
|
|
391
|
+
return `<p class="directory_empty_message">Directory is empty</p>`;
|
|
360
392
|
}
|
|
361
393
|
let html = `<ul class="directory_content">`;
|
|
362
394
|
for (const directoryContentItem of directoryContentItems) {
|
|
363
|
-
const { type, fileUrlRelativeToParent,
|
|
395
|
+
const { type, fileUrlRelativeToParent, fileUrlRelativeToServer } =
|
|
364
396
|
directoryContentItem;
|
|
397
|
+
let href = fileUrlRelativeToServer;
|
|
398
|
+
if (href === "") {
|
|
399
|
+
href = `${directoryContentMagicName}`;
|
|
400
|
+
}
|
|
365
401
|
html += `
|
|
366
402
|
<li class="directory_child" data-type="${type}">
|
|
367
|
-
<a href="/${
|
|
403
|
+
<a href="/${href}">${fileUrlRelativeToParent}</a>
|
|
368
404
|
</li>`;
|
|
369
405
|
}
|
|
370
406
|
html += `\n </ul>`;
|