Skip to content

Commit 0c53c42

Browse files
committed
lib: support glob on --watch-path
1 parent 99c80e3 commit 0c53c42

File tree

3 files changed

+91
-6
lines changed

3 files changed

+91
-6
lines changed

lib/internal/fs/glob.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,4 +783,5 @@ module.exports = {
783783
__proto__: null,
784784
Glob,
785785
matchGlobPattern,
786+
createMatcher,
786787
};

lib/internal/main/watch_mode.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const {
3+
ArrayPrototypeFlatMap,
34
ArrayPrototypeForEach,
45
ArrayPrototypeJoin,
56
ArrayPrototypeMap,
@@ -27,14 +28,29 @@ const { inspect } = require('util');
2728
const { setTimeout, clearTimeout } = require('timers');
2829
const { resolve } = require('path');
2930
const { once } = require('events');
31+
const { createMatcher } = require('internal/fs/glob');
32+
const { globSync } = require('fs');
3033

3134
prepareMainThreadExecution(false, false);
3235
markBootstrapComplete();
3336

37+
function hasGlobPattern(path) {
38+
return createMatcher(path).hasMagic();
39+
}
40+
41+
function handleWatchedPath(path) {
42+
if (hasGlobPattern(path)) {
43+
const matchedFilesFromGlob = globSync(path);
44+
const resolvedMatchedFiles = ArrayPrototypeMap(matchedFilesFromGlob, (path) => resolve(path));
45+
return resolvedMatchedFiles;
46+
}
47+
return resolve(path);
48+
}
49+
3450
const kKillSignal = convertToValidSignal(getOptionValue('--watch-kill-signal'));
3551
const kShouldFilterModules = getOptionValue('--watch-path').length === 0;
3652
const kEnvFile = getOptionValue('--env-file') || getOptionValue('--env-file-if-exists');
37-
const kWatchedPaths = ArrayPrototypeMap(getOptionValue('--watch-path'), (path) => resolve(path));
53+
const kWatchedPaths = ArrayPrototypeFlatMap(getOptionValue('--watch-path'), (path) => handleWatchedPath(path));
3854
const kPreserveOutput = getOptionValue('--watch-preserve-output');
3955
const kCommand = ArrayPrototypeSlice(process.argv, 1);
4056
const kCommandStr = inspect(ArrayPrototypeJoin(kCommand, ' '));

test/sequential/test-watch-mode.mjs

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,21 @@ async function runWriteSucceed({
108108
let stderr = '';
109109
const stdout = [];
110110

111+
let watchedFiles = [];
112+
let currentWatchedFileIndex = 0;
113+
const isWatchingMultpileFiles = Array.isArray(watchedFile) && watchedFile.length > 1;
114+
const isWatchingSingleFile = !isWatchingMultpileFiles;
115+
116+
if (isWatchingMultpileFiles) {
117+
watchedFiles = watchedFile;
118+
restarts = watchedFiles.length + 1;
119+
}
120+
111121
child.stderr.on('data', (data) => {
112122
stderr += data;
113123
});
114124

125+
115126
try {
116127
// Break the chunks into lines
117128
for await (const data of createInterface({ input: child.stdout })) {
@@ -120,11 +131,22 @@ async function runWriteSucceed({
120131
}
121132
if (data.startsWith(completed)) {
122133
completes++;
123-
if (completes === restarts) {
124-
break;
125-
}
126-
if (completes === 1) {
127-
cancelRestarts = restart(watchedFile);
134+
if (isWatchingSingleFile) {
135+
if (completes === restarts) {
136+
break;
137+
}
138+
if (completes === 1) {
139+
cancelRestarts = restart(watchedFile);
140+
}
141+
} else {
142+
if (completes === restarts) {
143+
break;
144+
}
145+
if (completes < restarts) {
146+
cancelRestarts();
147+
const currentlyWatchedFile = watchedFiles[currentWatchedFileIndex++];
148+
cancelRestarts = restart(currentlyWatchedFile);
149+
}
128150
}
129151
}
130152

@@ -791,4 +813,50 @@ process.on('message', (message) => {
791813
`Completed running ${inspect(file)}. Waiting for file changes before restarting...`,
792814
]);
793815
});
816+
817+
it('should watch files from a given glob pattern --watch-path=./**/*.js', async () => {
818+
819+
const tmpDirForGlobTest = tmpdir.resolve('glob-test-dir');
820+
mkdirSync(tmpDirForGlobTest);
821+
822+
const globPattern = path.resolve(tmpDirForGlobTest, '**/*.js');
823+
824+
const directory1 = path.join(tmpDirForGlobTest, 'directory1');
825+
const directory2 = path.join(tmpDirForGlobTest, 'directory2');
826+
827+
mkdirSync(directory1);
828+
mkdirSync(directory2);
829+
830+
const tmpJsFile1 = createTmpFile('', '.js', directory1);
831+
const tmpJsFile2 = createTmpFile('', '.js', directory1);
832+
const tmpJsFile3 = createTmpFile('', '.js', directory2);
833+
const tmpJsFile4 = createTmpFile('', '.js', directory2);
834+
const tmpJsFile5 = createTmpFile('', '.js', directory2);
835+
836+
const mainJsFile = createTmpFile('console.log(\'running\')', '.js', tmpDirForGlobTest);
837+
838+
const args = ['--watch-path', globPattern, mainJsFile];
839+
const watchedFiles = [tmpJsFile1, tmpJsFile2, tmpJsFile3, tmpJsFile4, tmpJsFile5];
840+
841+
const { stderr, stdout } = await runWriteSucceed({
842+
args,
843+
watchedFile: watchedFiles,
844+
});
845+
846+
function expectRepeatedCompletes(n) {
847+
const expectedStdout = [];
848+
for (let i = 0; i < n; i++) {
849+
if (i !== 0) {
850+
expectedStdout.push(`Restarting ${inspect((mainJsFile))}`);
851+
}
852+
expectedStdout.push('running');
853+
expectedStdout.push(`Completed running ${inspect(mainJsFile)}. Waiting for file changes before restarting...`);
854+
}
855+
return expectedStdout;
856+
}
857+
858+
assert.strictEqual(stderr, '');
859+
assert.deepStrictEqual(stdout, expectRepeatedCompletes(6));
860+
861+
});
794862
});

0 commit comments

Comments
 (0)