@jsenv/filesystem 4.13.5 → 4.14.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.13.5",
3
+ "version": "4.14.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,9 +29,9 @@
29
29
  "/src/"
30
30
  ],
31
31
  "dependencies": {
32
- "@jsenv/urls": "2.6.0",
33
- "@jsenv/url-meta": "8.5.3",
34
- "@jsenv/abort": "4.3.0",
35
- "@jsenv/utils": "2.1.3"
32
+ "@jsenv/urls": "2.6.1",
33
+ "@jsenv/url-meta": "8.5.4",
34
+ "@jsenv/abort": "4.3.1",
35
+ "@jsenv/utils": "2.2.0"
36
36
  }
37
37
  }
@@ -249,50 +249,18 @@ export const registerDirectoryLifecycle = (
249
249
  handleEntryUpdated(entryInfo);
250
250
  };
251
251
  const handleEntryFound = (entryInfo, { notify = true } = {}) => {
252
- infoMap.set(entryInfo.relativeUrl, entryInfo);
253
- if (entryInfo.type === "directory") {
254
- const directoryUrl = `${entryInfo.url}/`;
255
- let entryNameArray;
256
- try {
257
- const directoryUrlObject = new URL(directoryUrl);
258
- entryNameArray = readdirSync(directoryUrlObject);
259
- } catch (e) {
260
- if (
261
- e.code === "ENOENT" ||
262
- e.code === "EACCES" ||
263
- e.code === "EPERM" ||
264
- e.code === "ENOTDIR"
265
- ) {
266
- return;
267
- }
268
- throw e;
269
- }
270
- for (const entryName of entryNameArray) {
271
- const childEntryUrl = new URL(entryName, directoryUrl).href;
272
- const childEntryInfo = readEntryInfo(childEntryUrl);
273
- if (childEntryInfo.type !== null && childEntryInfo.patternValue) {
274
- handleEntryFound(childEntryInfo, { notify });
275
- }
276
- }
277
- // we must watch manually every directory we find
278
- if (!fsWatchSupportsRecursive) {
252
+ const seenSet = new Set();
253
+ const applyEntryDiscoveredEffects = (entryInfo) => {
254
+ seenSet.add(entryInfo.url);
255
+ infoMap.set(entryInfo.relativeUrl, entryInfo);
256
+ if (entryInfo.type === "directory") {
257
+ const directoryUrl = entryInfo.url.endsWith("/")
258
+ ? entryInfo.url
259
+ : `${entryInfo.url}/`;
260
+ let entryNameArray;
279
261
  try {
280
- const watcher = createWatcher(urlToFileSystemPath(entryInfo.url), {
281
- persistent: keepProcessAlive,
282
- });
283
- tracker.registerCleanupCallback(() => {
284
- watcher.close();
285
- });
286
- watcher.on("change", (eventType, filename) => {
287
- handleDirectoryEvent({
288
- directoryRelativeUrl: entryInfo.relativeUrl,
289
- filename: filename
290
- ? // replace back slashes with slashes
291
- filename.replace(/\\/g, "/")
292
- : "",
293
- eventType,
294
- });
295
- });
262
+ const directoryUrlObject = new URL(directoryUrl);
263
+ entryNameArray = readdirSync(directoryUrlObject);
296
264
  } catch (e) {
297
265
  if (
298
266
  e.code === "ENOENT" ||
@@ -304,16 +272,59 @@ export const registerDirectoryLifecycle = (
304
272
  }
305
273
  throw e;
306
274
  }
275
+ for (const entryName of entryNameArray) {
276
+ const childEntryUrl = new URL(entryName, directoryUrl).href;
277
+ if (seenSet.has(childEntryUrl)) {
278
+ continue;
279
+ }
280
+ const childEntryInfo = readEntryInfo(childEntryUrl);
281
+ if (childEntryInfo.type !== null && childEntryInfo.patternValue) {
282
+ applyEntryDiscoveredEffects(childEntryInfo);
283
+ }
284
+ }
285
+ // we must watch manually every directory we find
286
+ if (!fsWatchSupportsRecursive) {
287
+ try {
288
+ const watcher = createWatcher(urlToFileSystemPath(entryInfo.url), {
289
+ persistent: keepProcessAlive,
290
+ });
291
+ tracker.registerCleanupCallback(() => {
292
+ watcher.close();
293
+ });
294
+ watcher.on("change", (eventType, filename) => {
295
+ handleDirectoryEvent({
296
+ directoryRelativeUrl: entryInfo.relativeUrl,
297
+ filename: filename
298
+ ? // replace back slashes with slashes
299
+ filename.replace(/\\/g, "/")
300
+ : "",
301
+ eventType,
302
+ });
303
+ });
304
+ } catch (e) {
305
+ if (
306
+ e.code === "ENOENT" ||
307
+ e.code === "EACCES" ||
308
+ e.code === "EPERM" ||
309
+ e.code === "ENOTDIR"
310
+ ) {
311
+ return;
312
+ }
313
+ throw e;
314
+ }
315
+ }
307
316
  }
308
- }
309
- if (added && entryInfo.patternValue && notify) {
310
- added({
311
- relativeUrl: entryInfo.relativeUrl,
312
- type: entryInfo.type,
313
- patternValue: entryInfo.patternValue,
314
- mtime: entryInfo.stat.mtimeMs,
315
- });
316
- }
317
+ if (added && entryInfo.patternValue && notify) {
318
+ added({
319
+ relativeUrl: entryInfo.relativeUrl,
320
+ type: entryInfo.type,
321
+ patternValue: entryInfo.patternValue,
322
+ mtime: entryInfo.stat.mtimeMs,
323
+ });
324
+ }
325
+ };
326
+ applyEntryDiscoveredEffects(entryInfo);
327
+ seenSet.clear();
317
328
  };
318
329
  const handleEntryLost = (entryInfo) => {
319
330
  infoMap.delete(entryInfo.relativeUrl);
@@ -339,16 +350,9 @@ export const registerDirectoryLifecycle = (
339
350
  }
340
351
  };
341
352
 
342
- const entries = readdirSync(new URL(sourceUrl));
343
- for (const entry of entries) {
344
- const entryUrl = new URL(entry, sourceUrl).href;
345
- const entryInfo = readEntryInfo(entryUrl);
346
- if (entryInfo.type !== null && entryInfo.patternValue) {
347
- handleEntryFound(entryInfo, {
348
- notify: notifyExistent,
349
- });
350
- }
351
- }
353
+ handleEntryFound(readEntryInfo(sourceUrl), {
354
+ notify: notifyExistent,
355
+ });
352
356
  if (debug) {
353
357
  const relativeUrls = Array.from(infoMap.keys());
354
358
  if (relativeUrls.length === 0) {
package/src/main.js CHANGED
@@ -19,6 +19,10 @@ export { comparePathnames } from "./path_and_url/compare_pathnames.js";
19
19
  export { ensureWindowsDriveLetter } from "./path_and_url/ensure_windows_drive_letter.js";
20
20
  export { getParentDirectoryUrl } from "./path_and_url/get_parent_directory_url.js";
21
21
  export { findAncestorDirectoryUrl } from "./path_and_url/find_ancestor_directory_url.js";
22
+ // All other exports are agnostic and focused on the filesystem only
23
+ // "lookupPackageDirectory" is an exception because it related to node module resolution
24
+ // but it's very useful and it's not a problem to have it here (and useful to share this logic)
25
+ export { lookupPackageDirectory } from "./path_and_url/lookup_package_directory.js";
22
26
 
23
27
  // list
24
28
  export { collectDirectoryMatchReport } from "./list/collect_directory_match_report.js";
@@ -0,0 +1,9 @@
1
+ import { existsSync } from "node:fs";
2
+ import { findAncestorDirectoryUrl } from "./find_ancestor_directory_url.js";
3
+
4
+ export const lookupPackageDirectory = (currentUrl) => {
5
+ return findAncestorDirectoryUrl(currentUrl, (ancestorDirectoryUrl) => {
6
+ const potentialPackageJsonFileUrl = `${ancestorDirectoryUrl}package.json`;
7
+ return existsSync(new URL(potentialPackageJsonFileUrl));
8
+ });
9
+ };
@@ -5,7 +5,6 @@
5
5
 
6
6
  import { fileSystemPathToUrl, isFileSystemPath } from "@jsenv/urls";
7
7
  import { readlinkSync } from "node:fs";
8
-
9
8
  import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
10
9
 
11
10
  export const readSymbolicLinkSync = (url) => {