| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -28,6 +28,7 @@ const { | |||
| 28 | 28 | ArrayPrototypeIncludes, | |
| 29 | 29 | ArrayPrototypeIndexOf, | |
| 30 | 30 | ArrayPrototypeJoin, | |
| 31 | + ArrayPrototypeMap, | ||
| 31 | 32 | ArrayPrototypePush, | |
| 32 | 33 | ArrayPrototypeSlice, | |
| 33 | 34 | ArrayPrototypeSplice, | |
@@ -191,7 +192,13 @@ function updateChildren(parent, child, scan) { | |||
| 191 | 192 | ||
| 192 | 193 | function reportModuleToWatchMode(filename) { | |
| 193 | 194 | if (shouldReportRequiredModules && process.send) { | |
| 194 | - process.send({ 'watch:require': filename }); | ||
| 195 | + process.send({ 'watch:require': [filename] }); | ||
| 196 | + } | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + function reportModuleNotFoundToWatchMode(basePath, extensions) { | ||
| 200 | + if (shouldReportRequiredModules && process.send) { | ||
| 201 | + process.send({ 'watch:require': ArrayPrototypeMap(extensions, (ext) => path.resolve(`${basePath}${ext}`)) }); | ||
| 195 | 202 | } | |
| 196 | 203 | } | |
| 197 | 204 | ||
@@ -648,6 +655,7 @@ Module._findPath = function(request, paths, isMain) { | |||
| 648 | 655 | Module._pathCache[cacheKey] = filename; | |
| 649 | 656 | return filename; | |
| 650 | 657 | } | |
| 658 | + reportModuleNotFoundToWatchMode(basePath, ArrayPrototypeConcat([''], exts)); | ||
| 651 | 659 | } | |
| 652 | 660 | ||
| 653 | 661 | return false; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -463,7 +463,7 @@ class ESMLoader { | |||
| 463 | 463 | ); | |
| 464 | 464 | ||
| 465 | 465 | if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { | |
| 466 | - process.send({ 'watch:import': url }); | ||
| 466 | + process.send({ 'watch:import': [url] }); | ||
| 467 | 467 | } | |
| 468 | 468 | ||
| 469 | 469 | const job = new ModuleJob( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -254,6 +254,9 @@ function finalizeResolution(resolved, base, preserveSymlinks) { | |||
| 254 | 254 | err.url = String(resolved); | |
| 255 | 255 | throw err; | |
| 256 | 256 | } else if (!stats.isFile()) { | |
| 257 | + if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { | ||
| 258 | + process.send({ 'watch:require': [path || resolved.pathname] }); | ||
| 259 | + } | ||
| 257 | 260 | throw new ERR_MODULE_NOT_FOUND( | |
| 258 | 261 | path || resolved.pathname, base && fileURLToPath(base), 'module'); | |
| 259 | 262 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,8 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | ||
| 3 | 3 | const { | |
| 4 | + ArrayIsArray, | ||
| 5 | + ArrayPrototypeForEach, | ||
| 4 | 6 | SafeMap, | |
| 5 | 7 | SafeSet, | |
| 6 | 8 | StringPrototypeStartsWith, | |
@@ -94,6 +96,7 @@ class FilesWatcher extends EventEmitter { | |||
| 94 | 96 | } | |
| 95 | 97 | ||
| 96 | 98 | filterFile(file) { | |
| 99 | + if (!file) return; | ||
| 97 | 100 | if (supportsRecursiveWatching) { | |
| 98 | 101 | this.watchPath(dirname(file)); | |
| 99 | 102 | } else { | |
@@ -109,11 +112,11 @@ class FilesWatcher extends EventEmitter { | |||
| 109 | 112 | } | |
| 110 | 113 | child.on('message', (message) => { | |
| 111 | 114 | try { | |
| 112 | - if (message['watch:require']) { | ||
| 113 | - this.filterFile(message['watch:require']); | ||
| 115 | + if (ArrayIsArray(message['watch:require'])) { | ||
| 116 | + ArrayPrototypeForEach(message['watch:require'], (file) => this.filterFile(file)); | ||
| 114 | 117 | } | |
| 115 | - if (message['watch:import']) { | ||
| 116 | - this.filterFile(fileURLToPath(message['watch:import'])); | ||
| 118 | + if (ArrayIsArray(message['watch:import'])) { | ||
| 119 | + ArrayPrototypeForEach(message['watch:import'], (file) => this.filterFile(fileURLToPath(file))); | ||
| 117 | 120 | } | |
| 118 | 121 | } catch { | |
| 119 | 122 | // Failed watching file. ignore | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,7 +6,7 @@ const tmpdir = require('../../common/tmpdir'); | |||
| 6 | 6 | const tmpfile = path.join(tmpdir.path, 'file'); | |
| 7 | 7 | fs.writeFileSync(tmpfile, ''); | |
| 8 | 8 | ||
| 9 | - process.send({ 'watch:require': path.resolve(__filename) }); | ||
| 10 | - process.send({ 'watch:import': url.pathToFileURL(path.resolve(__filename)).toString() }); | ||
| 11 | - process.send({ 'watch:import': url.pathToFileURL(tmpfile).toString() }); | ||
| 12 | - process.send({ 'watch:import': new URL('http://invalid.com').toString() }); | ||
| 9 | + process.send({ 'watch:require': [path.resolve(__filename)] }); | ||
| 10 | + process.send({ 'watch:import': [url.pathToFileURL(path.resolve(__filename)).toString()] }); | ||
| 11 | + process.send({ 'watch:import': [url.pathToFileURL(tmpfile).toString()] }); | ||
| 12 | + process.send({ 'watch:import': [new URL('http://invalid.com').toString()] }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,10 +9,13 @@ import { spawn } from 'node:child_process'; | |||
| 9 | 9 | import { writeFileSync, readFileSync } from 'node:fs'; | |
| 10 | 10 | import { inspect } from 'node:util'; | |
| 11 | 11 | import { once } from 'node:events'; | |
| 12 | + import { createInterface } from 'node:readline/promises'; | ||
| 12 | 13 | ||
| 13 | 14 | if (common.isIBMi) | |
| 14 | 15 | common.skip('IBMi does not support `fs.watch()`'); | |
| 15 | 16 | ||
| 17 | + const supportsRecursive = common.isOSX || common.isWindows; | ||
| 18 | + | ||
| 16 | 19 | function restart(file) { | |
| 17 | 20 | // To avoid flakiness, we save the file repeatedly until test is done | |
| 18 | 21 | writeFileSync(file, readFileSync(file)); | |
@@ -59,8 +62,8 @@ async function spawnWithRestarts({ | |||
| 59 | 62 | } | |
| 60 | 63 | ||
| 61 | 64 | let tmpFiles = 0; | |
| 62 | - function createTmpFile(content = 'console.log("running");') { | ||
| 63 | - const file = path.join(tmpdir.path, `${tmpFiles++}.js`); | ||
| 65 | + function createTmpFile(content = 'console.log("running");', ext = '.js') { | ||
| 66 | + const file = path.join(tmpdir.path, `${tmpFiles++}${ext}`); | ||
| 64 | 67 | writeFileSync(file, content); | |
| 65 | 68 | return file; | |
| 66 | 69 | } | |
@@ -74,11 +77,29 @@ function assertRestartedCorrectly({ stdout, messages: { inner, completed, restar | |||
| 74 | 77 | assert.deepStrictEqual(lines.slice(-end.length), end); | |
| 75 | 78 | } | |
| 76 | 79 | ||
| 80 | + async function failWriteSucceed({ file, watchedFile }) { | ||
| 81 | + const child = spawn(execPath, ['--watch', '--no-warnings', file], { encoding: 'utf8' }); | ||
| 82 | + | ||
| 83 | + try { | ||
| 84 | + // Break the chunks into lines | ||
| 85 | + for await (const data of createInterface({ input: child.stdout })) { | ||
| 86 | + if (data.startsWith('Completed running')) { | ||
| 87 | + break; | ||
| 88 | + } | ||
| 89 | + if (data.startsWith('Failed running')) { | ||
| 90 | + writeFileSync(watchedFile, 'console.log("test has ran");'); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + } finally { | ||
| 94 | + child.kill(); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + | ||
| 77 | 98 | tmpdir.refresh(); | |
| 78 | 99 | ||
| 79 | 100 | // Warning: this suite can run safely with concurrency: true | |
| 80 | 101 | // only if tests do not watch/depend on the same files | |
| 81 | - describe('watch mode', { concurrency: true, timeout: 60_0000 }, () => { | ||
| 102 | + describe('watch mode', { concurrency: true, timeout: 60_000 }, () => { | ||
| 82 | 103 | it('should watch changes to a file - event loop ended', async () => { | |
| 83 | 104 | const file = createTmpFile(); | |
| 84 | 105 | const { stderr, stdout } = await spawnWithRestarts({ file }); | |
@@ -104,16 +125,8 @@ describe('watch mode', { concurrency: true, timeout: 60_0000 }, () => { | |||
| 104 | 125 | }); | |
| 105 | 126 | }); | |
| 106 | 127 | ||
| 107 | - it('should not watch when running an non-existing file', async () => { | ||
| 108 | - const file = fixtures.path('watch-mode/non-existing.js'); | ||
| 109 | - const { stderr, stdout } = await spawnWithRestarts({ file, restarts: 0 }); | ||
| 110 | - | ||
| 111 | - assert.match(stderr, /code: 'MODULE_NOT_FOUND'/); | ||
| 112 | - assert.strictEqual(stdout, `Failed running ${inspect(file)}\n`); | ||
| 113 | - }); | ||
| 114 | - | ||
| 115 | 128 | it('should watch when running an non-existing file - when specified under --watch-path', { | |
| 116 | - skip: !common.isOSX && !common.isWindows | ||
| 129 | + skip: !supportsRecursive | ||
| 117 | 130 | }, async () => { | |
| 118 | 131 | const file = fixtures.path('watch-mode/subdir/non-existing.js'); | |
| 119 | 132 | const watchedFile = fixtures.path('watch-mode/subdir/file.js'); | |
@@ -220,4 +233,39 @@ describe('watch mode', { concurrency: true, timeout: 60_0000 }, () => { | |||
| 220 | 233 | messages: { restarted: `Restarting ${inspect(file)}`, completed: `Completed running ${inspect(file)}` }, | |
| 221 | 234 | }); | |
| 222 | 235 | }); | |
| 236 | + | ||
| 237 | + // TODO: Remove skip after https://github.com/nodejs/node/pull/45271 lands | ||
| 238 | + it('should not watch when running an missing file', { | ||
| 239 | + skip: !supportsRecursive | ||
| 240 | + }, async () => { | ||
| 241 | + const nonExistingfile = path.join(tmpdir.path, `${tmpFiles++}.js`); | ||
| 242 | + await failWriteSucceed({ file: nonExistingfile, watchedFile: nonExistingfile }); | ||
| 243 | + }); | ||
| 244 | + | ||
| 245 | + it('should not watch when running an missing mjs file', { | ||
| 246 | + skip: !supportsRecursive | ||
| 247 | + }, async () => { | ||
| 248 | + const nonExistingfile = path.join(tmpdir.path, `${tmpFiles++}.mjs`); | ||
| 249 | + await failWriteSucceed({ file: nonExistingfile, watchedFile: nonExistingfile }); | ||
| 250 | + }); | ||
| 251 | + | ||
| 252 | + it('should watch changes to previously missing dependency', { | ||
| 253 | + skip: !supportsRecursive | ||
| 254 | + }, async () => { | ||
| 255 | + const dependency = path.join(tmpdir.path, `${tmpFiles++}.js`); | ||
| 256 | + const relativeDependencyPath = `./${path.basename(dependency)}`; | ||
| 257 | + const dependant = createTmpFile(`console.log(require('${relativeDependencyPath}'))`); | ||
| 258 | + | ||
| 259 | + await failWriteSucceed({ file: dependant, watchedFile: dependency }); | ||
| 260 | + }); | ||
| 261 | + | ||
| 262 | + it('should watch changes to previously missing ESM dependency', { | ||
| 263 | + skip: !supportsRecursive | ||
| 264 | + }, async () => { | ||
| 265 | + const dependency = path.join(tmpdir.path, `${tmpFiles++}.mjs`); | ||
| 266 | + const relativeDependencyPath = `./${path.basename(dependency)}`; | ||
| 267 | + const dependant = createTmpFile(`import '${relativeDependencyPath}'`, '.mjs'); | ||
| 268 | + | ||
| 269 | + await failWriteSucceed({ file: dependant, watchedFile: dependency }); | ||
| 270 | + }); | ||
| 223 | 271 | }); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments