@jsenv/filesystem 4.14.6 → 4.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "4.14.6",
3
+ "version": "4.15.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,7 +30,7 @@
30
30
  ],
31
31
  "sideEffects": false,
32
32
  "dependencies": {
33
- "@jsenv/urls": "2.7.1",
33
+ "@jsenv/urls": "2.7.2",
34
34
  "@jsenv/url-meta": "8.5.6",
35
35
  "@jsenv/abort": "4.3.1",
36
36
  "@jsenv/utils": "2.3.0"
package/src/main.js CHANGED
@@ -19,12 +19,13 @@ export { comparePathnames } from "./path_and_url/compare_pathnames.js";
19
19
  export { compareFileUrls } from "./path_and_url/compare_file_urls.js";
20
20
  export { ensureWindowsDriveLetter } from "./path_and_url/ensure_windows_drive_letter.js";
21
21
  export { getParentDirectoryUrl } from "./path_and_url/get_parent_directory_url.js";
22
- export { findAncestorDirectoryUrl } from "./path_and_url/find_ancestor_directory_url.js";
22
+ export { findSelfOrAncestorDirectoryUrl } from "./path_and_url/find_self_or_ancestor_directory_url.js";
23
23
  // All other exports are agnostic and focused on the filesystem only
24
24
  // "lookupPackageDirectory" is an exception because it related to node module resolution
25
25
  // but it's very useful and it's not a problem to have it here (and useful to share this logic)
26
26
  export {
27
27
  lookupPackageDirectory,
28
+ createLookupPackageDirectory,
28
29
  readPackageAtOrNull,
29
30
  } from "./path_and_url/lookup_package_directory.js";
30
31
 
@@ -54,6 +55,7 @@ export { writeDirectorySync } from "./read_write/write_directory_sync.js";
54
55
  export { readFileStructureSync } from "./read_write/read_file_structure_sync.js";
55
56
  export { writeFileStructureSync } from "./read_write/write_file_structure_sync.js";
56
57
  export { saveDirectoryContentSync } from "./read_write/save_directory_content_sync.js";
58
+ export { updateJsonFileSync } from "./read_write/update_json_file_sync.js";
57
59
 
58
60
  // stat
59
61
  export { readEntryStat } from "./read_write/stat/read_entry_stat.js";
@@ -1,7 +1,10 @@
1
1
  import { getParentDirectoryUrl } from "./get_parent_directory_url.js";
2
2
 
3
- export const findAncestorDirectoryUrl = (url, callback) => {
3
+ export const findSelfOrAncestorDirectoryUrl = (url, callback) => {
4
4
  url = String(url);
5
+ if (!url.endsWith("/")) {
6
+ url = new URL("./", url).href;
7
+ }
5
8
  while (url !== "file:///") {
6
9
  if (callback(url)) {
7
10
  return url;
@@ -1,13 +1,53 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import { findAncestorDirectoryUrl } from "./find_ancestor_directory_url.js";
2
+ import { findSelfOrAncestorDirectoryUrl } from "./find_self_or_ancestor_directory_url.js";
3
+ import { getParentDirectoryUrl } from "./get_parent_directory_url.js";
3
4
 
4
5
  export const lookupPackageDirectory = (currentUrl) => {
5
- return findAncestorDirectoryUrl(currentUrl, (ancestorDirectoryUrl) => {
6
+ return findSelfOrAncestorDirectoryUrl(currentUrl, (ancestorDirectoryUrl) => {
6
7
  const potentialPackageJsonFileUrl = `${ancestorDirectoryUrl}package.json`;
7
8
  return existsSync(new URL(potentialPackageJsonFileUrl));
8
9
  });
9
10
  };
10
11
 
12
+ export const createLookupPackageDirectory = () => {
13
+ const cache = new Map();
14
+ const lookupPackageDirectoryWithCache = (currentUrl) => {
15
+ const directoryUrls = [];
16
+ currentUrl = String(currentUrl);
17
+ if (currentUrl.endsWith("/")) {
18
+ directoryUrls.push(currentUrl);
19
+ } else {
20
+ const directoryUrl = new URL("./", currentUrl).href;
21
+ directoryUrls.push(directoryUrl);
22
+ currentUrl = directoryUrl;
23
+ }
24
+ while (currentUrl !== "file:///") {
25
+ const fromCache = cache.get(currentUrl);
26
+ if (fromCache !== undefined) {
27
+ return fromCache;
28
+ }
29
+ const packageJsonUrlCandidate = `${currentUrl}package.json`;
30
+ if (existsSync(new URL(packageJsonUrlCandidate))) {
31
+ for (const directoryUrl of directoryUrls) {
32
+ cache.set(directoryUrl, currentUrl);
33
+ }
34
+ return currentUrl;
35
+ }
36
+ const directoryUrl = getParentDirectoryUrl(currentUrl);
37
+ directoryUrls.push(directoryUrl);
38
+ currentUrl = directoryUrl;
39
+ }
40
+ for (const directoryUrl of directoryUrls) {
41
+ cache.set(directoryUrl, null);
42
+ }
43
+ return null;
44
+ };
45
+ lookupPackageDirectoryWithCache.clearCache = () => {
46
+ cache.clear();
47
+ };
48
+ return lookupPackageDirectoryWithCache;
49
+ };
50
+
11
51
  export const readPackageAtOrNull = (packageDirectoryUrl) => {
12
52
  try {
13
53
  const packageFileContent = readFileSync(
@@ -0,0 +1,27 @@
1
+ import { readFileSync } from "./read_file_sync.js";
2
+ import { writeFileSync } from "./write_file_sync.js";
3
+
4
+ export const updateJsonFileSync = (fileUrl, values = {}) => {
5
+ try {
6
+ const jsonString = readFileSync(fileUrl, { as: "string" });
7
+ const json = JSON.parse(jsonString);
8
+ const newContent = { ...json };
9
+ for (const key of Object.keys(values)) {
10
+ const value = values[key];
11
+ newContent[key] = value;
12
+ }
13
+ let jsonFormatted;
14
+ if (jsonString.startsWith("{\n")) {
15
+ jsonFormatted = JSON.stringify(newContent, null, " ");
16
+ } else {
17
+ jsonFormatted = JSON.stringify(newContent);
18
+ }
19
+ writeFileSync(fileUrl, jsonFormatted);
20
+ } catch (e) {
21
+ if (e.code === "ENOENT") {
22
+ writeFileSync(fileUrl, JSON.stringify(values));
23
+ return;
24
+ }
25
+ throw e;
26
+ }
27
+ };
@@ -2,7 +2,7 @@ import { urlToFileSystemPath } from "@jsenv/urls";
2
2
  import { mkdirSync, statSync, unlinkSync } from "node:fs";
3
3
 
4
4
  import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
5
- import { findAncestorDirectoryUrl } from "../path_and_url/find_ancestor_directory_url.js";
5
+ import { findSelfOrAncestorDirectoryUrl } from "../path_and_url/find_self_or_ancestor_directory_url.js";
6
6
  import { readEntryStatSync } from "./stat/read_entry_stat_sync.js";
7
7
  import { statsToType } from "./stat/stats_to_type.js";
8
8
 
@@ -23,7 +23,7 @@ export const writeDirectorySync = (
23
23
  if (e.code === "ENOTDIR") {
24
24
  let previousNonDirUrl = destinationUrl;
25
25
  // we must try all parent directories as long as it fails with ENOTDIR
26
- findAncestorDirectoryUrl(destinationUrl, (ancestorUrl) => {
26
+ findSelfOrAncestorDirectoryUrl(destinationUrl, (ancestorUrl) => {
27
27
  try {
28
28
  statSync(new URL(ancestorUrl));
29
29
  return true;