Skip to content

Commit 1d5e724

Browse files
committed
Fixed watchers not supporting contexts
1 parent 468a43c commit 1d5e724

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

src/emulation/async.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ export function watchFile(
588588
return;
589589
}
590590

591-
const watcher = new StatWatcher(normalizedPath, opts);
591+
const watcher = new StatWatcher(this, normalizedPath, opts);
592592
watcher.on('change', (curr: Stats, prev: Stats) => {
593593
const entry = statWatchers.get(normalizedPath);
594594
if (!entry) {
@@ -639,7 +639,7 @@ export function watch(
639639
options?: fs.WatchOptions | ((event: string, filename: string) => any),
640640
listener?: (event: string, filename: string) => any
641641
): FSWatcher {
642-
const watcher = new FSWatcher<string>(normalizePath(path), typeof options == 'object' ? options : {});
642+
const watcher = new FSWatcher<string>(this, normalizePath(path), typeof options == 'object' ? options : {});
643643
listener = typeof options == 'function' ? options : listener;
644644
watcher.on('change', listener || nop);
645645
return watcher;

src/emulation/promises.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -943,13 +943,17 @@ export async function realpath(this: V_Context, path: fs.PathLike, options?: fs.
943943
}
944944
realpath satisfies typeof promises.realpath;
945945

946-
export function watch(filename: fs.PathLike, options?: fs.WatchOptions | BufferEncoding): AsyncIterable<promises.FileChangeInfo<string>>;
947-
export function watch(filename: fs.PathLike, options: fs.WatchOptions | fs.BufferEncodingOption): AsyncIterable<promises.FileChangeInfo<Buffer>>;
948-
export function watch(filename: fs.PathLike, options?: fs.WatchOptions | string): AsyncIterable<promises.FileChangeInfo<string>> | AsyncIterable<promises.FileChangeInfo<Buffer>>;
949-
export function watch<T extends string | Buffer>(filename: fs.PathLike, options: fs.WatchOptions | string = {}): AsyncIterable<promises.FileChangeInfo<T>> {
946+
export function watch(this: V_Context, filename: fs.PathLike, options?: fs.WatchOptions | BufferEncoding): AsyncIterable<promises.FileChangeInfo<string>>;
947+
export function watch(this: V_Context, filename: fs.PathLike, options: fs.WatchOptions | fs.BufferEncodingOption): AsyncIterable<promises.FileChangeInfo<Buffer>>;
948+
export function watch(
949+
this: V_Context,
950+
filename: fs.PathLike,
951+
options?: fs.WatchOptions | string
952+
): AsyncIterable<promises.FileChangeInfo<string>> | AsyncIterable<promises.FileChangeInfo<Buffer>>;
953+
export function watch<T extends string | Buffer>(this: V_Context, filename: fs.PathLike, options: fs.WatchOptions | string = {}): AsyncIterable<promises.FileChangeInfo<T>> {
950954
return {
951955
[Symbol.asyncIterator](): AsyncIterator<promises.FileChangeInfo<T>> {
952-
const watcher = new FSWatcher<T>(filename.toString(), typeof options !== 'string' ? options : { encoding: options as BufferEncoding | 'buffer' });
956+
const watcher = new FSWatcher<T>(this, filename.toString(), typeof options !== 'string' ? options : { encoding: options as BufferEncoding | 'buffer' });
953957

954958
// A queue to hold change events, since we need to resolve them in the async iterator
955959
const eventQueue: ((value: IteratorResult<promises.FileChangeInfo<T>>) => void)[] = [];

src/emulation/watchers.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EventEmitter } from 'eventemitter3';
22
import type { EventEmitter as NodeEventEmitter } from 'node:events';
33
import type * as fs from 'node:fs';
4+
import type { V_Context } from '../context.js';
45
import { ErrnoError } from '../error.js';
56
import { isStatsEqual, type Stats } from '../stats.js';
67
import { normalizePath } from '../utils.js';
@@ -24,7 +25,13 @@ class Watcher<TEvents extends Record<string, unknown[]> = Record<string, unknown
2425
}
2526
/* eslint-enable @typescript-eslint/no-explicit-any */
2627

27-
public constructor(public readonly path: string) {
28+
public constructor(
29+
/**
30+
* @internal
31+
*/
32+
public readonly _context: V_Context,
33+
public readonly path: string
34+
) {
2835
super();
2936
}
3037

@@ -71,10 +78,11 @@ export class FSWatcher<T extends string | Buffer = string | Buffer>
7178
implements fs.FSWatcher
7279
{
7380
public constructor(
81+
context: V_Context,
7482
path: string,
7583
public readonly options: fs.WatchOptions
7684
) {
77-
super(path);
85+
super(context, path);
7886
addWatcher(path.toString(), this);
7987
}
8088

@@ -105,10 +113,11 @@ export class StatWatcher
105113
private previous?: Stats;
106114

107115
public constructor(
116+
context: V_Context,
108117
path: string,
109118
private options: { persistent?: boolean; interval?: number }
110119
) {
111-
super(path);
120+
super(context, path);
112121
this.start();
113122
}
114123

@@ -185,10 +194,16 @@ export function emitChange(eventType: fs.WatchEventType, filename: string) {
185194
while (parent !== normalizedFilename) {
186195
normalizedFilename = parent;
187196
parent = dirname(parent);
188-
if (watchers.has(parent)) {
189-
for (const watcher of watchers.get(parent)!) {
190-
watcher.emit('change', eventType, filename.slice(parent.length + (parent == '/' ? 0 : 1)));
191-
}
197+
if (!watchers.has(parent)) continue;
198+
199+
for (const watcher of watchers.get(parent)!) {
200+
// Strip the context root from the path if the watcher has a context
201+
202+
const root = watcher._context?.root;
203+
const contextPath = root && filename.startsWith(root) ? filename.slice(root.length) : filename;
204+
const relativePath = contextPath.slice(parent.length + (parent == '/' ? 0 : 1));
205+
206+
watcher.emit('change', eventType, relativePath);
192207
}
193208
}
194209
}

0 commit comments

Comments
 (0)