@jsenv/test 3.5.31 → 3.5.32

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.
Files changed (2) hide show
  1. package/dist/jsenv_test.js +331 -242
  2. package/package.json +2 -2
@@ -4,7 +4,7 @@ import tty from "node:tty";
4
4
  import stringWidth from "string-width";
5
5
  import { pathToFileURL, fileURLToPath } from "node:url";
6
6
  import { URL_META, filterV8Coverage } from "./js/v8_coverage.js";
7
- import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFile as readFile$1, readFileSync, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, unlinkSync, readdirSync, rmdirSync, existsSync } from "node:fs";
7
+ import { readdir, chmod, stat, lstat, chmodSync, statSync, lstatSync, promises, readFile as readFile$1, unlinkSync, openSync, closeSync, readdirSync, rmdirSync, mkdirSync, readFileSync, writeFileSync as writeFileSync$1, unlink, rmdir, existsSync } from "node:fs";
8
8
  import { dirname } from "node:path";
9
9
  import crypto from "node:crypto";
10
10
  import { readGitHubWorkflowEnv, startGithubCheckRun } from "@jsenv/github-check-run";
@@ -2120,6 +2120,42 @@ const extractDriveLetter = (resource) => {
2120
2120
  return null;
2121
2121
  };
2122
2122
 
2123
+ const getParentDirectoryUrl = (url) => {
2124
+ if (url.startsWith("file://")) {
2125
+ // With node.js new URL('../', 'file:///C:/').href
2126
+ // returns "file:///C:/" instead of "file:///"
2127
+ const resource = url.slice("file://".length);
2128
+ const slashLastIndex = resource.lastIndexOf("/");
2129
+ if (slashLastIndex === -1) {
2130
+ return url;
2131
+ }
2132
+ const lastCharIndex = resource.length - 1;
2133
+ if (slashLastIndex === lastCharIndex) {
2134
+ const slashBeforeLastIndex = resource.lastIndexOf(
2135
+ "/",
2136
+ slashLastIndex - 1,
2137
+ );
2138
+ if (slashBeforeLastIndex === -1) {
2139
+ return url;
2140
+ }
2141
+ return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
2142
+ }
2143
+ return `file://${resource.slice(0, slashLastIndex + 1)}`;
2144
+ }
2145
+ return new URL(url.endsWith("/") ? "../" : "./", url).href;
2146
+ };
2147
+
2148
+ const findAncestorDirectoryUrl = (url, callback) => {
2149
+ url = String(url);
2150
+ while (url !== "file:///") {
2151
+ if (callback(url)) {
2152
+ return url;
2153
+ }
2154
+ url = getParentDirectoryUrl(url);
2155
+ }
2156
+ return null;
2157
+ };
2158
+
2123
2159
  const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
2124
2160
  const directoryUrl = assertAndNormalizeDirectoryUrl(url);
2125
2161
  const directoryUrlObject = new URL(directoryUrl);
@@ -2542,7 +2578,284 @@ const readFile = async (value, { as = "buffer" } = {}) => {
2542
2578
  );
2543
2579
  };
2544
2580
 
2545
- const writeFileSync = (destination, content = "") => {
2581
+ const removeEntrySync = (
2582
+ source,
2583
+ {
2584
+ allowUseless = false,
2585
+ recursive = false,
2586
+ maxRetries = 3,
2587
+ retryDelay = 100,
2588
+ onlyContent = false,
2589
+ } = {},
2590
+ ) => {
2591
+ const sourceUrl = assertAndNormalizeFileUrl(source);
2592
+ const sourceStats = readEntryStatSync(sourceUrl, {
2593
+ nullIfNotFound: true,
2594
+ followLink: false,
2595
+ });
2596
+ if (!sourceStats) {
2597
+ if (allowUseless) {
2598
+ return;
2599
+ }
2600
+ throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
2601
+ }
2602
+
2603
+ // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
2604
+ // FIFO and socket are ignored, not sure what they are exactly and what to do with them
2605
+ // other libraries ignore them, let's do the same.
2606
+ if (
2607
+ sourceStats.isFile() ||
2608
+ sourceStats.isSymbolicLink() ||
2609
+ sourceStats.isCharacterDevice() ||
2610
+ sourceStats.isBlockDevice()
2611
+ ) {
2612
+ removeNonDirectory$1(
2613
+ sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl);
2614
+ } else if (sourceStats.isDirectory()) {
2615
+ const directoryUrl = ensurePathnameTrailingSlash(sourceUrl);
2616
+ removeDirectorySync$1(directoryUrl, {
2617
+ recursive,
2618
+ maxRetries,
2619
+ retryDelay,
2620
+ onlyContent,
2621
+ });
2622
+ }
2623
+ };
2624
+
2625
+ const removeNonDirectory$1 = (sourceUrl) => {
2626
+ const sourcePath = urlToFileSystemPath(sourceUrl);
2627
+ const attempt = () => {
2628
+ unlinkSyncNaive(sourcePath);
2629
+ };
2630
+ attempt();
2631
+ };
2632
+
2633
+ const unlinkSyncNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
2634
+ try {
2635
+ unlinkSync(sourcePath);
2636
+ } catch (error) {
2637
+ if (error.code === "ENOENT") {
2638
+ return;
2639
+ }
2640
+ if (
2641
+ handleTemporaryError &&
2642
+ (error.code === "EBUSY" ||
2643
+ error.code === "EMFILE" ||
2644
+ error.code === "ENFILE" ||
2645
+ error.code === "ENOENT")
2646
+ ) {
2647
+ handleTemporaryError(error);
2648
+ return;
2649
+ }
2650
+ throw error;
2651
+ }
2652
+ };
2653
+
2654
+ const removeDirectorySync$1 = (
2655
+ rootDirectoryUrl,
2656
+ { maxRetries, retryDelay, recursive, onlyContent },
2657
+ ) => {
2658
+ const visit = (sourceUrl) => {
2659
+ const sourceStats = readEntryStatSync(sourceUrl, {
2660
+ nullIfNotFound: true,
2661
+ followLink: false,
2662
+ });
2663
+
2664
+ // file/directory not found
2665
+ if (sourceStats === null) {
2666
+ return;
2667
+ }
2668
+
2669
+ if (
2670
+ sourceStats.isFile() ||
2671
+ sourceStats.isCharacterDevice() ||
2672
+ sourceStats.isBlockDevice()
2673
+ ) {
2674
+ visitFile(sourceUrl);
2675
+ } else if (sourceStats.isSymbolicLink()) {
2676
+ visitSymbolicLink(sourceUrl);
2677
+ } else if (sourceStats.isDirectory()) {
2678
+ visitDirectory(`${sourceUrl}/`);
2679
+ }
2680
+ };
2681
+
2682
+ const visitDirectory = (directoryUrl) => {
2683
+ const directoryPath = urlToFileSystemPath(directoryUrl);
2684
+ const optionsFromRecursive = recursive
2685
+ ? {
2686
+ handleNotEmptyError: () => {
2687
+ removeDirectoryContent(directoryUrl);
2688
+ visitDirectory(directoryUrl);
2689
+ },
2690
+ }
2691
+ : {};
2692
+ removeDirectorySyncNaive(directoryPath, {
2693
+ ...optionsFromRecursive,
2694
+ // Workaround for https://github.com/joyent/node/issues/4337
2695
+ ...(process.platform === "win32"
2696
+ ? {
2697
+ handlePermissionError: (error) => {
2698
+ console.error(
2699
+ `trying to fix windows EPERM after readir on ${directoryPath}`,
2700
+ );
2701
+
2702
+ let openOrCloseError;
2703
+ try {
2704
+ const fd = openSync(directoryPath);
2705
+ closeSync(fd);
2706
+ } catch (e) {
2707
+ openOrCloseError = e;
2708
+ }
2709
+
2710
+ if (openOrCloseError) {
2711
+ if (openOrCloseError.code === "ENOENT") {
2712
+ return;
2713
+ }
2714
+ console.error(
2715
+ `error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
2716
+ );
2717
+ throw error;
2718
+ }
2719
+ removeDirectorySyncNaive(directoryPath, {
2720
+ ...optionsFromRecursive,
2721
+ });
2722
+ },
2723
+ }
2724
+ : {}),
2725
+ });
2726
+ };
2727
+
2728
+ const removeDirectoryContent = (directoryUrl) => {
2729
+ const entryNames = readdirSync(new URL(directoryUrl));
2730
+ for (const entryName of entryNames) {
2731
+ const url = resolveUrl(entryName, directoryUrl);
2732
+ visit(url);
2733
+ }
2734
+ };
2735
+
2736
+ const visitFile = (fileUrl) => {
2737
+ removeNonDirectory$1(fileUrl);
2738
+ };
2739
+
2740
+ const visitSymbolicLink = (symbolicLinkUrl) => {
2741
+ removeNonDirectory$1(symbolicLinkUrl);
2742
+ };
2743
+
2744
+ if (onlyContent) {
2745
+ removeDirectoryContent(rootDirectoryUrl);
2746
+ } else {
2747
+ visitDirectory(rootDirectoryUrl);
2748
+ }
2749
+ };
2750
+
2751
+ const removeDirectorySyncNaive = (
2752
+ directoryPath,
2753
+ { handleNotEmptyError = null, handlePermissionError = null } = {},
2754
+ ) => {
2755
+ try {
2756
+ rmdirSync(directoryPath);
2757
+ } catch (error) {
2758
+ if (handlePermissionError && error.code === "EPERM") {
2759
+ handlePermissionError(error);
2760
+ return;
2761
+ }
2762
+ if (error.code === "ENOENT") {
2763
+ return;
2764
+ }
2765
+ if (
2766
+ handleNotEmptyError &&
2767
+ // linux os
2768
+ (error.code === "ENOTEMPTY" ||
2769
+ // SunOS
2770
+ error.code === "EEXIST")
2771
+ ) {
2772
+ handleNotEmptyError(error);
2773
+ return;
2774
+ }
2775
+ throw error;
2776
+ }
2777
+ };
2778
+
2779
+ const removeDirectorySync = (url, options = {}) => {
2780
+ return removeEntrySync(url, {
2781
+ ...options,
2782
+ recursive: true,
2783
+ });
2784
+ };
2785
+
2786
+ const writeDirectorySync = (
2787
+ destination,
2788
+ { recursive = true, allowUseless = false, force } = {},
2789
+ ) => {
2790
+ const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
2791
+ const destinationPath = urlToFileSystemPath(destinationUrl);
2792
+
2793
+ let destinationStats;
2794
+ try {
2795
+ destinationStats = readEntryStatSync(destinationUrl, {
2796
+ nullIfNotFound: true,
2797
+ followLink: false,
2798
+ });
2799
+ } catch (e) {
2800
+ if (e.code === "ENOTDIR") {
2801
+ let previousNonDirUrl = destinationUrl;
2802
+ // we must try all parent directories as long as it fails with ENOTDIR
2803
+ findAncestorDirectoryUrl(destinationUrl, (ancestorUrl) => {
2804
+ try {
2805
+ statSync(new URL(ancestorUrl));
2806
+ return true;
2807
+ } catch (e) {
2808
+ if (e.code === "ENOTDIR") {
2809
+ previousNonDirUrl = ancestorUrl;
2810
+ return false;
2811
+ }
2812
+ throw e;
2813
+ }
2814
+ });
2815
+ if (force) {
2816
+ unlinkSync(
2817
+ new URL(
2818
+ previousNonDirUrl
2819
+ // remove trailing slash
2820
+ .slice(0, -1),
2821
+ ),
2822
+ );
2823
+ } else {
2824
+ throw new Error(
2825
+ `cannot write directory at ${destinationPath} because there is a file at ${urlToFileSystemPath(
2826
+ previousNonDirUrl,
2827
+ )}`,
2828
+ );
2829
+ }
2830
+ } else {
2831
+ throw e;
2832
+ }
2833
+ }
2834
+
2835
+ if (destinationStats) {
2836
+ if (destinationStats.isDirectory()) {
2837
+ if (allowUseless) {
2838
+ return;
2839
+ }
2840
+ throw new Error(`directory already exists at ${destinationPath}`);
2841
+ }
2842
+ const destinationType = statsToType(destinationStats);
2843
+ throw new Error(
2844
+ `cannot write directory at ${destinationPath} because there is a ${destinationType}`,
2845
+ );
2846
+ }
2847
+
2848
+ try {
2849
+ mkdirSync(destinationPath, { recursive });
2850
+ } catch (error) {
2851
+ if (allowUseless && error.code === "EEXIST") {
2852
+ return;
2853
+ }
2854
+ throw error;
2855
+ }
2856
+ };
2857
+
2858
+ const writeFileSync = (destination, content = "", { force } = {}) => {
2546
2859
  const destinationUrl = assertAndNormalizeFileUrl(destination);
2547
2860
  const destinationUrlObject = new URL(destinationUrl);
2548
2861
  if (content && content instanceof URL) {
@@ -2551,8 +2864,18 @@ const writeFileSync = (destination, content = "") => {
2551
2864
  try {
2552
2865
  writeFileSync$1(destinationUrlObject, content);
2553
2866
  } catch (error) {
2554
- if (error.code === "ENOENT") {
2555
- mkdirSync(new URL("./", destinationUrlObject), {
2867
+ if (error.code === "EISDIR") {
2868
+ // happens when directory existed but got deleted and now it's a file
2869
+ if (force) {
2870
+ removeDirectorySync(destinationUrlObject);
2871
+ writeFileSync$1(destinationUrlObject, content);
2872
+ } else {
2873
+ throw error;
2874
+ }
2875
+ }
2876
+ if (error.code === "ENOENT" || error.code === "ENOTDIR") {
2877
+ writeDirectorySync(new URL("./", destinationUrlObject), {
2878
+ force,
2556
2879
  recursive: true,
2557
2880
  });
2558
2881
  writeFileSync$1(destinationUrlObject, content);
@@ -2600,7 +2923,7 @@ const removeEntry = async (
2600
2923
  sourceStats.isCharacterDevice() ||
2601
2924
  sourceStats.isBlockDevice()
2602
2925
  ) {
2603
- await removeNonDirectory$1(
2926
+ await removeNonDirectory(
2604
2927
  sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl,
2605
2928
  {
2606
2929
  maxRetries,
@@ -2621,7 +2944,7 @@ const removeEntry = async (
2621
2944
  }
2622
2945
  };
2623
2946
 
2624
- const removeNonDirectory$1 = (sourceUrl, { maxRetries, retryDelay }) => {
2947
+ const removeNonDirectory = (sourceUrl, { maxRetries, retryDelay }) => {
2625
2948
  const sourcePath = urlToFileSystemPath(sourceUrl);
2626
2949
 
2627
2950
  let retryCount = 0;
@@ -2760,11 +3083,11 @@ const removeDirectory = async (
2760
3083
  };
2761
3084
 
2762
3085
  const visitFile = async (fileUrl) => {
2763
- await removeNonDirectory$1(fileUrl, { maxRetries, retryDelay });
3086
+ await removeNonDirectory(fileUrl, { maxRetries, retryDelay });
2764
3087
  };
2765
3088
 
2766
3089
  const visitSymbolicLink = async (symbolicLinkUrl) => {
2767
- await removeNonDirectory$1(symbolicLinkUrl, { maxRetries, retryDelay });
3090
+ await removeNonDirectory(symbolicLinkUrl, { maxRetries, retryDelay });
2768
3091
  };
2769
3092
 
2770
3093
  try {
@@ -2809,240 +3132,6 @@ const removeDirectoryNaive = (
2809
3132
 
2810
3133
  process.platform === "win32";
2811
3134
 
2812
- const writeDirectorySync = (
2813
- destination,
2814
- { recursive = true, allowUseless = false } = {},
2815
- ) => {
2816
- const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
2817
- const destinationPath = urlToFileSystemPath(destinationUrl);
2818
-
2819
- const destinationStats = readEntryStatSync(destinationUrl, {
2820
- nullIfNotFound: true,
2821
- followLink: false,
2822
- });
2823
-
2824
- if (destinationStats) {
2825
- if (destinationStats.isDirectory()) {
2826
- if (allowUseless) {
2827
- return;
2828
- }
2829
- throw new Error(`directory already exists at ${destinationPath}`);
2830
- }
2831
-
2832
- const destinationType = statsToType(destinationStats);
2833
- throw new Error(
2834
- `cannot write directory at ${destinationPath} because there is a ${destinationType}`,
2835
- );
2836
- }
2837
-
2838
- try {
2839
- mkdirSync(destinationPath, { recursive });
2840
- } catch (error) {
2841
- if (allowUseless && error.code === "EEXIST") {
2842
- return;
2843
- }
2844
- throw error;
2845
- }
2846
- };
2847
-
2848
- const removeEntrySync = (
2849
- source,
2850
- {
2851
- allowUseless = false,
2852
- recursive = false,
2853
- maxRetries = 3,
2854
- retryDelay = 100,
2855
- onlyContent = false,
2856
- } = {},
2857
- ) => {
2858
- const sourceUrl = assertAndNormalizeFileUrl(source);
2859
- const sourceStats = readEntryStatSync(sourceUrl, {
2860
- nullIfNotFound: true,
2861
- followLink: false,
2862
- });
2863
- if (!sourceStats) {
2864
- if (allowUseless) {
2865
- return;
2866
- }
2867
- throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`);
2868
- }
2869
-
2870
- // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
2871
- // FIFO and socket are ignored, not sure what they are exactly and what to do with them
2872
- // other libraries ignore them, let's do the same.
2873
- if (
2874
- sourceStats.isFile() ||
2875
- sourceStats.isSymbolicLink() ||
2876
- sourceStats.isCharacterDevice() ||
2877
- sourceStats.isBlockDevice()
2878
- ) {
2879
- removeNonDirectory(
2880
- sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl);
2881
- } else if (sourceStats.isDirectory()) {
2882
- const directoryUrl = ensurePathnameTrailingSlash(sourceUrl);
2883
- removeDirectorySync(directoryUrl, {
2884
- recursive,
2885
- maxRetries,
2886
- retryDelay,
2887
- onlyContent,
2888
- });
2889
- }
2890
- };
2891
-
2892
- const removeNonDirectory = (sourceUrl) => {
2893
- const sourcePath = urlToFileSystemPath(sourceUrl);
2894
- const attempt = () => {
2895
- unlinkSyncNaive(sourcePath);
2896
- };
2897
- attempt();
2898
- };
2899
-
2900
- const unlinkSyncNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
2901
- try {
2902
- unlinkSync(sourcePath);
2903
- } catch (error) {
2904
- if (error.code === "ENOENT") {
2905
- return;
2906
- }
2907
- if (
2908
- handleTemporaryError &&
2909
- (error.code === "EBUSY" ||
2910
- error.code === "EMFILE" ||
2911
- error.code === "ENFILE" ||
2912
- error.code === "ENOENT")
2913
- ) {
2914
- handleTemporaryError(error);
2915
- return;
2916
- }
2917
- throw error;
2918
- }
2919
- };
2920
-
2921
- const removeDirectorySync = (
2922
- rootDirectoryUrl,
2923
- { maxRetries, retryDelay, recursive, onlyContent },
2924
- ) => {
2925
- const visit = (sourceUrl) => {
2926
- const sourceStats = readEntryStatSync(sourceUrl, {
2927
- nullIfNotFound: true,
2928
- followLink: false,
2929
- });
2930
-
2931
- // file/directory not found
2932
- if (sourceStats === null) {
2933
- return;
2934
- }
2935
-
2936
- if (
2937
- sourceStats.isFile() ||
2938
- sourceStats.isCharacterDevice() ||
2939
- sourceStats.isBlockDevice()
2940
- ) {
2941
- visitFile(sourceUrl);
2942
- } else if (sourceStats.isSymbolicLink()) {
2943
- visitSymbolicLink(sourceUrl);
2944
- } else if (sourceStats.isDirectory()) {
2945
- visitDirectory(`${sourceUrl}/`);
2946
- }
2947
- };
2948
-
2949
- const visitDirectory = (directoryUrl) => {
2950
- const directoryPath = urlToFileSystemPath(directoryUrl);
2951
- const optionsFromRecursive = recursive
2952
- ? {
2953
- handleNotEmptyError: () => {
2954
- removeDirectoryContent(directoryUrl);
2955
- visitDirectory(directoryUrl);
2956
- },
2957
- }
2958
- : {};
2959
- removeDirectorySyncNaive(directoryPath, {
2960
- ...optionsFromRecursive,
2961
- // Workaround for https://github.com/joyent/node/issues/4337
2962
- ...(process.platform === "win32"
2963
- ? {
2964
- handlePermissionError: (error) => {
2965
- console.error(
2966
- `trying to fix windows EPERM after readir on ${directoryPath}`,
2967
- );
2968
-
2969
- let openOrCloseError;
2970
- try {
2971
- const fd = openSync(directoryPath);
2972
- closeSync(fd);
2973
- } catch (e) {
2974
- openOrCloseError = e;
2975
- }
2976
-
2977
- if (openOrCloseError) {
2978
- if (openOrCloseError.code === "ENOENT") {
2979
- return;
2980
- }
2981
- console.error(
2982
- `error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
2983
- );
2984
- throw error;
2985
- }
2986
- removeDirectorySyncNaive(directoryPath, {
2987
- ...optionsFromRecursive,
2988
- });
2989
- },
2990
- }
2991
- : {}),
2992
- });
2993
- };
2994
-
2995
- const removeDirectoryContent = (directoryUrl) => {
2996
- const entryNames = readdirSync(new URL(directoryUrl));
2997
- for (const entryName of entryNames) {
2998
- const url = resolveUrl(entryName, directoryUrl);
2999
- visit(url);
3000
- }
3001
- };
3002
-
3003
- const visitFile = (fileUrl) => {
3004
- removeNonDirectory(fileUrl);
3005
- };
3006
-
3007
- const visitSymbolicLink = (symbolicLinkUrl) => {
3008
- removeNonDirectory(symbolicLinkUrl);
3009
- };
3010
-
3011
- if (onlyContent) {
3012
- removeDirectoryContent(rootDirectoryUrl);
3013
- } else {
3014
- visitDirectory(rootDirectoryUrl);
3015
- }
3016
- };
3017
-
3018
- const removeDirectorySyncNaive = (
3019
- directoryPath,
3020
- { handleNotEmptyError = null, handlePermissionError = null } = {},
3021
- ) => {
3022
- try {
3023
- rmdirSync(directoryPath);
3024
- } catch (error) {
3025
- if (handlePermissionError && error.code === "EPERM") {
3026
- handlePermissionError(error);
3027
- return;
3028
- }
3029
- if (error.code === "ENOENT") {
3030
- return;
3031
- }
3032
- if (
3033
- handleNotEmptyError &&
3034
- // linux os
3035
- (error.code === "ENOTEMPTY" ||
3036
- // SunOS
3037
- error.code === "EEXIST")
3038
- ) {
3039
- handleNotEmptyError(error);
3040
- return;
3041
- }
3042
- throw error;
3043
- }
3044
- };
3045
-
3046
3135
  process.platform === "win32";
3047
3136
 
3048
3137
  const ensureEmptyDirectorySync = (source) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/test",
3
- "version": "3.5.31",
3
+ "version": "3.5.32",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,7 +39,7 @@
39
39
  "@jsenv/abort": "4.3.0",
40
40
  "@jsenv/ast": "6.4.1",
41
41
  "@jsenv/exception": "1.1.3",
42
- "@jsenv/filesystem": "4.11.0",
42
+ "@jsenv/filesystem": "4.12.0",
43
43
  "@jsenv/github-check-run": "0.2.5",
44
44
  "@jsenv/node-esm-resolution": "1.0.6",
45
45
  "@jsenv/humanize": "1.2.8",