@jsenv/core 39.7.7 → 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,
|
|
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,30 +3646,9 @@ const normalizeMediaType = (value) => {
|
|
|
3610
3646
|
return value;
|
|
3611
3647
|
};
|
|
3612
3648
|
|
|
3613
|
-
const
|
|
3614
|
-
const destinationUrl = assertAndNormalizeFileUrl(destination);
|
|
3615
|
-
const destinationUrlObject = new URL(destinationUrl);
|
|
3616
|
-
if (content && content instanceof URL) {
|
|
3617
|
-
content = readFileSync(content);
|
|
3618
|
-
}
|
|
3619
|
-
try {
|
|
3620
|
-
writeFileSync$1(destinationUrlObject, content);
|
|
3621
|
-
} catch (error) {
|
|
3622
|
-
if (error.code === "ENOENT") {
|
|
3623
|
-
mkdirSync(new URL("./", destinationUrlObject), {
|
|
3624
|
-
recursive: true,
|
|
3625
|
-
});
|
|
3626
|
-
writeFileSync$1(destinationUrlObject, content);
|
|
3627
|
-
return;
|
|
3628
|
-
}
|
|
3629
|
-
throw error;
|
|
3630
|
-
}
|
|
3631
|
-
};
|
|
3632
|
-
|
|
3633
|
-
const removeEntry = async (
|
|
3649
|
+
const removeEntrySync = (
|
|
3634
3650
|
source,
|
|
3635
3651
|
{
|
|
3636
|
-
signal = new AbortController().signal,
|
|
3637
3652
|
allowUseless = false,
|
|
3638
3653
|
recursive = false,
|
|
3639
3654
|
maxRetries = 3,
|
|
@@ -3642,110 +3657,74 @@ const removeEntry = async (
|
|
|
3642
3657
|
} = {},
|
|
3643
3658
|
) => {
|
|
3644
3659
|
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
nullIfNotFound: true,
|
|
3653
|
-
followLink: false,
|
|
3654
|
-
});
|
|
3655
|
-
if (!sourceStats) {
|
|
3656
|
-
if (allowUseless) {
|
|
3657
|
-
return;
|
|
3658
|
-
}
|
|
3659
|
-
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
3660
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
3661
|
+
nullIfNotFound: true,
|
|
3662
|
+
followLink: false,
|
|
3663
|
+
});
|
|
3664
|
+
if (!sourceStats) {
|
|
3665
|
+
if (allowUseless) {
|
|
3666
|
+
return;
|
|
3660
3667
|
}
|
|
3668
|
+
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
3669
|
+
}
|
|
3661
3670
|
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
recursive,
|
|
3682
|
-
maxRetries,
|
|
3683
|
-
retryDelay,
|
|
3684
|
-
onlyContent,
|
|
3685
|
-
});
|
|
3686
|
-
}
|
|
3687
|
-
} finally {
|
|
3688
|
-
await removeOperation.end();
|
|
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
|
+
});
|
|
3689
3690
|
}
|
|
3690
3691
|
};
|
|
3691
3692
|
|
|
3692
|
-
const removeNonDirectory$1 = (sourceUrl
|
|
3693
|
+
const removeNonDirectory$1 = (sourceUrl) => {
|
|
3693
3694
|
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
3694
|
-
|
|
3695
|
-
let retryCount = 0;
|
|
3696
3695
|
const attempt = () => {
|
|
3697
|
-
|
|
3698
|
-
...(retryCount >= maxRetries
|
|
3699
|
-
? {}
|
|
3700
|
-
: {
|
|
3701
|
-
handleTemporaryError: async () => {
|
|
3702
|
-
retryCount++;
|
|
3703
|
-
return new Promise((resolve) => {
|
|
3704
|
-
setTimeout(() => {
|
|
3705
|
-
resolve(attempt());
|
|
3706
|
-
}, retryCount * retryDelay);
|
|
3707
|
-
});
|
|
3708
|
-
},
|
|
3709
|
-
}),
|
|
3710
|
-
});
|
|
3696
|
+
unlinkSyncNaive(sourcePath);
|
|
3711
3697
|
};
|
|
3712
|
-
|
|
3698
|
+
attempt();
|
|
3713
3699
|
};
|
|
3714
3700
|
|
|
3715
|
-
const
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
)
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
}
|
|
3735
|
-
});
|
|
3736
|
-
});
|
|
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
|
+
}
|
|
3737
3720
|
};
|
|
3738
3721
|
|
|
3739
|
-
const
|
|
3722
|
+
const removeDirectorySync$1 = (
|
|
3740
3723
|
rootDirectoryUrl,
|
|
3741
|
-
{
|
|
3724
|
+
{ maxRetries, retryDelay, recursive, onlyContent },
|
|
3742
3725
|
) => {
|
|
3743
|
-
const
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
const visit = async (sourceUrl) => {
|
|
3747
|
-
removeDirectoryOperation.throwIfAborted();
|
|
3748
|
-
const sourceStats = await readEntryStat(sourceUrl, {
|
|
3726
|
+
const visit = (sourceUrl) => {
|
|
3727
|
+
const sourceStats = readEntryStatSync(sourceUrl, {
|
|
3749
3728
|
nullIfNotFound: true,
|
|
3750
3729
|
followLink: false,
|
|
3751
3730
|
});
|
|
@@ -3760,31 +3739,30 @@ const removeDirectory = async (
|
|
|
3760
3739
|
sourceStats.isCharacterDevice() ||
|
|
3761
3740
|
sourceStats.isBlockDevice()
|
|
3762
3741
|
) {
|
|
3763
|
-
|
|
3742
|
+
visitFile(sourceUrl);
|
|
3764
3743
|
} else if (sourceStats.isSymbolicLink()) {
|
|
3765
|
-
|
|
3744
|
+
visitSymbolicLink(sourceUrl);
|
|
3766
3745
|
} else if (sourceStats.isDirectory()) {
|
|
3767
|
-
|
|
3746
|
+
visitDirectory(`${sourceUrl}/`);
|
|
3768
3747
|
}
|
|
3769
3748
|
};
|
|
3770
3749
|
|
|
3771
|
-
const visitDirectory =
|
|
3750
|
+
const visitDirectory = (directoryUrl) => {
|
|
3772
3751
|
const directoryPath = urlToFileSystemPath(directoryUrl);
|
|
3773
3752
|
const optionsFromRecursive = recursive
|
|
3774
3753
|
? {
|
|
3775
|
-
handleNotEmptyError:
|
|
3776
|
-
|
|
3777
|
-
|
|
3754
|
+
handleNotEmptyError: () => {
|
|
3755
|
+
removeDirectoryContent(directoryUrl);
|
|
3756
|
+
visitDirectory(directoryUrl);
|
|
3778
3757
|
},
|
|
3779
3758
|
}
|
|
3780
3759
|
: {};
|
|
3781
|
-
|
|
3782
|
-
await removeDirectoryNaive(directoryPath, {
|
|
3760
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
3783
3761
|
...optionsFromRecursive,
|
|
3784
3762
|
// Workaround for https://github.com/joyent/node/issues/4337
|
|
3785
3763
|
...(process.platform === "win32"
|
|
3786
3764
|
? {
|
|
3787
|
-
handlePermissionError:
|
|
3765
|
+
handlePermissionError: (error) => {
|
|
3788
3766
|
console.error(
|
|
3789
3767
|
`trying to fix windows EPERM after readir on ${directoryPath}`,
|
|
3790
3768
|
);
|
|
@@ -3806,8 +3784,7 @@ const removeDirectory = async (
|
|
|
3806
3784
|
);
|
|
3807
3785
|
throw error;
|
|
3808
3786
|
}
|
|
3809
|
-
|
|
3810
|
-
await removeDirectoryNaive(directoryPath, {
|
|
3787
|
+
removeDirectorySyncNaive(directoryPath, {
|
|
3811
3788
|
...optionsFromRecursive,
|
|
3812
3789
|
});
|
|
3813
3790
|
},
|
|
@@ -3816,70 +3793,170 @@ const removeDirectory = async (
|
|
|
3816
3793
|
});
|
|
3817
3794
|
};
|
|
3818
3795
|
|
|
3819
|
-
const removeDirectoryContent =
|
|
3820
|
-
|
|
3821
|
-
const
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
await visit(url);
|
|
3826
|
-
}),
|
|
3827
|
-
);
|
|
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
|
+
}
|
|
3828
3802
|
};
|
|
3829
3803
|
|
|
3830
|
-
const visitFile =
|
|
3831
|
-
|
|
3804
|
+
const visitFile = (fileUrl) => {
|
|
3805
|
+
removeNonDirectory$1(fileUrl);
|
|
3832
3806
|
};
|
|
3833
3807
|
|
|
3834
|
-
const visitSymbolicLink =
|
|
3835
|
-
|
|
3808
|
+
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
3809
|
+
removeNonDirectory$1(symbolicLinkUrl);
|
|
3836
3810
|
};
|
|
3837
3811
|
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
await visitDirectory(rootDirectoryUrl);
|
|
3843
|
-
}
|
|
3844
|
-
} finally {
|
|
3845
|
-
await removeDirectoryOperation.end();
|
|
3812
|
+
if (onlyContent) {
|
|
3813
|
+
removeDirectoryContent(rootDirectoryUrl);
|
|
3814
|
+
} else {
|
|
3815
|
+
visitDirectory(rootDirectoryUrl);
|
|
3846
3816
|
}
|
|
3847
3817
|
};
|
|
3848
3818
|
|
|
3849
|
-
const
|
|
3819
|
+
const removeDirectorySyncNaive = (
|
|
3850
3820
|
directoryPath,
|
|
3851
3821
|
{ handleNotEmptyError = null, handlePermissionError = null } = {},
|
|
3852
3822
|
) => {
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
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;
|
|
3870
3881
|
}
|
|
3882
|
+
});
|
|
3883
|
+
if (force) {
|
|
3884
|
+
unlinkSync(
|
|
3885
|
+
new URL(
|
|
3886
|
+
previousNonDirUrl
|
|
3887
|
+
// remove trailing slash
|
|
3888
|
+
.slice(0, -1),
|
|
3889
|
+
),
|
|
3890
|
+
);
|
|
3871
3891
|
} else {
|
|
3872
|
-
|
|
3892
|
+
throw new Error(
|
|
3893
|
+
`cannot write directory at ${destinationPath} because there is a file at ${urlToFileSystemPath(
|
|
3894
|
+
previousNonDirUrl,
|
|
3895
|
+
)}`,
|
|
3896
|
+
);
|
|
3873
3897
|
}
|
|
3874
|
-
}
|
|
3875
|
-
|
|
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
|
+
}
|
|
3876
3924
|
};
|
|
3877
3925
|
|
|
3878
|
-
|
|
3926
|
+
const writeFileSync = (destination, content = "", { force } = {}) => {
|
|
3927
|
+
const destinationUrl = assertAndNormalizeFileUrl(destination);
|
|
3928
|
+
const destinationUrlObject = new URL(destinationUrl);
|
|
3929
|
+
if (content && content instanceof URL) {
|
|
3930
|
+
content = readFileSync(content);
|
|
3931
|
+
}
|
|
3932
|
+
try {
|
|
3933
|
+
writeFileSync$1(destinationUrlObject, content);
|
|
3934
|
+
} catch (error) {
|
|
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,
|
|
3947
|
+
recursive: true,
|
|
3948
|
+
});
|
|
3949
|
+
writeFileSync$1(destinationUrlObject, content);
|
|
3950
|
+
return;
|
|
3951
|
+
}
|
|
3952
|
+
throw error;
|
|
3953
|
+
}
|
|
3954
|
+
};
|
|
3879
3955
|
|
|
3880
|
-
const
|
|
3956
|
+
const removeEntry = async (
|
|
3881
3957
|
source,
|
|
3882
3958
|
{
|
|
3959
|
+
signal = new AbortController().signal,
|
|
3883
3960
|
allowUseless = false,
|
|
3884
3961
|
recursive = false,
|
|
3885
3962
|
maxRetries = 3,
|
|
@@ -3888,74 +3965,110 @@ const removeEntrySync = (
|
|
|
3888
3965
|
} = {},
|
|
3889
3966
|
) => {
|
|
3890
3967
|
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3968
|
+
|
|
3969
|
+
const removeOperation = Abort.startOperation();
|
|
3970
|
+
removeOperation.addAbortSignal(signal);
|
|
3971
|
+
|
|
3972
|
+
try {
|
|
3973
|
+
removeOperation.throwIfAborted();
|
|
3974
|
+
const sourceStats = await readEntryStat(sourceUrl, {
|
|
3975
|
+
nullIfNotFound: true,
|
|
3976
|
+
followLink: false,
|
|
3977
|
+
});
|
|
3978
|
+
if (!sourceStats) {
|
|
3979
|
+
if (allowUseless) {
|
|
3980
|
+
return;
|
|
3981
|
+
}
|
|
3982
|
+
throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
|
|
3898
3983
|
}
|
|
3899
|
-
|
|
3984
|
+
|
|
3985
|
+
// https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
|
|
3986
|
+
// FIFO and socket are ignored, not sure what they are exactly and what to do with them
|
|
3987
|
+
// other libraries ignore them, let's do the same.
|
|
3988
|
+
if (
|
|
3989
|
+
sourceStats.isFile() ||
|
|
3990
|
+
sourceStats.isSymbolicLink() ||
|
|
3991
|
+
sourceStats.isCharacterDevice() ||
|
|
3992
|
+
sourceStats.isBlockDevice()
|
|
3993
|
+
) {
|
|
3994
|
+
await removeNonDirectory(
|
|
3995
|
+
sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl,
|
|
3996
|
+
{
|
|
3997
|
+
maxRetries,
|
|
3998
|
+
retryDelay,
|
|
3999
|
+
},
|
|
4000
|
+
);
|
|
4001
|
+
} else if (sourceStats.isDirectory()) {
|
|
4002
|
+
await removeDirectory(ensurePathnameTrailingSlash(sourceUrl), {
|
|
4003
|
+
signal: removeOperation.signal,
|
|
4004
|
+
recursive,
|
|
4005
|
+
maxRetries,
|
|
4006
|
+
retryDelay,
|
|
4007
|
+
onlyContent,
|
|
4008
|
+
});
|
|
4009
|
+
}
|
|
4010
|
+
} finally {
|
|
4011
|
+
await removeOperation.end();
|
|
3900
4012
|
}
|
|
4013
|
+
};
|
|
3901
4014
|
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
4015
|
+
const removeNonDirectory = (sourceUrl, { maxRetries, retryDelay }) => {
|
|
4016
|
+
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
4017
|
+
|
|
4018
|
+
let retryCount = 0;
|
|
4019
|
+
const attempt = () => {
|
|
4020
|
+
return unlinkNaive(sourcePath, {
|
|
4021
|
+
...(retryCount >= maxRetries
|
|
4022
|
+
? {}
|
|
4023
|
+
: {
|
|
4024
|
+
handleTemporaryError: async () => {
|
|
4025
|
+
retryCount++;
|
|
4026
|
+
return new Promise((resolve) => {
|
|
4027
|
+
setTimeout(() => {
|
|
4028
|
+
resolve(attempt());
|
|
4029
|
+
}, retryCount * retryDelay);
|
|
4030
|
+
});
|
|
4031
|
+
},
|
|
4032
|
+
}),
|
|
3920
4033
|
});
|
|
3921
|
-
}
|
|
3922
|
-
};
|
|
3923
|
-
|
|
3924
|
-
const removeNonDirectory = (sourceUrl) => {
|
|
3925
|
-
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
3926
|
-
const attempt = () => {
|
|
3927
|
-
unlinkSyncNaive(sourcePath);
|
|
3928
4034
|
};
|
|
3929
|
-
attempt();
|
|
4035
|
+
return attempt();
|
|
3930
4036
|
};
|
|
3931
4037
|
|
|
3932
|
-
const
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
4038
|
+
const unlinkNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
|
|
4039
|
+
return new Promise((resolve, reject) => {
|
|
4040
|
+
unlink(sourcePath, (error) => {
|
|
4041
|
+
if (error) {
|
|
4042
|
+
if (error.code === "ENOENT") {
|
|
4043
|
+
resolve();
|
|
4044
|
+
} else if (
|
|
4045
|
+
handleTemporaryError &&
|
|
4046
|
+
(error.code === "EBUSY" ||
|
|
4047
|
+
error.code === "EMFILE" ||
|
|
4048
|
+
error.code === "ENFILE" ||
|
|
4049
|
+
error.code === "ENOENT")
|
|
4050
|
+
) {
|
|
4051
|
+
resolve(handleTemporaryError(error));
|
|
4052
|
+
} else {
|
|
4053
|
+
reject(error);
|
|
4054
|
+
}
|
|
4055
|
+
} else {
|
|
4056
|
+
resolve();
|
|
4057
|
+
}
|
|
4058
|
+
});
|
|
4059
|
+
});
|
|
3951
4060
|
};
|
|
3952
4061
|
|
|
3953
|
-
const
|
|
4062
|
+
const removeDirectory = async (
|
|
3954
4063
|
rootDirectoryUrl,
|
|
3955
|
-
{ maxRetries, retryDelay, recursive, onlyContent },
|
|
4064
|
+
{ signal, maxRetries, retryDelay, recursive, onlyContent },
|
|
3956
4065
|
) => {
|
|
3957
|
-
const
|
|
3958
|
-
|
|
4066
|
+
const removeDirectoryOperation = Abort.startOperation();
|
|
4067
|
+
removeDirectoryOperation.addAbortSignal(signal);
|
|
4068
|
+
|
|
4069
|
+
const visit = async (sourceUrl) => {
|
|
4070
|
+
removeDirectoryOperation.throwIfAborted();
|
|
4071
|
+
const sourceStats = await readEntryStat(sourceUrl, {
|
|
3959
4072
|
nullIfNotFound: true,
|
|
3960
4073
|
followLink: false,
|
|
3961
4074
|
});
|
|
@@ -3970,30 +4083,31 @@ const removeDirectorySync$1 = (
|
|
|
3970
4083
|
sourceStats.isCharacterDevice() ||
|
|
3971
4084
|
sourceStats.isBlockDevice()
|
|
3972
4085
|
) {
|
|
3973
|
-
visitFile(sourceUrl);
|
|
4086
|
+
await visitFile(sourceUrl);
|
|
3974
4087
|
} else if (sourceStats.isSymbolicLink()) {
|
|
3975
|
-
visitSymbolicLink(sourceUrl);
|
|
4088
|
+
await visitSymbolicLink(sourceUrl);
|
|
3976
4089
|
} else if (sourceStats.isDirectory()) {
|
|
3977
|
-
visitDirectory(`${sourceUrl}/`);
|
|
4090
|
+
await visitDirectory(`${sourceUrl}/`);
|
|
3978
4091
|
}
|
|
3979
4092
|
};
|
|
3980
4093
|
|
|
3981
|
-
const visitDirectory = (directoryUrl) => {
|
|
4094
|
+
const visitDirectory = async (directoryUrl) => {
|
|
3982
4095
|
const directoryPath = urlToFileSystemPath(directoryUrl);
|
|
3983
4096
|
const optionsFromRecursive = recursive
|
|
3984
4097
|
? {
|
|
3985
|
-
handleNotEmptyError: () => {
|
|
3986
|
-
removeDirectoryContent(directoryUrl);
|
|
3987
|
-
visitDirectory(directoryUrl);
|
|
4098
|
+
handleNotEmptyError: async () => {
|
|
4099
|
+
await removeDirectoryContent(directoryUrl);
|
|
4100
|
+
await visitDirectory(directoryUrl);
|
|
3988
4101
|
},
|
|
3989
4102
|
}
|
|
3990
4103
|
: {};
|
|
3991
|
-
|
|
4104
|
+
removeDirectoryOperation.throwIfAborted();
|
|
4105
|
+
await removeDirectoryNaive(directoryPath, {
|
|
3992
4106
|
...optionsFromRecursive,
|
|
3993
4107
|
// Workaround for https://github.com/joyent/node/issues/4337
|
|
3994
4108
|
...(process.platform === "win32"
|
|
3995
4109
|
? {
|
|
3996
|
-
handlePermissionError: (error) => {
|
|
4110
|
+
handlePermissionError: async (error) => {
|
|
3997
4111
|
console.error(
|
|
3998
4112
|
`trying to fix windows EPERM after readir on ${directoryPath}`,
|
|
3999
4113
|
);
|
|
@@ -4015,7 +4129,8 @@ const removeDirectorySync$1 = (
|
|
|
4015
4129
|
);
|
|
4016
4130
|
throw error;
|
|
4017
4131
|
}
|
|
4018
|
-
|
|
4132
|
+
|
|
4133
|
+
await removeDirectoryNaive(directoryPath, {
|
|
4019
4134
|
...optionsFromRecursive,
|
|
4020
4135
|
});
|
|
4021
4136
|
},
|
|
@@ -4024,59 +4139,69 @@ const removeDirectorySync$1 = (
|
|
|
4024
4139
|
});
|
|
4025
4140
|
};
|
|
4026
4141
|
|
|
4027
|
-
const removeDirectoryContent = (directoryUrl) => {
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4142
|
+
const removeDirectoryContent = async (directoryUrl) => {
|
|
4143
|
+
removeDirectoryOperation.throwIfAborted();
|
|
4144
|
+
const names = await readDirectory(directoryUrl);
|
|
4145
|
+
await Promise.all(
|
|
4146
|
+
names.map(async (name) => {
|
|
4147
|
+
const url = resolveUrl$1(name, directoryUrl);
|
|
4148
|
+
await visit(url);
|
|
4149
|
+
}),
|
|
4150
|
+
);
|
|
4033
4151
|
};
|
|
4034
4152
|
|
|
4035
|
-
const visitFile = (fileUrl) => {
|
|
4036
|
-
removeNonDirectory(fileUrl);
|
|
4153
|
+
const visitFile = async (fileUrl) => {
|
|
4154
|
+
await removeNonDirectory(fileUrl, { maxRetries, retryDelay });
|
|
4037
4155
|
};
|
|
4038
4156
|
|
|
4039
|
-
const visitSymbolicLink = (symbolicLinkUrl) => {
|
|
4040
|
-
removeNonDirectory(symbolicLinkUrl);
|
|
4157
|
+
const visitSymbolicLink = async (symbolicLinkUrl) => {
|
|
4158
|
+
await removeNonDirectory(symbolicLinkUrl, { maxRetries, retryDelay });
|
|
4041
4159
|
};
|
|
4042
4160
|
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4161
|
+
try {
|
|
4162
|
+
if (onlyContent) {
|
|
4163
|
+
await removeDirectoryContent(rootDirectoryUrl);
|
|
4164
|
+
} else {
|
|
4165
|
+
await visitDirectory(rootDirectoryUrl);
|
|
4166
|
+
}
|
|
4167
|
+
} finally {
|
|
4168
|
+
await removeDirectoryOperation.end();
|
|
4047
4169
|
}
|
|
4048
4170
|
};
|
|
4049
4171
|
|
|
4050
|
-
const
|
|
4172
|
+
const removeDirectoryNaive = (
|
|
4051
4173
|
directoryPath,
|
|
4052
4174
|
{ handleNotEmptyError = null, handlePermissionError = null } = {},
|
|
4053
4175
|
) => {
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4176
|
+
return new Promise((resolve, reject) => {
|
|
4177
|
+
rmdir(directoryPath, (error, lstatObject) => {
|
|
4178
|
+
if (error) {
|
|
4179
|
+
if (handlePermissionError && error.code === "EPERM") {
|
|
4180
|
+
resolve(handlePermissionError(error));
|
|
4181
|
+
} else if (error.code === "ENOENT") {
|
|
4182
|
+
resolve();
|
|
4183
|
+
} else if (
|
|
4184
|
+
handleNotEmptyError &&
|
|
4185
|
+
// linux os
|
|
4186
|
+
(error.code === "ENOTEMPTY" ||
|
|
4187
|
+
// SunOS
|
|
4188
|
+
error.code === "EEXIST")
|
|
4189
|
+
) {
|
|
4190
|
+
resolve(handleNotEmptyError(error));
|
|
4191
|
+
} else {
|
|
4192
|
+
reject(error);
|
|
4193
|
+
}
|
|
4194
|
+
} else {
|
|
4195
|
+
resolve(lstatObject);
|
|
4196
|
+
}
|
|
4197
|
+
});
|
|
4198
|
+
});
|
|
4076
4199
|
};
|
|
4077
4200
|
|
|
4078
4201
|
process.platform === "win32";
|
|
4079
4202
|
|
|
4203
|
+
process.platform === "win32";
|
|
4204
|
+
|
|
4080
4205
|
const ensureEmptyDirectory = async (source) => {
|
|
4081
4206
|
const stats = await readEntryStat(source, {
|
|
4082
4207
|
nullIfNotFound: true,
|
|
@@ -4104,13 +4229,6 @@ const ensureEmptyDirectory = async (source) => {
|
|
|
4104
4229
|
);
|
|
4105
4230
|
};
|
|
4106
4231
|
|
|
4107
|
-
const removeDirectorySync = (url, options = {}) => {
|
|
4108
|
-
return removeEntrySync(url, {
|
|
4109
|
-
...options,
|
|
4110
|
-
recursive: true,
|
|
4111
|
-
});
|
|
4112
|
-
};
|
|
4113
|
-
|
|
4114
4232
|
const callOnceIdlePerFile = (callback, idleMs) => {
|
|
4115
4233
|
const timeoutIdMap = new Map();
|
|
4116
4234
|
return (fileEvent) => {
|
|
@@ -11364,39 +11482,10 @@ const jsenvPluginTranspilation = ({
|
|
|
11364
11482
|
};
|
|
11365
11483
|
|
|
11366
11484
|
const lookupPackageDirectory = (currentUrl) => {
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
if (existsSync(new URL(packageJsonFileUrl))) {
|
|
11372
|
-
return currentUrl;
|
|
11373
|
-
}
|
|
11374
|
-
return lookupPackageDirectory(getParentUrl$1(currentUrl));
|
|
11375
|
-
};
|
|
11376
|
-
|
|
11377
|
-
const getParentUrl$1 = (url) => {
|
|
11378
|
-
if (url.startsWith("file://")) {
|
|
11379
|
-
// With node.js new URL('../', 'file:///C:/').href
|
|
11380
|
-
// returns "file:///C:/" instead of "file:///"
|
|
11381
|
-
const resource = url.slice("file://".length);
|
|
11382
|
-
const slashLastIndex = resource.lastIndexOf("/");
|
|
11383
|
-
if (slashLastIndex === -1) {
|
|
11384
|
-
return url;
|
|
11385
|
-
}
|
|
11386
|
-
const lastCharIndex = resource.length - 1;
|
|
11387
|
-
if (slashLastIndex === lastCharIndex) {
|
|
11388
|
-
const slashBeforeLastIndex = resource.lastIndexOf(
|
|
11389
|
-
"/",
|
|
11390
|
-
slashLastIndex - 1,
|
|
11391
|
-
);
|
|
11392
|
-
if (slashBeforeLastIndex === -1) {
|
|
11393
|
-
return url;
|
|
11394
|
-
}
|
|
11395
|
-
return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
|
|
11396
|
-
}
|
|
11397
|
-
return `file://${resource.slice(0, slashLastIndex + 1)}`;
|
|
11398
|
-
}
|
|
11399
|
-
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
|
+
});
|
|
11400
11489
|
};
|
|
11401
11490
|
|
|
11402
11491
|
const watchSourceFiles = (
|
|
@@ -14368,18 +14457,7 @@ const createUrlInfoTransformer = ({
|
|
|
14368
14457
|
contentIsInlined = false;
|
|
14369
14458
|
}
|
|
14370
14459
|
if (!contentIsInlined) {
|
|
14371
|
-
|
|
14372
|
-
writeFileSync(new URL(generatedUrl), urlInfo.content);
|
|
14373
|
-
} catch (e) {
|
|
14374
|
-
if (e.code === "EISDIR") {
|
|
14375
|
-
// happens when directory existed but got delete
|
|
14376
|
-
// we can safely remove that directory and write the new file
|
|
14377
|
-
removeDirectorySync(new URL(generatedUrl));
|
|
14378
|
-
writeFileSync(new URL(generatedUrl), urlInfo.content);
|
|
14379
|
-
} else {
|
|
14380
|
-
throw e;
|
|
14381
|
-
}
|
|
14382
|
-
}
|
|
14460
|
+
writeFileSync(new URL(generatedUrl), urlInfo.content, { force: true });
|
|
14383
14461
|
}
|
|
14384
14462
|
const { sourcemapGeneratedUrl, sourcemapReference } = urlInfo;
|
|
14385
14463
|
if (sourcemapGeneratedUrl && sourcemapReference) {
|
|
@@ -19175,6 +19253,7 @@ const jsenvPluginProtocolFile = ({
|
|
|
19175
19253
|
if (!urlInfo.url.startsWith("file:")) {
|
|
19176
19254
|
return null;
|
|
19177
19255
|
}
|
|
19256
|
+
const { rootDirectoryUrl } = urlInfo.context;
|
|
19178
19257
|
const generateContent = () => {
|
|
19179
19258
|
const urlObject = new URL(urlInfo.url);
|
|
19180
19259
|
const { firstReference } = urlInfo;
|
|
@@ -19193,11 +19272,12 @@ const jsenvPluginProtocolFile = ({
|
|
|
19193
19272
|
: false;
|
|
19194
19273
|
if (acceptsHtml) {
|
|
19195
19274
|
firstReference.expectedType = "html";
|
|
19196
|
-
const
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
19275
|
+
const directoryUrl = urlObject.href;
|
|
19276
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
19277
|
+
directoryUrl,
|
|
19278
|
+
rootDirectoryUrl,
|
|
19200
19279
|
);
|
|
19280
|
+
const html = generateHtmlForDirectory(directoryContentItems);
|
|
19201
19281
|
return {
|
|
19202
19282
|
type: "html",
|
|
19203
19283
|
contentType: "text/html",
|
|
@@ -19230,32 +19310,13 @@ const jsenvPluginProtocolFile = ({
|
|
|
19230
19310
|
if (e.code !== "ENOENT") {
|
|
19231
19311
|
throw e;
|
|
19232
19312
|
}
|
|
19233
|
-
const
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
firstExistingAncestorDirectoryUrl = new URL(
|
|
19237
|
-
"../",
|
|
19238
|
-
firstExistingAncestorDirectoryUrl,
|
|
19239
|
-
);
|
|
19240
|
-
if (
|
|
19241
|
-
!urlIsInsideOf(
|
|
19242
|
-
firstExistingAncestorDirectoryUrl,
|
|
19243
|
-
rootDirectoryUrl,
|
|
19244
|
-
)
|
|
19245
|
-
) {
|
|
19246
|
-
firstExistingAncestorDirectoryUrl = rootDirectoryUrl;
|
|
19247
|
-
break;
|
|
19248
|
-
}
|
|
19249
|
-
}
|
|
19250
|
-
|
|
19251
|
-
const firstExistingAncestorDirectoryContent = readdirSync(
|
|
19252
|
-
new URL(firstExistingAncestorDirectoryUrl),
|
|
19313
|
+
const directoryContentItems = generateDirectoryContentItems(
|
|
19314
|
+
urlInfo.url,
|
|
19315
|
+
rootDirectoryUrl,
|
|
19253
19316
|
);
|
|
19254
19317
|
const html = generateHtmlForENOENT(
|
|
19255
19318
|
urlInfo.url,
|
|
19256
|
-
|
|
19257
|
-
firstExistingAncestorDirectoryUrl,
|
|
19258
|
-
urlInfo.context.rootDirectoryUrl,
|
|
19319
|
+
directoryContentItems,
|
|
19259
19320
|
directoryListingUrlMocks,
|
|
19260
19321
|
);
|
|
19261
19322
|
return {
|
|
@@ -19274,11 +19335,9 @@ const jsenvPluginProtocolFile = ({
|
|
|
19274
19335
|
];
|
|
19275
19336
|
};
|
|
19276
19337
|
|
|
19277
|
-
const generateHtmlForDirectory = (
|
|
19278
|
-
directoryUrl
|
|
19279
|
-
|
|
19280
|
-
rootDirectoryUrl,
|
|
19281
|
-
) => {
|
|
19338
|
+
const generateHtmlForDirectory = (directoryContentItems) => {
|
|
19339
|
+
let directoryUrl = directoryContentItems.firstExistingDirectoryUrl;
|
|
19340
|
+
const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
|
|
19282
19341
|
directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
19283
19342
|
|
|
19284
19343
|
const htmlForDirectory = String(readFileSync(htmlFileUrlForDirectory));
|
|
@@ -19287,23 +19346,19 @@ const generateHtmlForDirectory = (
|
|
|
19287
19346
|
directoryUrl,
|
|
19288
19347
|
directoryNav: () =>
|
|
19289
19348
|
generateDirectoryNav(directoryRelativeUrl, rootDirectoryUrl),
|
|
19290
|
-
directoryContent: () =>
|
|
19291
|
-
generateDirectoryContent(
|
|
19292
|
-
directoryContentArray,
|
|
19293
|
-
directoryUrl,
|
|
19294
|
-
rootDirectoryUrl,
|
|
19295
|
-
),
|
|
19349
|
+
directoryContent: () => generateDirectoryContent(directoryContentItems),
|
|
19296
19350
|
};
|
|
19297
19351
|
const html = replacePlaceholders$1(htmlForDirectory, replacers);
|
|
19298
19352
|
return html;
|
|
19299
19353
|
};
|
|
19300
19354
|
const generateHtmlForENOENT = (
|
|
19301
19355
|
url,
|
|
19302
|
-
|
|
19303
|
-
ancestorDirectoryUrl,
|
|
19304
|
-
rootDirectoryUrl,
|
|
19356
|
+
directoryContentItems,
|
|
19305
19357
|
directoryListingUrlMocks,
|
|
19306
19358
|
) => {
|
|
19359
|
+
const ancestorDirectoryUrl = directoryContentItems.firstExistingDirectoryUrl;
|
|
19360
|
+
const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
|
|
19361
|
+
|
|
19307
19362
|
const htmlFor404AndAncestorDir = String(
|
|
19308
19363
|
readFileSync(html404AndAncestorDirFileUrl),
|
|
19309
19364
|
);
|
|
@@ -19322,11 +19377,7 @@ const generateHtmlForENOENT = (
|
|
|
19322
19377
|
ancestorDirectoryNav: () =>
|
|
19323
19378
|
generateDirectoryNav(ancestorDirectoryRelativeUrl, rootDirectoryUrl),
|
|
19324
19379
|
ancestorDirectoryContent: () =>
|
|
19325
|
-
generateDirectoryContent(
|
|
19326
|
-
ancestorDirectoryContentArray,
|
|
19327
|
-
ancestorDirectoryUrl,
|
|
19328
|
-
rootDirectoryUrl,
|
|
19329
|
-
),
|
|
19380
|
+
generateDirectoryContent(directoryContentItems),
|
|
19330
19381
|
};
|
|
19331
19382
|
const html = replacePlaceholders$1(htmlFor404AndAncestorDir, replacers);
|
|
19332
19383
|
return html;
|
|
@@ -19368,31 +19419,95 @@ const generateDirectoryNav = (relativeUrl, rootDirectoryUrl) => {
|
|
|
19368
19419
|
}
|
|
19369
19420
|
return dirPartsHtml;
|
|
19370
19421
|
};
|
|
19371
|
-
const
|
|
19372
|
-
|
|
19373
|
-
|
|
19374
|
-
|
|
19375
|
-
)
|
|
19376
|
-
|
|
19377
|
-
|
|
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
|
+
}
|
|
19378
19430
|
}
|
|
19379
|
-
const
|
|
19431
|
+
const directoryContentArray = readdirSync(firstExistingDirectoryUrl);
|
|
19432
|
+
const fileUrls = [];
|
|
19380
19433
|
for (const filename of directoryContentArray) {
|
|
19381
|
-
const fileUrlObject = new URL(filename,
|
|
19382
|
-
|
|
19383
|
-
|
|
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));
|
|
19384
19477
|
} else {
|
|
19385
|
-
|
|
19478
|
+
sortedUrls.push(fileUrl);
|
|
19386
19479
|
}
|
|
19387
19480
|
}
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
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);
|
|
19395
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;
|
|
19396
19511
|
html += `
|
|
19397
19512
|
<li class="directory_child" data-type="${type}">
|
|
19398
19513
|
<a href="/${fileUrlRelativeToRoot}">${fileUrlRelativeToParent}</a>
|