@jsenv/core 39.7.6 → 39.8.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
CHANGED
|
@@ -3,7 +3,7 @@ import os, { networkInterfaces } from "node:os";
|
|
|
3
3
|
import tty from "node:tty";
|
|
4
4
|
import stringWidth from "string-width";
|
|
5
5
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
6
|
-
import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFileSync, writeFileSync as writeFileSync$1,
|
|
6
|
+
import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, unlinkSync, openSync, closeSync, readdirSync, rmdirSync, mkdirSync, readFileSync, writeFileSync as writeFileSync$1, unlink, rmdir, watch, createReadStream, readFile, existsSync, realpathSync } from "node:fs";
|
|
7
7
|
import { extname } from "node:path";
|
|
8
8
|
import crypto, { createHash } from "node:crypto";
|
|
9
9
|
import cluster from "node:cluster";
|
|
@@ -2058,6 +2058,42 @@ const extractDriveLetter = (resource) => {
|
|
|
2058
2058
|
return null;
|
|
2059
2059
|
};
|
|
2060
2060
|
|
|
2061
|
+
const getParentDirectoryUrl = (url) => {
|
|
2062
|
+
if (url.startsWith("file://")) {
|
|
2063
|
+
// With node.js new URL('../', 'file:///C:/').href
|
|
2064
|
+
// returns "file:///C:/" instead of "file:///"
|
|
2065
|
+
const resource = url.slice("file://".length);
|
|
2066
|
+
const slashLastIndex = resource.lastIndexOf("/");
|
|
2067
|
+
if (slashLastIndex === -1) {
|
|
2068
|
+
return url;
|
|
2069
|
+
}
|
|
2070
|
+
const lastCharIndex = resource.length - 1;
|
|
2071
|
+
if (slashLastIndex === lastCharIndex) {
|
|
2072
|
+
const slashBeforeLastIndex = resource.lastIndexOf(
|
|
2073
|
+
"/",
|
|
2074
|
+
slashLastIndex - 1,
|
|
2075
|
+
);
|
|
2076
|
+
if (slashBeforeLastIndex === -1) {
|
|
2077
|
+
return url;
|
|
2078
|
+
}
|
|
2079
|
+
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
|
|
2080
|
+
}
|
|
2081
|
+
return `file://${resource.slice(0, slashLastIndex + 1)}`;
|
|
2082
|
+
}
|
|
2083
|
+
return new URL(url.endsWith("/") ? "../" : "./", url).href;
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
const findAncestorDirectoryUrl = (url, callback) => {
|
|
2087
|
+
url = String(url);
|
|
2088
|
+
while (url !== "file:///") {
|
|
2089
|
+
if (callback(url)) {
|
|
2090
|
+
return url;
|
|
2091
|
+
}
|
|
2092
|
+
url = getParentDirectoryUrl(url);
|
|
2093
|
+
}
|
|
2094
|
+
return null;
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2061
2097
|
const createCallbackListNotifiedOnce = () => {
|
|
2062
2098
|
let callbacks = [];
|
|
2063
2099
|
let status = "waiting";
|
|
@@ -3610,7 +3646,284 @@ const normalizeMediaType = (value) => {
|
|
|
3610
3646
|
return value;
|
|
3611
3647
|
};
|
|
3612
3648
|
|
|
3613
|
-
const
|
|
3649
|
+
const removeEntrySync = (
|
|
3650
|
+
source,
|
|
3651
|
+
{
|
|
3652
|
+
allowUseless = false,
|
|
3653
|
+
recursive = false,
|
|
3654
|
+
maxRetries = 3,
|
|
3655
|
+
retryDelay = 100,
|
|
3656
|
+
onlyContent = false,
|
|
3657
|
+
} = {},
|
|
3658
|
+
) => {
|
|
3659
|
+
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
3660
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
3661
|
+
nullIfNotFound: true,
|
|
3662
|
+
followLink: false,
|
|
3663
|
+
});
|
|
3664
|
+
if (!sourceStats) {
|
|
3665
|
+
if (allowUseless) {
|
|
3666
|
+
return;
|
|
3667
|
+
}
|
|
3668
|
+
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
|
|
3672
|
+
// FIFO and socket are ignored, not sure what they are exactly and what to do with them
|
|
3673
|
+
// other libraries ignore them, let's do the same.
|
|
3674
|
+
if (
|
|
3675
|
+
sourceStats.isFile() ||
|
|
3676
|
+
sourceStats.isSymbolicLink() ||
|
|
3677
|
+
sourceStats.isCharacterDevice() ||
|
|
3678
|
+
sourceStats.isBlockDevice()
|
|
3679
|
+
) {
|
|
3680
|
+
removeNonDirectory$1(
|
|
3681
|
+
sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl);
|
|
3682
|
+
} else if (sourceStats.isDirectory()) {
|
|
3683
|
+
const directoryUrl = ensurePathnameTrailingSlash(sourceUrl);
|
|
3684
|
+
removeDirectorySync$1(directoryUrl, {
|
|
3685
|
+
recursive,
|
|
3686
|
+
maxRetries,
|
|
3687
|
+
retryDelay,
|
|
3688
|
+
onlyContent,
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
};
|
|
3692
|
+
|
|
3693
|
+
const removeNonDirectory$1 = (sourceUrl) => {
|
|
3694
|
+
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
3695
|
+
const attempt = () => {
|
|
3696
|
+
unlinkSyncNaive(sourcePath);
|
|
3697
|
+
};
|
|
3698
|
+
attempt();
|
|
3699
|
+
};
|
|
3700
|
+
|
|
3701
|
+
const unlinkSyncNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
|
|
3702
|
+
try {
|
|
3703
|
+
unlinkSync(sourcePath);
|
|
3704
|
+
} catch (error) {
|
|
3705
|
+
if (error.code === "ENOENT") {
|
|
3706
|
+
return;
|
|
3707
|
+
}
|
|
3708
|
+
if (
|
|
3709
|
+
handleTemporaryError &&
|
|
3710
|
+
(error.code === "EBUSY" ||
|
|
3711
|
+
error.code === "EMFILE" ||
|
|
3712
|
+
error.code === "ENFILE" ||
|
|
3713
|
+
error.code === "ENOENT")
|
|
3714
|
+
) {
|
|
3715
|
+
handleTemporaryError(error);
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3718
|
+
throw error;
|
|
3719
|
+
}
|
|
3720
|
+
};
|
|
3721
|
+
|
|
3722
|
+
const removeDirectorySync$1 = (
|
|
3723
|
+
rootDirectoryUrl,
|
|
3724
|
+
{ maxRetries, retryDelay, recursive, onlyContent },
|
|
3725
|
+
) => {
|
|
3726
|
+
const visit = (sourceUrl) => {
|
|
3727
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
3728
|
+
nullIfNotFound: true,
|
|
3729
|
+
followLink: false,
|
|
3730
|
+
});
|
|
3731
|
+
|
|
3732
|
+
// file/directory not found
|
|
3733
|
+
if (sourceStats === null) {
|
|
3734
|
+
return;
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
if (
|
|
3738
|
+
sourceStats.isFile() ||
|
|
3739
|
+
sourceStats.isCharacterDevice() ||
|
|
3740
|
+
sourceStats.isBlockDevice()
|
|
3741
|
+
) {
|
|
3742
|
+
visitFile(sourceUrl);
|
|
3743
|
+
} else if (sourceStats.isSymbolicLink()) {
|
|
3744
|
+
visitSymbolicLink(sourceUrl);
|
|
3745
|
+
} else if (sourceStats.isDirectory()) {
|
|
3746
|
+
visitDirectory(`${sourceUrl}/`);
|
|
3747
|
+
}
|
|
3748
|
+
};
|
|
3749
|
+
|
|
3750
|
+
const visitDirectory = (directoryUrl) => {
|
|
3751
|
+
const directoryPath = urlToFileSystemPath(directoryUrl);
|
|
3752
|
+
const optionsFromRecursive = recursive
|
|
3753
|
+
? {
|
|
3754
|
+
handleNotEmptyError: () => {
|
|
3755
|
+
removeDirectoryContent(directoryUrl);
|
|
3756
|
+
visitDirectory(directoryUrl);
|
|
3757
|
+
},
|
|
3758
|
+
}
|
|
3759
|
+
: {};
|
|
3760
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
3761
|
+
...optionsFromRecursive,
|
|
3762
|
+
// Workaround for https://github.com/joyent/node/issues/4337
|
|
3763
|
+
...(process.platform === "win32"
|
|
3764
|
+
? {
|
|
3765
|
+
handlePermissionError: (error) => {
|
|
3766
|
+
console.error(
|
|
3767
|
+
`trying to fix windows EPERM after readir on ${directoryPath}`,
|
|
3768
|
+
);
|
|
3769
|
+
|
|
3770
|
+
let openOrCloseError;
|
|
3771
|
+
try {
|
|
3772
|
+
const fd = openSync(directoryPath);
|
|
3773
|
+
closeSync(fd);
|
|
3774
|
+
} catch (e) {
|
|
3775
|
+
openOrCloseError = e;
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
if (openOrCloseError) {
|
|
3779
|
+
if (openOrCloseError.code === "ENOENT") {
|
|
3780
|
+
return;
|
|
3781
|
+
}
|
|
3782
|
+
console.error(
|
|
3783
|
+
`error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
|
|
3784
|
+
);
|
|
3785
|
+
throw error;
|
|
3786
|
+
}
|
|
3787
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
3788
|
+
...optionsFromRecursive,
|
|
3789
|
+
});
|
|
3790
|
+
},
|
|
3791
|
+
}
|
|
3792
|
+
: {}),
|
|
3793
|
+
});
|
|
3794
|
+
};
|
|
3795
|
+
|
|
3796
|
+
const removeDirectoryContent = (directoryUrl) => {
|
|
3797
|
+
const entryNames = readdirSync(new URL(directoryUrl));
|
|
3798
|
+
for (const entryName of entryNames) {
|
|
3799
|
+
const url = resolveUrl$1(entryName, directoryUrl);
|
|
3800
|
+
visit(url);
|
|
3801
|
+
}
|
|
3802
|
+
};
|
|
3803
|
+
|
|
3804
|
+
const visitFile = (fileUrl) => {
|
|
3805
|
+
removeNonDirectory$1(fileUrl);
|
|
3806
|
+
};
|
|
3807
|
+
|
|
3808
|
+
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
3809
|
+
removeNonDirectory$1(symbolicLinkUrl);
|
|
3810
|
+
};
|
|
3811
|
+
|
|
3812
|
+
if (onlyContent) {
|
|
3813
|
+
removeDirectoryContent(rootDirectoryUrl);
|
|
3814
|
+
} else {
|
|
3815
|
+
visitDirectory(rootDirectoryUrl);
|
|
3816
|
+
}
|
|
3817
|
+
};
|
|
3818
|
+
|
|
3819
|
+
const removeDirectorySyncNaive = (
|
|
3820
|
+
directoryPath,
|
|
3821
|
+
{ handleNotEmptyError = null, handlePermissionError = null } = {},
|
|
3822
|
+
) => {
|
|
3823
|
+
try {
|
|
3824
|
+
rmdirSync(directoryPath);
|
|
3825
|
+
} catch (error) {
|
|
3826
|
+
if (handlePermissionError && error.code === "EPERM") {
|
|
3827
|
+
handlePermissionError(error);
|
|
3828
|
+
return;
|
|
3829
|
+
}
|
|
3830
|
+
if (error.code === "ENOENT") {
|
|
3831
|
+
return;
|
|
3832
|
+
}
|
|
3833
|
+
if (
|
|
3834
|
+
handleNotEmptyError &&
|
|
3835
|
+
// linux os
|
|
3836
|
+
(error.code === "ENOTEMPTY" ||
|
|
3837
|
+
// SunOS
|
|
3838
|
+
error.code === "EEXIST")
|
|
3839
|
+
) {
|
|
3840
|
+
handleNotEmptyError(error);
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3843
|
+
throw error;
|
|
3844
|
+
}
|
|
3845
|
+
};
|
|
3846
|
+
|
|
3847
|
+
const removeDirectorySync = (url, options = {}) => {
|
|
3848
|
+
return removeEntrySync(url, {
|
|
3849
|
+
...options,
|
|
3850
|
+
recursive: true,
|
|
3851
|
+
});
|
|
3852
|
+
};
|
|
3853
|
+
|
|
3854
|
+
const writeDirectorySync = (
|
|
3855
|
+
destination,
|
|
3856
|
+
{ recursive = true, allowUseless = false, force } = {},
|
|
3857
|
+
) => {
|
|
3858
|
+
const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
|
|
3859
|
+
const destinationPath = urlToFileSystemPath(destinationUrl);
|
|
3860
|
+
|
|
3861
|
+
let destinationStats;
|
|
3862
|
+
try {
|
|
3863
|
+
destinationStats = readEntryStatSync(destinationUrl, {
|
|
3864
|
+
nullIfNotFound: true,
|
|
3865
|
+
followLink: false,
|
|
3866
|
+
});
|
|
3867
|
+
} catch (e) {
|
|
3868
|
+
if (e.code === "ENOTDIR") {
|
|
3869
|
+
let previousNonDirUrl = destinationUrl;
|
|
3870
|
+
// we must try all parent directories as long as it fails with ENOTDIR
|
|
3871
|
+
findAncestorDirectoryUrl(destinationUrl, (ancestorUrl) => {
|
|
3872
|
+
try {
|
|
3873
|
+
statSync(new URL(ancestorUrl));
|
|
3874
|
+
return true;
|
|
3875
|
+
} catch (e) {
|
|
3876
|
+
if (e.code === "ENOTDIR") {
|
|
3877
|
+
previousNonDirUrl = ancestorUrl;
|
|
3878
|
+
return false;
|
|
3879
|
+
}
|
|
3880
|
+
throw e;
|
|
3881
|
+
}
|
|
3882
|
+
});
|
|
3883
|
+
if (force) {
|
|
3884
|
+
unlinkSync(
|
|
3885
|
+
new URL(
|
|
3886
|
+
previousNonDirUrl
|
|
3887
|
+
// remove trailing slash
|
|
3888
|
+
.slice(0, -1),
|
|
3889
|
+
),
|
|
3890
|
+
);
|
|
3891
|
+
} else {
|
|
3892
|
+
throw new Error(
|
|
3893
|
+
`cannot write directory at ${destinationPath} because there is a file at ${urlToFileSystemPath(
|
|
3894
|
+
previousNonDirUrl,
|
|
3895
|
+
)}`,
|
|
3896
|
+
);
|
|
3897
|
+
}
|
|
3898
|
+
} else {
|
|
3899
|
+
throw e;
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
|
|
3903
|
+
if (destinationStats) {
|
|
3904
|
+
if (destinationStats.isDirectory()) {
|
|
3905
|
+
if (allowUseless) {
|
|
3906
|
+
return;
|
|
3907
|
+
}
|
|
3908
|
+
throw new Error(`directory already exists at ${destinationPath}`);
|
|
3909
|
+
}
|
|
3910
|
+
const destinationType = statsToType(destinationStats);
|
|
3911
|
+
throw new Error(
|
|
3912
|
+
`cannot write directory at ${destinationPath} because there is a ${destinationType}`,
|
|
3913
|
+
);
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3916
|
+
try {
|
|
3917
|
+
mkdirSync(destinationPath, { recursive });
|
|
3918
|
+
} catch (error) {
|
|
3919
|
+
if (allowUseless && error.code === "EEXIST") {
|
|
3920
|
+
return;
|
|
3921
|
+
}
|
|
3922
|
+
throw error;
|
|
3923
|
+
}
|
|
3924
|
+
};
|
|
3925
|
+
|
|
3926
|
+
const writeFileSync = (destination, content = "", { force } = {}) => {
|
|
3614
3927
|
const destinationUrl = assertAndNormalizeFileUrl(destination);
|
|
3615
3928
|
const destinationUrlObject = new URL(destinationUrl);
|
|
3616
3929
|
if (content && content instanceof URL) {
|
|
@@ -3619,8 +3932,18 @@ const writeFileSync = (destination, content = "") => {
|
|
|
3619
3932
|
try {
|
|
3620
3933
|
writeFileSync$1(destinationUrlObject, content);
|
|
3621
3934
|
} catch (error) {
|
|
3622
|
-
if (error.code === "
|
|
3623
|
-
|
|
3935
|
+
if (error.code === "EISDIR") {
|
|
3936
|
+
// happens when directory existed but got deleted and now it's a file
|
|
3937
|
+
if (force) {
|
|
3938
|
+
removeDirectorySync(destinationUrlObject);
|
|
3939
|
+
writeFileSync$1(destinationUrlObject, content);
|
|
3940
|
+
} else {
|
|
3941
|
+
throw error;
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
|
3945
|
+
writeDirectorySync(new URL("./", destinationUrlObject), {
|
|
3946
|
+
force,
|
|
3624
3947
|
recursive: true,
|
|
3625
3948
|
});
|
|
3626
3949
|
writeFileSync$1(destinationUrlObject, content);
|
|
@@ -11159,39 +11482,10 @@ const jsenvPluginTranspilation = ({
|
|
|
11159
11482
|
};
|
|
11160
11483
|
|
|
11161
11484
|
const lookupPackageDirectory = (currentUrl) => {
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
if (existsSync(new URL(packageJsonFileUrl))) {
|
|
11167
|
-
return currentUrl;
|
|
11168
|
-
}
|
|
11169
|
-
return lookupPackageDirectory(getParentUrl$1(currentUrl));
|
|
11170
|
-
};
|
|
11171
|
-
|
|
11172
|
-
const getParentUrl$1 = (url) => {
|
|
11173
|
-
if (url.startsWith("file://")) {
|
|
11174
|
-
// With node.js new URL('../', 'file:///C:/').href
|
|
11175
|
-
// returns "file:///C:/" instead of "file:///"
|
|
11176
|
-
const resource = url.slice("file://".length);
|
|
11177
|
-
const slashLastIndex = resource.lastIndexOf("/");
|
|
11178
|
-
if (slashLastIndex === -1) {
|
|
11179
|
-
return url;
|
|
11180
|
-
}
|
|
11181
|
-
const lastCharIndex = resource.length - 1;
|
|
11182
|
-
if (slashLastIndex === lastCharIndex) {
|
|
11183
|
-
const slashBeforeLastIndex = resource.lastIndexOf(
|
|
11184
|
-
"/",
|
|
11185
|
-
slashLastIndex - 1,
|
|
11186
|
-
);
|
|
11187
|
-
if (slashBeforeLastIndex === -1) {
|
|
11188
|
-
return url;
|
|
11189
|
-
}
|
|
11190
|
-
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
|
|
11191
|
-
}
|
|
11192
|
-
return `file://${resource.slice(0, slashLastIndex + 1)}`;
|
|
11193
|
-
}
|
|
11194
|
-
return new URL(url.endsWith("/") ? "../" : "./", url).href;
|
|
11485
|
+
return findAncestorDirectoryUrl(currentUrl, (ancestorDirectoryUrl) => {
|
|
11486
|
+
const potentialPackageJsonFileUrl = `${ancestorDirectoryUrl}package.json`;
|
|
11487
|
+
return existsSync(new URL(potentialPackageJsonFileUrl));
|
|
11488
|
+
});
|
|
11195
11489
|
};
|
|
11196
11490
|
|
|
11197
11491
|
const watchSourceFiles = (
|
|
@@ -14163,7 +14457,7 @@ const createUrlInfoTransformer = ({
|
|
|
14163
14457
|
contentIsInlined = false;
|
|
14164
14458
|
}
|
|
14165
14459
|
if (!contentIsInlined) {
|
|
14166
|
-
writeFileSync(new URL(generatedUrl), urlInfo.content);
|
|
14460
|
+
writeFileSync(new URL(generatedUrl), urlInfo.content, { force: true });
|
|
14167
14461
|
}
|
|
14168
14462
|
const { sourcemapGeneratedUrl, sourcemapReference } = urlInfo;
|
|
14169
14463
|
if (sourcemapGeneratedUrl && sourcemapReference) {
|
|
@@ -18959,6 +19253,7 @@ const jsenvPluginProtocolFile = ({
|
|
|
18959
19253
|
if (!urlInfo.url.startsWith("file:")) {
|
|
18960
19254
|
return null;
|
|
18961
19255
|
}
|
|
19256
|
+
const { rootDirectoryUrl } = urlInfo.context;
|
|
18962
19257
|
const generateContent = () => {
|
|
18963
19258
|
const urlObject = new URL(urlInfo.url);
|
|
18964
19259
|
const { firstReference } = urlInfo;
|
|
@@ -18977,11 +19272,12 @@ const jsenvPluginProtocolFile = ({
|
|
|
18977
19272
|
: false;
|
|
18978
19273
|
if (acceptsHtml) {
|
|
18979
19274
|
firstReference.expectedType = "html";
|
|
18980
|
-
const
|
|
18981
|
-
|
|
18982
|
-
|
|
18983
|
-
|
|
19275
|
+
const directoryUrl = urlObject.href;
|
|
19276
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
19277
|
+
directoryUrl,
|
|
19278
|
+
rootDirectoryUrl,
|
|
18984
19279
|
);
|
|
19280
|
+
const html = generateHtmlForDirectory(directoryContentItems);
|
|
18985
19281
|
return {
|
|
18986
19282
|
type: "html",
|
|
18987
19283
|
contentType: "text/html",
|
|
@@ -19014,32 +19310,13 @@ const jsenvPluginProtocolFile = ({
|
|
|
19014
19310
|
if (e.code !== "ENOENT") {
|
|
19015
19311
|
throw e;
|
|
19016
19312
|
}
|
|
19017
|
-
const
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
firstExistingAncestorDirectoryUrl = new URL(
|
|
19021
|
-
"../",
|
|
19022
|
-
firstExistingAncestorDirectoryUrl,
|
|
19023
|
-
);
|
|
19024
|
-
if (
|
|
19025
|
-
!urlIsInsideOf(
|
|
19026
|
-
firstExistingAncestorDirectoryUrl,
|
|
19027
|
-
rootDirectoryUrl,
|
|
19028
|
-
)
|
|
19029
|
-
) {
|
|
19030
|
-
firstExistingAncestorDirectoryUrl = rootDirectoryUrl;
|
|
19031
|
-
break;
|
|
19032
|
-
}
|
|
19033
|
-
}
|
|
19034
|
-
|
|
19035
|
-
const firstExistingAncestorDirectoryContent = readdirSync(
|
|
19036
|
-
new URL(firstExistingAncestorDirectoryUrl),
|
|
19313
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
19314
|
+
urlInfo.url,
|
|
19315
|
+
rootDirectoryUrl,
|
|
19037
19316
|
);
|
|
19038
19317
|
const html = generateHtmlForENOENT(
|
|
19039
19318
|
urlInfo.url,
|
|
19040
|
-
|
|
19041
|
-
firstExistingAncestorDirectoryUrl,
|
|
19042
|
-
urlInfo.context.rootDirectoryUrl,
|
|
19319
|
+
directoryContentItems,
|
|
19043
19320
|
directoryListingUrlMocks,
|
|
19044
19321
|
);
|
|
19045
19322
|
return {
|
|
@@ -19058,11 +19335,9 @@ const jsenvPluginProtocolFile = ({
|
|
|
19058
19335
|
];
|
|
19059
19336
|
};
|
|
19060
19337
|
|
|
19061
|
-
const generateHtmlForDirectory = (
|
|
19062
|
-
directoryUrl
|
|
19063
|
-
|
|
19064
|
-
rootDirectoryUrl,
|
|
19065
|
-
) => {
|
|
19338
|
+
const generateHtmlForDirectory = (directoryContentItems) => {
|
|
19339
|
+
let directoryUrl = directoryContentItems.firstExistingDirectoryUrl;
|
|
19340
|
+
const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
|
|
19066
19341
|
directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
19067
19342
|
|
|
19068
19343
|
const htmlForDirectory = String(readFileSync(htmlFileUrlForDirectory));
|
|
@@ -19071,23 +19346,19 @@ const generateHtmlForDirectory = (
|
|
|
19071
19346
|
directoryUrl,
|
|
19072
19347
|
directoryNav: () =>
|
|
19073
19348
|
generateDirectoryNav(directoryRelativeUrl, rootDirectoryUrl),
|
|
19074
|
-
directoryContent: () =>
|
|
19075
|
-
generateDirectoryContent(
|
|
19076
|
-
directoryContentArray,
|
|
19077
|
-
directoryUrl,
|
|
19078
|
-
rootDirectoryUrl,
|
|
19079
|
-
),
|
|
19349
|
+
directoryContent: () => generateDirectoryContent(directoryContentItems),
|
|
19080
19350
|
};
|
|
19081
19351
|
const html = replacePlaceholders$1(htmlForDirectory, replacers);
|
|
19082
19352
|
return html;
|
|
19083
19353
|
};
|
|
19084
19354
|
const generateHtmlForENOENT = (
|
|
19085
19355
|
url,
|
|
19086
|
-
|
|
19087
|
-
ancestorDirectoryUrl,
|
|
19088
|
-
rootDirectoryUrl,
|
|
19356
|
+
directoryContentItems,
|
|
19089
19357
|
directoryListingUrlMocks,
|
|
19090
19358
|
) => {
|
|
19359
|
+
const ancestorDirectoryUrl = directoryContentItems.firstExistingDirectoryUrl;
|
|
19360
|
+
const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
|
|
19361
|
+
|
|
19091
19362
|
const htmlFor404AndAncestorDir = String(
|
|
19092
19363
|
readFileSync(html404AndAncestorDirFileUrl),
|
|
19093
19364
|
);
|
|
@@ -19106,11 +19377,7 @@ const generateHtmlForENOENT = (
|
|
|
19106
19377
|
ancestorDirectoryNav: () =>
|
|
19107
19378
|
generateDirectoryNav(ancestorDirectoryRelativeUrl, rootDirectoryUrl),
|
|
19108
19379
|
ancestorDirectoryContent: () =>
|
|
19109
|
-
generateDirectoryContent(
|
|
19110
|
-
ancestorDirectoryContentArray,
|
|
19111
|
-
ancestorDirectoryUrl,
|
|
19112
|
-
rootDirectoryUrl,
|
|
19113
|
-
),
|
|
19380
|
+
generateDirectoryContent(directoryContentItems),
|
|
19114
19381
|
};
|
|
19115
19382
|
const html = replacePlaceholders$1(htmlFor404AndAncestorDir, replacers);
|
|
19116
19383
|
return html;
|
|
@@ -19152,31 +19419,95 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
19152
19419
|
}
|
|
19153
19420
|
return dirPartsHtml;
|
|
19154
19421
|
};
|
|
19155
|
-
const
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
|
|
19159
|
-
)
|
|
19160
|
-
|
|
19161
|
-
|
|
19422
|
+
const generateDirectoryContentItems = (directoryUrl, rootDirectoryUrl) => {
|
|
19423
|
+
let firstExistingDirectoryUrl = new URL("./", directoryUrl);
|
|
19424
|
+
while (!existsSync(firstExistingDirectoryUrl)) {
|
|
19425
|
+
firstExistingDirectoryUrl = new URL("../", firstExistingDirectoryUrl);
|
|
19426
|
+
if (!urlIsInsideOf(firstExistingDirectoryUrl, rootDirectoryUrl)) {
|
|
19427
|
+
firstExistingDirectoryUrl = new URL(rootDirectoryUrl);
|
|
19428
|
+
break;
|
|
19429
|
+
}
|
|
19162
19430
|
}
|
|
19163
|
-
const
|
|
19431
|
+
const directoryContentArray = readdirSync(firstExistingDirectoryUrl);
|
|
19432
|
+
const fileUrls = [];
|
|
19164
19433
|
for (const filename of directoryContentArray) {
|
|
19165
|
-
const fileUrlObject = new URL(filename,
|
|
19166
|
-
|
|
19167
|
-
|
|
19434
|
+
const fileUrlObject = new URL(filename, firstExistingDirectoryUrl);
|
|
19435
|
+
fileUrls.push(fileUrlObject);
|
|
19436
|
+
}
|
|
19437
|
+
package_workspaces: {
|
|
19438
|
+
if (String(firstExistingDirectoryUrl) !== String(rootDirectoryUrl)) {
|
|
19439
|
+
break package_workspaces;
|
|
19440
|
+
}
|
|
19441
|
+
const packageDirectoryUrl = lookupPackageDirectory(rootDirectoryUrl);
|
|
19442
|
+
if (!packageDirectoryUrl) {
|
|
19443
|
+
break package_workspaces;
|
|
19444
|
+
}
|
|
19445
|
+
if (String(packageDirectoryUrl) === String(rootDirectoryUrl)) {
|
|
19446
|
+
break package_workspaces;
|
|
19447
|
+
}
|
|
19448
|
+
let packageContent;
|
|
19449
|
+
try {
|
|
19450
|
+
packageContent = JSON.parse(
|
|
19451
|
+
readFileSync(new URL("package.json", packageDirectoryUrl), "utf8"),
|
|
19452
|
+
);
|
|
19453
|
+
} catch {
|
|
19454
|
+
break package_workspaces;
|
|
19455
|
+
}
|
|
19456
|
+
const { workspaces } = packageContent;
|
|
19457
|
+
if (Array.isArray(workspaces)) {
|
|
19458
|
+
for (const workspace of workspaces) {
|
|
19459
|
+
const workspaceUrlObject = new URL(workspace, packageDirectoryUrl);
|
|
19460
|
+
const workspaceUrl = workspaceUrlObject.href;
|
|
19461
|
+
if (workspaceUrl.endsWith("*")) {
|
|
19462
|
+
const directoryUrl = ensurePathnameTrailingSlash(
|
|
19463
|
+
workspaceUrl.slice(0, -1),
|
|
19464
|
+
);
|
|
19465
|
+
fileUrls.push(new URL(directoryUrl));
|
|
19466
|
+
} else {
|
|
19467
|
+
fileUrls.push(ensurePathnameTrailingSlash(workspaceUrlObject));
|
|
19468
|
+
}
|
|
19469
|
+
}
|
|
19470
|
+
}
|
|
19471
|
+
}
|
|
19472
|
+
|
|
19473
|
+
const sortedUrls = [];
|
|
19474
|
+
for (let fileUrl of fileUrls) {
|
|
19475
|
+
if (lstatSync(fileUrl).isDirectory()) {
|
|
19476
|
+
sortedUrls.push(ensurePathnameTrailingSlash(fileUrl));
|
|
19168
19477
|
} else {
|
|
19169
|
-
|
|
19478
|
+
sortedUrls.push(fileUrl);
|
|
19170
19479
|
}
|
|
19171
19480
|
}
|
|
19172
|
-
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
const
|
|
19481
|
+
sortedUrls.sort((a, b) => {
|
|
19482
|
+
return comparePathnames(a.pathname, b.pathname);
|
|
19483
|
+
});
|
|
19484
|
+
|
|
19485
|
+
const items = [];
|
|
19486
|
+
for (const sortedUrl of sortedUrls) {
|
|
19487
|
+
const fileUrlRelativeToParent = urlToRelativeUrl(
|
|
19488
|
+
sortedUrl,
|
|
19489
|
+
firstExistingDirectoryUrl,
|
|
19490
|
+
);
|
|
19491
|
+
const fileUrlRelativeToRoot = urlToRelativeUrl(sortedUrl, rootDirectoryUrl);
|
|
19179
19492
|
const type = fileUrlRelativeToParent.endsWith("/") ? "dir" : "file";
|
|
19493
|
+
items.push({
|
|
19494
|
+
type,
|
|
19495
|
+
fileUrlRelativeToParent,
|
|
19496
|
+
fileUrlRelativeToRoot,
|
|
19497
|
+
});
|
|
19498
|
+
}
|
|
19499
|
+
items.rootDirectoryUrl = rootDirectoryUrl;
|
|
19500
|
+
items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
|
|
19501
|
+
return items;
|
|
19502
|
+
};
|
|
19503
|
+
const generateDirectoryContent = (directoryContentItems) => {
|
|
19504
|
+
if (directoryContentItems.length === 0) {
|
|
19505
|
+
return `<p>Directory is empty</p>`;
|
|
19506
|
+
}
|
|
19507
|
+
let html = `<ul class="directory_content">`;
|
|
19508
|
+
for (const directoryContentItem of directoryContentItems) {
|
|
19509
|
+
const { type, fileUrlRelativeToParent, fileUrlRelativeToRoot } =
|
|
19510
|
+
directoryContentItem;
|
|
19180
19511
|
html += `
|
|
19181
19512
|
<li class="directory_child" data-type="${type}">
|
|
19182
19513
|
<a href="/${fileUrlRelativeToRoot}">${fileUrlRelativeToParent}</a>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "39.
|
|
3
|
+
"version": "39.8.0",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
71
71
|
"@jsenv/abort": "4.3.0",
|
|
72
72
|
"@jsenv/ast": "6.4.1",
|
|
73
|
-
"@jsenv/filesystem": "4.
|
|
73
|
+
"@jsenv/filesystem": "4.12.0",
|
|
74
74
|
"@jsenv/humanize": "1.2.8",
|
|
75
75
|
"@jsenv/importmap": "1.2.1",
|
|
76
76
|
"@jsenv/integrity": "0.0.2",
|
|
@@ -1,37 +1,9 @@
|
|
|
1
|
+
import { findAncestorDirectoryUrl } from "@jsenv/filesystem";
|
|
1
2
|
import { existsSync } from "node:fs";
|
|
2
3
|
|
|
3
4
|
export const lookupPackageDirectory = (currentUrl) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (existsSync(new URL(packageJsonFileUrl))) {
|
|
9
|
-
return currentUrl;
|
|
10
|
-
}
|
|
11
|
-
return lookupPackageDirectory(getParentUrl(currentUrl));
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const getParentUrl = (url) => {
|
|
15
|
-
if (url.startsWith("file://")) {
|
|
16
|
-
// With node.js new URL('../', 'file:///C:/').href
|
|
17
|
-
// returns "file:///C:/" instead of "file:///"
|
|
18
|
-
const resource = url.slice("file://".length);
|
|
19
|
-
const slashLastIndex = resource.lastIndexOf("/");
|
|
20
|
-
if (slashLastIndex === -1) {
|
|
21
|
-
return url;
|
|
22
|
-
}
|
|
23
|
-
const lastCharIndex = resource.length - 1;
|
|
24
|
-
if (slashLastIndex === lastCharIndex) {
|
|
25
|
-
const slashBeforeLastIndex = resource.lastIndexOf(
|
|
26
|
-
"/",
|
|
27
|
-
slashLastIndex - 1,
|
|
28
|
-
);
|
|
29
|
-
if (slashBeforeLastIndex === -1) {
|
|
30
|
-
return url;
|
|
31
|
-
}
|
|
32
|
-
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
|
|
33
|
-
}
|
|
34
|
-
return `file://${resource.slice(0, slashLastIndex + 1)}`;
|
|
35
|
-
}
|
|
36
|
-
return new URL(url.endsWith("/") ? "../" : "./", url).href;
|
|
5
|
+
return findAncestorDirectoryUrl(currentUrl, (ancestorDirectoryUrl) => {
|
|
6
|
+
const potentialPackageJsonFileUrl = `${ancestorDirectoryUrl}package.json`;
|
|
7
|
+
return existsSync(new URL(potentialPackageJsonFileUrl));
|
|
8
|
+
});
|
|
37
9
|
};
|
|
@@ -275,7 +275,7 @@ export const createUrlInfoTransformer = ({
|
|
|
275
275
|
contentIsInlined = false;
|
|
276
276
|
}
|
|
277
277
|
if (!contentIsInlined) {
|
|
278
|
-
writeFileSync(new URL(generatedUrl), urlInfo.content);
|
|
278
|
+
writeFileSync(new URL(generatedUrl), urlInfo.content, { force: true });
|
|
279
279
|
}
|
|
280
280
|
const { sourcemapGeneratedUrl, sourcemapReference } = urlInfo;
|
|
281
281
|
if (sourcemapGeneratedUrl && sourcemapReference) {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@jsenv/urls";
|
|
12
12
|
import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
|
|
13
13
|
import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
|
|
14
|
+
import { lookupPackageDirectory } from "../../helpers/lookup_package_directory.js";
|
|
14
15
|
import { jsenvCoreDirectoryUrl } from "../../jsenv_core_directory_url.js";
|
|
15
16
|
import { jsenvPluginFsRedirection } from "./jsenv_plugin_fs_redirection.js";
|
|
16
17
|
|
|
@@ -83,6 +84,7 @@ export const jsenvPluginProtocolFile = ({
|
|
|
83
84
|
if (!urlInfo.url.startsWith("file:")) {
|
|
84
85
|
return null;
|
|
85
86
|
}
|
|
87
|
+
const { rootDirectoryUrl } = urlInfo.context;
|
|
86
88
|
const generateContent = () => {
|
|
87
89
|
const urlObject = new URL(urlInfo.url);
|
|
88
90
|
const { firstReference } = urlInfo;
|
|
@@ -101,11 +103,12 @@ export const jsenvPluginProtocolFile = ({
|
|
|
101
103
|
: false;
|
|
102
104
|
if (acceptsHtml) {
|
|
103
105
|
firstReference.expectedType = "html";
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
const directoryUrl = urlObject.href;
|
|
107
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
108
|
+
directoryUrl,
|
|
109
|
+
rootDirectoryUrl,
|
|
108
110
|
);
|
|
111
|
+
const html = generateHtmlForDirectory(directoryContentItems);
|
|
109
112
|
return {
|
|
110
113
|
type: "html",
|
|
111
114
|
contentType: "text/html",
|
|
@@ -138,32 +141,13 @@ export const jsenvPluginProtocolFile = ({
|
|
|
138
141
|
if (e.code !== "ENOENT") {
|
|
139
142
|
throw e;
|
|
140
143
|
}
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
firstExistingAncestorDirectoryUrl = new URL(
|
|
145
|
-
"../",
|
|
146
|
-
firstExistingAncestorDirectoryUrl,
|
|
147
|
-
);
|
|
148
|
-
if (
|
|
149
|
-
!urlIsInsideOf(
|
|
150
|
-
firstExistingAncestorDirectoryUrl,
|
|
151
|
-
rootDirectoryUrl,
|
|
152
|
-
)
|
|
153
|
-
) {
|
|
154
|
-
firstExistingAncestorDirectoryUrl = rootDirectoryUrl;
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const firstExistingAncestorDirectoryContent = readdirSync(
|
|
160
|
-
new URL(firstExistingAncestorDirectoryUrl),
|
|
144
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
145
|
+
urlInfo.url,
|
|
146
|
+
rootDirectoryUrl,
|
|
161
147
|
);
|
|
162
148
|
const html = generateHtmlForENOENT(
|
|
163
149
|
urlInfo.url,
|
|
164
|
-
|
|
165
|
-
firstExistingAncestorDirectoryUrl,
|
|
166
|
-
urlInfo.context.rootDirectoryUrl,
|
|
150
|
+
directoryContentItems,
|
|
167
151
|
directoryListingUrlMocks,
|
|
168
152
|
);
|
|
169
153
|
return {
|
|
@@ -182,11 +166,9 @@ export const jsenvPluginProtocolFile = ({
|
|
|
182
166
|
];
|
|
183
167
|
};
|
|
184
168
|
|
|
185
|
-
const generateHtmlForDirectory = (
|
|
186
|
-
directoryUrl
|
|
187
|
-
|
|
188
|
-
rootDirectoryUrl,
|
|
189
|
-
) => {
|
|
169
|
+
const generateHtmlForDirectory = (directoryContentItems) => {
|
|
170
|
+
let directoryUrl = directoryContentItems.firstExistingDirectoryUrl;
|
|
171
|
+
const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
|
|
190
172
|
directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
191
173
|
|
|
192
174
|
const htmlForDirectory = String(readFileSync(htmlFileUrlForDirectory));
|
|
@@ -195,23 +177,19 @@ const generateHtmlForDirectory = (
|
|
|
195
177
|
directoryUrl,
|
|
196
178
|
directoryNav: () =>
|
|
197
179
|
generateDirectoryNav(directoryRelativeUrl, rootDirectoryUrl),
|
|
198
|
-
directoryContent: () =>
|
|
199
|
-
generateDirectoryContent(
|
|
200
|
-
directoryContentArray,
|
|
201
|
-
directoryUrl,
|
|
202
|
-
rootDirectoryUrl,
|
|
203
|
-
),
|
|
180
|
+
directoryContent: () => generateDirectoryContent(directoryContentItems),
|
|
204
181
|
};
|
|
205
182
|
const html = replacePlaceholders(htmlForDirectory, replacers);
|
|
206
183
|
return html;
|
|
207
184
|
};
|
|
208
185
|
const generateHtmlForENOENT = (
|
|
209
186
|
url,
|
|
210
|
-
|
|
211
|
-
ancestorDirectoryUrl,
|
|
212
|
-
rootDirectoryUrl,
|
|
187
|
+
directoryContentItems,
|
|
213
188
|
directoryListingUrlMocks,
|
|
214
189
|
) => {
|
|
190
|
+
const ancestorDirectoryUrl = directoryContentItems.firstExistingDirectoryUrl;
|
|
191
|
+
const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
|
|
192
|
+
|
|
215
193
|
const htmlFor404AndAncestorDir = String(
|
|
216
194
|
readFileSync(html404AndAncestorDirFileUrl),
|
|
217
195
|
);
|
|
@@ -230,11 +208,7 @@ const generateHtmlForENOENT = (
|
|
|
230
208
|
ancestorDirectoryNav: () =>
|
|
231
209
|
generateDirectoryNav(ancestorDirectoryRelativeUrl, rootDirectoryUrl),
|
|
232
210
|
ancestorDirectoryContent: () =>
|
|
233
|
-
generateDirectoryContent(
|
|
234
|
-
ancestorDirectoryContentArray,
|
|
235
|
-
ancestorDirectoryUrl,
|
|
236
|
-
rootDirectoryUrl,
|
|
237
|
-
),
|
|
211
|
+
generateDirectoryContent(directoryContentItems),
|
|
238
212
|
};
|
|
239
213
|
const html = replacePlaceholders(htmlFor404AndAncestorDir, replacers);
|
|
240
214
|
return html;
|
|
@@ -276,31 +250,95 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
276
250
|
}
|
|
277
251
|
return dirPartsHtml;
|
|
278
252
|
};
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
)
|
|
284
|
-
|
|
285
|
-
|
|
253
|
+
const generateDirectoryContentItems = (directoryUrl, rootDirectoryUrl) => {
|
|
254
|
+
let firstExistingDirectoryUrl = new URL("./", directoryUrl);
|
|
255
|
+
while (!existsSync(firstExistingDirectoryUrl)) {
|
|
256
|
+
firstExistingDirectoryUrl = new URL("../", firstExistingDirectoryUrl);
|
|
257
|
+
if (!urlIsInsideOf(firstExistingDirectoryUrl, rootDirectoryUrl)) {
|
|
258
|
+
firstExistingDirectoryUrl = new URL(rootDirectoryUrl);
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
286
261
|
}
|
|
287
|
-
const
|
|
262
|
+
const directoryContentArray = readdirSync(firstExistingDirectoryUrl);
|
|
263
|
+
const fileUrls = [];
|
|
288
264
|
for (const filename of directoryContentArray) {
|
|
289
|
-
const fileUrlObject = new URL(filename,
|
|
290
|
-
|
|
291
|
-
|
|
265
|
+
const fileUrlObject = new URL(filename, firstExistingDirectoryUrl);
|
|
266
|
+
fileUrls.push(fileUrlObject);
|
|
267
|
+
}
|
|
268
|
+
package_workspaces: {
|
|
269
|
+
if (String(firstExistingDirectoryUrl) !== String(rootDirectoryUrl)) {
|
|
270
|
+
break package_workspaces;
|
|
271
|
+
}
|
|
272
|
+
const packageDirectoryUrl = lookupPackageDirectory(rootDirectoryUrl);
|
|
273
|
+
if (!packageDirectoryUrl) {
|
|
274
|
+
break package_workspaces;
|
|
275
|
+
}
|
|
276
|
+
if (String(packageDirectoryUrl) === String(rootDirectoryUrl)) {
|
|
277
|
+
break package_workspaces;
|
|
278
|
+
}
|
|
279
|
+
let packageContent;
|
|
280
|
+
try {
|
|
281
|
+
packageContent = JSON.parse(
|
|
282
|
+
readFileSync(new URL("package.json", packageDirectoryUrl), "utf8"),
|
|
283
|
+
);
|
|
284
|
+
} catch {
|
|
285
|
+
break package_workspaces;
|
|
286
|
+
}
|
|
287
|
+
const { workspaces } = packageContent;
|
|
288
|
+
if (Array.isArray(workspaces)) {
|
|
289
|
+
for (const workspace of workspaces) {
|
|
290
|
+
const workspaceUrlObject = new URL(workspace, packageDirectoryUrl);
|
|
291
|
+
const workspaceUrl = workspaceUrlObject.href;
|
|
292
|
+
if (workspaceUrl.endsWith("*")) {
|
|
293
|
+
const directoryUrl = ensurePathnameTrailingSlash(
|
|
294
|
+
workspaceUrl.slice(0, -1),
|
|
295
|
+
);
|
|
296
|
+
fileUrls.push(new URL(directoryUrl));
|
|
297
|
+
} else {
|
|
298
|
+
fileUrls.push(ensurePathnameTrailingSlash(workspaceUrlObject));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const sortedUrls = [];
|
|
305
|
+
for (let fileUrl of fileUrls) {
|
|
306
|
+
if (lstatSync(fileUrl).isDirectory()) {
|
|
307
|
+
sortedUrls.push(ensurePathnameTrailingSlash(fileUrl));
|
|
292
308
|
} else {
|
|
293
|
-
|
|
309
|
+
sortedUrls.push(fileUrl);
|
|
294
310
|
}
|
|
295
311
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const
|
|
312
|
+
sortedUrls.sort((a, b) => {
|
|
313
|
+
return comparePathnames(a.pathname, b.pathname);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const items = [];
|
|
317
|
+
for (const sortedUrl of sortedUrls) {
|
|
318
|
+
const fileUrlRelativeToParent = urlToRelativeUrl(
|
|
319
|
+
sortedUrl,
|
|
320
|
+
firstExistingDirectoryUrl,
|
|
321
|
+
);
|
|
322
|
+
const fileUrlRelativeToRoot = urlToRelativeUrl(sortedUrl, rootDirectoryUrl);
|
|
303
323
|
const type = fileUrlRelativeToParent.endsWith("/") ? "dir" : "file";
|
|
324
|
+
items.push({
|
|
325
|
+
type,
|
|
326
|
+
fileUrlRelativeToParent,
|
|
327
|
+
fileUrlRelativeToRoot,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
items.rootDirectoryUrl = rootDirectoryUrl;
|
|
331
|
+
items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
|
|
332
|
+
return items;
|
|
333
|
+
};
|
|
334
|
+
const generateDirectoryContent = (directoryContentItems) => {
|
|
335
|
+
if (directoryContentItems.length === 0) {
|
|
336
|
+
return `<p>Directory is empty</p>`;
|
|
337
|
+
}
|
|
338
|
+
let html = `<ul class="directory_content">`;
|
|
339
|
+
for (const directoryContentItem of directoryContentItems) {
|
|
340
|
+
const { type, fileUrlRelativeToParent, fileUrlRelativeToRoot } =
|
|
341
|
+
directoryContentItem;
|
|
304
342
|
html += `
|
|
305
343
|
<li class="directory_child" data-type="${type}">
|
|
306
344
|
<a href="/${fileUrlRelativeToRoot}">${fileUrlRelativeToParent}</a>
|