@zenfs/core 1.6.12 → 1.6.14

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.
@@ -365,7 +365,7 @@ export function watchFile(path, options, listener) {
365
365
  }
366
366
  return;
367
367
  }
368
- const watcher = new StatWatcher(normalizedPath, opts);
368
+ const watcher = new StatWatcher(this, normalizedPath, opts);
369
369
  watcher.on('change', (curr, prev) => {
370
370
  const entry = statWatchers.get(normalizedPath);
371
371
  if (!entry) {
@@ -407,7 +407,7 @@ export function unwatchFile(path, listener = nop) {
407
407
  }
408
408
  unwatchFile;
409
409
  export function watch(path, options, listener) {
410
- const watcher = new FSWatcher(normalizePath(path), typeof options == 'object' ? options : {});
410
+ const watcher = new FSWatcher(this, normalizePath(path), typeof options == 'object' ? options : {});
411
411
  listener = typeof options == 'function' ? options : listener;
412
412
  watcher.on('change', listener || nop);
413
413
  return watcher;
@@ -295,9 +295,9 @@ export declare function lutimes(this: V_Context, path: fs.PathLike, atime: fs.Ti
295
295
  */
296
296
  export declare function realpath(this: V_Context, path: fs.PathLike, options: fs.BufferEncodingOption): Promise<Buffer>;
297
297
  export declare function realpath(this: V_Context, path: fs.PathLike, options?: fs.EncodingOption | BufferEncoding): Promise<string>;
298
- export declare function watch(filename: fs.PathLike, options?: fs.WatchOptions | BufferEncoding): AsyncIterable<promises.FileChangeInfo<string>>;
299
- export declare function watch(filename: fs.PathLike, options: fs.WatchOptions | fs.BufferEncodingOption): AsyncIterable<promises.FileChangeInfo<Buffer>>;
300
- export declare function watch(filename: fs.PathLike, options?: fs.WatchOptions | string): AsyncIterable<promises.FileChangeInfo<string>> | AsyncIterable<promises.FileChangeInfo<Buffer>>;
298
+ export declare function watch(this: V_Context, filename: fs.PathLike, options?: fs.WatchOptions | BufferEncoding): AsyncIterable<promises.FileChangeInfo<string>>;
299
+ export declare function watch(this: V_Context, filename: fs.PathLike, options: fs.WatchOptions | fs.BufferEncodingOption): AsyncIterable<promises.FileChangeInfo<Buffer>>;
300
+ export declare function watch(this: V_Context, filename: fs.PathLike, options?: fs.WatchOptions | string): AsyncIterable<promises.FileChangeInfo<string>> | AsyncIterable<promises.FileChangeInfo<Buffer>>;
301
301
  export declare function access(this: V_Context, path: fs.PathLike, mode?: number): Promise<void>;
302
302
  /**
303
303
  * Asynchronous `rm`. Removes files or directories (recursively).
@@ -928,7 +928,7 @@ realpath;
928
928
  export function watch(filename, options = {}) {
929
929
  return {
930
930
  [Symbol.asyncIterator]() {
931
- const watcher = new FSWatcher(filename.toString(), typeof options !== 'string' ? options : { encoding: options });
931
+ const watcher = new FSWatcher(this, filename.toString(), typeof options !== 'string' ? options : { encoding: options });
932
932
  // A queue to hold change events, since we need to resolve them in the async iterator
933
933
  const eventQueue = [];
934
934
  watcher.on('change', (eventType, filename) => {
@@ -1,6 +1,7 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
2
  import type { EventEmitter as NodeEventEmitter } from 'node:events';
3
3
  import type * as fs from 'node:fs';
4
+ import type { V_Context } from '../context.js';
4
5
  import { type Stats } from '../stats.js';
5
6
  /**
6
7
  * Base class for file system watchers.
@@ -9,10 +10,18 @@ import { type Stats } from '../stats.js';
9
10
  * @template TEvents The type of events emitted by the watcher.
10
11
  */
11
12
  declare class Watcher<TEvents extends Record<string, unknown[]> = Record<string, unknown[]>> extends EventEmitter<TEvents> implements NodeEventEmitter {
13
+ /**
14
+ * @internal
15
+ */
16
+ readonly _context: V_Context;
12
17
  readonly path: string;
13
18
  off<T extends EventEmitter.EventNames<TEvents>>(event: T, fn?: (...args: any[]) => void, context?: any, once?: boolean): this;
14
19
  removeListener<T extends EventEmitter.EventNames<TEvents>>(event: T, fn?: (...args: any[]) => void, context?: any, once?: boolean): this;
15
- constructor(path: string);
20
+ constructor(
21
+ /**
22
+ * @internal
23
+ */
24
+ _context: V_Context, path: string);
16
25
  setMaxListeners(): never;
17
26
  getMaxListeners(): never;
18
27
  prependListener(): never;
@@ -32,7 +41,7 @@ export declare class FSWatcher<T extends string | Buffer = string | Buffer> exte
32
41
  error: [error: Error];
33
42
  }> implements fs.FSWatcher {
34
43
  readonly options: fs.WatchOptions;
35
- constructor(path: string, options: fs.WatchOptions);
44
+ constructor(context: V_Context, path: string, options: fs.WatchOptions);
36
45
  close(): void;
37
46
  [Symbol.dispose](): void;
38
47
  }
@@ -49,7 +58,7 @@ export declare class StatWatcher extends Watcher<{
49
58
  private options;
50
59
  private intervalId?;
51
60
  private previous?;
52
- constructor(path: string, options: {
61
+ constructor(context: V_Context, path: string, options: {
53
62
  persistent?: boolean;
54
63
  interval?: number;
55
64
  });
@@ -19,8 +19,13 @@ class Watcher extends EventEmitter {
19
19
  return super.removeListener(event, fn, context, once);
20
20
  }
21
21
  /* eslint-enable @typescript-eslint/no-explicit-any */
22
- constructor(path) {
22
+ constructor(
23
+ /**
24
+ * @internal
25
+ */
26
+ _context, path) {
23
27
  super();
28
+ this._context = _context;
24
29
  this.path = path;
25
30
  }
26
31
  setMaxListeners() {
@@ -51,8 +56,8 @@ class Watcher extends EventEmitter {
51
56
  * @template T The type of the filename, either `string` or `Buffer`.
52
57
  */
53
58
  export class FSWatcher extends Watcher {
54
- constructor(path, options) {
55
- super(path);
59
+ constructor(context, path, options) {
60
+ super(context, path);
56
61
  this.options = options;
57
62
  addWatcher(path.toString(), this);
58
63
  }
@@ -70,8 +75,8 @@ export class FSWatcher extends Watcher {
70
75
  * Instances of `StatWatcher` are used by `fs.watchFile()` to monitor changes to a file's statistics.
71
76
  */
72
77
  export class StatWatcher extends Watcher {
73
- constructor(path, options) {
74
- super(path);
78
+ constructor(context, path, options) {
79
+ super(context, path);
75
80
  this.options = options;
76
81
  this.start();
77
82
  }
@@ -130,6 +135,7 @@ export function removeWatcher(path, watcher) {
130
135
  }
131
136
  }
132
137
  export function emitChange(eventType, filename) {
138
+ var _a;
133
139
  filename = normalizePath(filename);
134
140
  // Notify watchers on the specific file
135
141
  if (watchers.has(filename)) {
@@ -142,10 +148,14 @@ export function emitChange(eventType, filename) {
142
148
  while (parent !== normalizedFilename) {
143
149
  normalizedFilename = parent;
144
150
  parent = dirname(parent);
145
- if (watchers.has(parent)) {
146
- for (const watcher of watchers.get(parent)) {
147
- watcher.emit('change', eventType, filename.slice(parent.length + (parent == '/' ? 0 : 1)));
148
- }
151
+ if (!watchers.has(parent))
152
+ continue;
153
+ for (const watcher of watchers.get(parent)) {
154
+ // Strip the context root from the path if the watcher has a context
155
+ const root = (_a = watcher._context) === null || _a === void 0 ? void 0 : _a.root;
156
+ const contextPath = root && filename.startsWith(root) ? filename.slice(root.length) : filename;
157
+ const relativePath = contextPath.slice(parent.length + (parent == '/' ? 0 : 1));
158
+ watcher.emit('change', eventType, relativePath);
149
159
  }
150
160
  }
151
161
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "1.6.12",
3
+ "version": "1.6.14",
4
4
  "description": "A filesystem, anywhere",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -59,11 +59,6 @@
59
59
  "dev": "npm run build -- --watch",
60
60
  "prepublishOnly": "npm run build"
61
61
  },
62
- "lint-staged": {
63
- "*": [
64
- "prettier --write"
65
- ]
66
- },
67
62
  "dependencies": {
68
63
  "@types/node": "^22.10.1",
69
64
  "@types/readable-stream": "^4.0.10",
@@ -73,7 +68,6 @@
73
68
  "utilium": "^1.1.1"
74
69
  },
75
70
  "optionalDependencies": {
76
- "minimatch": "^9.0.3",
77
71
  "c8": "^10.1.2"
78
72
  },
79
73
  "devDependencies": {
@@ -81,7 +75,6 @@
81
75
  "@types/eslint__js": "^8.42.3",
82
76
  "eslint": "^9.15.0",
83
77
  "globals": "^15.9.0",
84
- "lint-staged": "^15.2.7",
85
78
  "prettier": "^3.2.5",
86
79
  "tsx": "^4.19.1",
87
80
  "typedoc": "^0.27.1",
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { readdirSync, statSync, writeFileSync } from 'node:fs';
3
- import _path from 'node:path/posix';
3
+ import { matchesGlob, relative, join, resolve } from 'node:path/posix';
4
4
  import { parseArgs } from 'node:util';
5
5
 
6
6
  const { values: options, positionals } = parseArgs({
@@ -36,24 +36,6 @@ if (options.quiet && options.verbose) {
36
36
  process.exit();
37
37
  }
38
38
 
39
- let matchesGlob = _path.matchesGlob;
40
-
41
- if (matchesGlob && options.verbose) {
42
- console.debug('[debug] path.matchesGlob is available.');
43
- }
44
-
45
- if (!matchesGlob) {
46
- console.warn('Warning: path.matchesGlob is not available, falling back to minimatch. (Node 20.17.0+ or 22.5.0+ needed)');
47
-
48
- try {
49
- const { minimatch } = await import('minimatch');
50
- matchesGlob = minimatch;
51
- } catch {
52
- console.error('Fatal error: Failed to fall back to minimatch (is it installed?)');
53
- process.exit(1);
54
- }
55
- }
56
-
57
39
  function fixSlash(path) {
58
40
  return path.replaceAll('\\', '/');
59
41
  }
@@ -96,7 +78,7 @@ function computeEntries(path) {
96
78
  const stats = statSync(path);
97
79
 
98
80
  if (stats.isFile()) {
99
- entries.set('/' + _path.relative(resolvedRoot, path), stats);
81
+ entries.set('/' + relative(resolvedRoot, path), stats);
100
82
  if (options.verbose) {
101
83
  console.log(`${color('green', 'file')} ${path}`);
102
84
  }
@@ -104,9 +86,9 @@ function computeEntries(path) {
104
86
  }
105
87
 
106
88
  for (const file of readdirSync(path)) {
107
- computeEntries(_path.join(path, file));
89
+ computeEntries(join(path, file));
108
90
  }
109
- entries.set('/' + _path.relative(resolvedRoot, path), stats);
91
+ entries.set('/' + relative(resolvedRoot, path), stats);
110
92
  if (options.verbose) {
111
93
  console.log(`${color('bright_green', ' dir')} ${path}`);
112
94
  }
@@ -119,7 +101,7 @@ function computeEntries(path) {
119
101
 
120
102
  computeEntries(resolvedRoot);
121
103
  if (!options.quiet) {
122
- console.log('Generated listing for ' + fixSlash(_path.resolve(root)));
104
+ console.log('Generated listing for ' + fixSlash(resolve(root)));
123
105
  }
124
106
 
125
107
  const index = {