Skip to content

Commit 590faab

Browse files
jazellyjakecastelli
andcommitted
watch: check parent and child path properly
co-authored-by: Jake Yuesong Li <[email protected]>
1 parent 59f00d7 commit 590faab

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

lib/internal/watch_mode/files_watcher.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const {
77
SafeMap,
88
SafeSet,
99
SafeWeakMap,
10-
StringPrototypeStartsWith,
10+
StringPrototypeStartsWith
1111
} = primordials;
1212

1313
const { validateNumber, validateOneOf } = require('internal/validators');
@@ -18,7 +18,7 @@ const EventEmitter = require('events');
1818
const { addAbortListener } = require('internal/events/abort_listener');
1919
const { watch } = require('fs');
2020
const { fileURLToPath } = require('internal/url');
21-
const { resolve, dirname } = require('path');
21+
const { resolve, dirname, sep } = require('path');
2222
const { setTimeout, clearTimeout } = require('timers');
2323

2424
const supportsRecursiveWatching = process.platform === 'win32' ||
@@ -52,13 +52,20 @@ class FilesWatcher extends EventEmitter {
5252
}
5353
}
5454

55+
#isParentPath(parentCandidate, childCandidate) {
56+
const parent = resolve(parentCandidate);
57+
const child = resolve(childCandidate);
58+
const normalizedParent = parent.endsWith(sep) ? parent : parent + sep;
59+
return StringPrototypeStartsWith(child, normalizedParent);
60+
}
61+
5562
#isPathWatched(path) {
5663
if (this.#watchers.has(path)) {
5764
return true;
5865
}
5966

6067
for (const { 0: watchedPath, 1: watcher } of this.#watchers.entries()) {
61-
if (watcher.recursive && StringPrototypeStartsWith(path, watchedPath)) {
68+
if (watcher.recursive && this.#isParentPath(watchedPath, path)) {
6269
return true;
6370
}
6471
}
@@ -68,7 +75,7 @@ class FilesWatcher extends EventEmitter {
6875

6976
#removeWatchedChildren(path) {
7077
for (const { 0: watchedPath, 1: watcher } of this.#watchers.entries()) {
71-
if (path !== watchedPath && StringPrototypeStartsWith(watchedPath, path)) {
78+
if (path !== watchedPath && this.#isParentPath(path, watchedPath)) {
7279
this.#unwatch(watcher);
7380
this.#watchers.delete(watchedPath);
7481
}

test/parallel/test-watch-mode-files_watcher.mjs

+33-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import path from 'node:path';
66
import assert from 'node:assert';
77
import process from 'node:process';
88
import { describe, it, beforeEach, afterEach } from 'node:test';
9-
import { writeFileSync, mkdirSync } from 'node:fs';
9+
import { writeFileSync, mkdirSync, appendFileSync } from 'node:fs';
1010
import { setTimeout } from 'node:timers/promises';
1111
import { once } from 'node:events';
1212
import { spawn } from 'node:child_process';
@@ -51,6 +51,38 @@ describe('watch mode file watcher', () => {
5151
assert.strictEqual(changesCount, 1);
5252
});
5353

54+
it('should watch changed files with same prefix path string', async () => {
55+
const ran1 = Promise.withResolvers();
56+
mkdirSync(tmpdir.resolve('subdir'));
57+
mkdirSync(tmpdir.resolve('sub'));
58+
const file1 = tmpdir.resolve('subdir', 'file1.mjs');
59+
const file2 = tmpdir.resolve('sub', 'file2.mjs');
60+
writeFileSync(file2, 'export const hello = () => { return "hello world"; };');
61+
writeFileSync(file1, 'import { hello } from "../sub/file2.mjs"; console.log(hello());');
62+
63+
let stdout = '';
64+
const child = spawn(process.execPath,
65+
['--watch', file1],
66+
{ encoding: 'utf8', stdio: 'pipe' });
67+
let completeCount = 0;
68+
child.stdout.on('data', async (data) => {
69+
stdout += data.toString();
70+
if (stdout.match(/Complete/g)) {
71+
completeCount++;
72+
}
73+
if (completeCount === 1) {
74+
ran1.resolve();
75+
}
76+
// The file is reloaded due to file watching
77+
if (completeCount === 2) {
78+
child.kill();
79+
await once(child, 'exit');
80+
}
81+
});
82+
await ran1.promise;
83+
appendFileSync(file1, '\n // append 1');
84+
});
85+
5486
it('should debounce changes', async () => {
5587
const file = tmpdir.resolve('file2');
5688
writeFileSync(file, 'written');

0 commit comments

Comments
 (0)