| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent f5b2fe1 commit fe12cc0
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1181,6 +1181,55 @@ The `atime` and `mtime` arguments follow these rules: | |||
| 1181 | 1181 | * If the value can not be converted to a number, or is `NaN`, `Infinity` or | |
| 1182 | 1182 | `-Infinity`, an `Error` will be thrown. | |
| 1183 | 1183 | ||
| 1184 | + ### `fsPromises.watch(filename[, options])` | ||
| 1185 | + <!-- YAML | ||
| 1186 | + added: REPLACEME | ||
| 1187 | + --> | ||
| 1188 | + | ||
| 1189 | + * `filename` {string|Buffer|URL} | ||
| 1190 | + * `options` {string|Object} | ||
| 1191 | + * `persistent` {boolean} Indicates whether the process should continue to run | ||
| 1192 | + as long as files are being watched. **Default:** `true`. | ||
| 1193 | + * `recursive` {boolean} Indicates whether all subdirectories should be | ||
| 1194 | + watched, or only the current directory. This applies when a directory is | ||
| 1195 | + specified, and only on supported platforms (See [caveats][]). **Default:** | ||
| 1196 | + `false`. | ||
| 1197 | + * `encoding` {string} Specifies the character encoding to be used for the | ||
| 1198 | + filename passed to the listener. **Default:** `'utf8'`. | ||
| 1199 | + * `signal` {AbortSignal} An {AbortSignal} used to signal when the watcher | ||
| 1200 | + should stop. | ||
| 1201 | + * Returns: {AsyncIterator} of objects with the properties: | ||
| 1202 | + * `eventType` {string} The type of change | ||
| 1203 | + * `filename` {string|Buffer} The name of the file changed. | ||
| 1204 | + | ||
| 1205 | + Returns an async iterator that watches for changes on `filename`, where `filename` | ||
| 1206 | + is either a file or a directory. | ||
| 1207 | + | ||
| 1208 | + ```js | ||
| 1209 | + const { watch } = require('fs/promises'); | ||
| 1210 | + | ||
| 1211 | + const ac = new AbortController(); | ||
| 1212 | + const { signal } = ac; | ||
| 1213 | + setTimeout(() => ac.abort(), 10000); | ||
| 1214 | + | ||
| 1215 | + (async () => { | ||
| 1216 | + try { | ||
| 1217 | + const watcher = watch(__filename, { signal }); | ||
| 1218 | + for await (const event of watcher) | ||
| 1219 | + console.log(event); | ||
| 1220 | + } catch (err) { | ||
| 1221 | + if (err.name === 'AbortError') | ||
| 1222 | + return; | ||
| 1223 | + throw err; | ||
| 1224 | + } | ||
| 1225 | + })(); | ||
| 1226 | + ``` | ||
| 1227 | + | ||
| 1228 | + On most platforms, `'rename'` is emitted whenever a filename appears or | ||
| 1229 | + disappears in the directory. | ||
| 1230 | + | ||
| 1231 | + All the [caveats][] for `fs.watch()` also apply to `fsPromises.watch()`. | ||
| 1232 | + | ||
| 1184 | 1233 | ### `fsPromises.writeFile(file, data[, options])` | |
| 1185 | 1234 | <!-- YAML | |
| 1186 | 1235 | added: v10.0.0 | |
@@ -3461,7 +3510,7 @@ changes: | |||
| 3461 | 3510 | as long as files are being watched. **Default:** `true`. | |
| 3462 | 3511 | * `recursive` {boolean} Indicates whether all subdirectories should be | |
| 3463 | 3512 | watched, or only the current directory. This applies when a directory is | |
| 3464 | - specified, and only on supported platforms (See [Caveats][]). **Default:** | ||
| 3513 | + specified, and only on supported platforms (See [caveats][]). **Default:** | ||
| 3465 | 3514 | `false`. | |
| 3466 | 3515 | * `encoding` {string} Specifies the character encoding to be used for the | |
| 3467 | 3516 | filename passed to the listener. **Default:** `'utf8'`. | |
@@ -6534,7 +6583,6 @@ A call to `fs.ftruncate()` or `filehandle.truncate()` can be used to reset | |||
| 6534 | 6583 | the file contents. | |
| 6535 | 6584 | ||
| 6536 | 6585 | [#25741]: https://github.com/nodejs/node/issues/25741 | |
| 6537 | - [Caveats]: #fs_caveats | ||
| 6538 | 6586 | [Common System Errors]: errors.md#errors_common_system_errors | |
| 6539 | 6587 | [File access constants]: #fs_file_access_constants | |
| 6540 | 6588 | [MDN-Date]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date | |
@@ -6544,6 +6592,7 @@ the file contents. | |||
| 6544 | 6592 | [Naming Files, Paths, and Namespaces]: https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file | |
| 6545 | 6593 | [Readable Stream]: stream.md#stream_class_stream_readable | |
| 6546 | 6594 | [Writable Stream]: stream.md#stream_class_stream_writable | |
| 6595 | + [caveats]: #fs_caveats | ||
| 6547 | 6596 | [`AHAFS`]: https://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ | |
| 6548 | 6597 | [`Buffer.byteLength`]: buffer.md#buffer_static_method_buffer_bytelength_string_encoding | |
| 6549 | 6598 | [`FSEvents`]: https://developer.apple.com/documentation/coreservices/file_system_events | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -72,6 +72,7 @@ const { | |||
| 72 | 72 | } = require('internal/validators'); | |
| 73 | 73 | const pathModule = require('path'); | |
| 74 | 74 | const { promisify } = require('internal/util'); | |
| 75 | + const { watch } = require('internal/fs/watchers'); | ||
| 75 | 76 | ||
| 76 | 77 | const kHandle = Symbol('kHandle'); | |
| 77 | 78 | const kFd = Symbol('kFd'); | |
@@ -713,6 +714,7 @@ module.exports = { | |||
| 713 | 714 | writeFile, | |
| 714 | 715 | appendFile, | |
| 715 | 716 | readFile, | |
| 717 | + watch, | ||
| 716 | 718 | }, | |
| 717 | 719 | ||
| 718 | 720 | FileHandle | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,27 +3,52 @@ | |||
| 3 | 3 | const { | |
| 4 | 4 | ObjectDefineProperty, | |
| 5 | 5 | ObjectSetPrototypeOf, | |
| 6 | + Promise, | ||
| 6 | 7 | Symbol, | |
| 7 | 8 | } = primordials; | |
| 8 | 9 | ||
| 9 | - const errors = require('internal/errors'); | ||
| 10 | + const { | ||
| 11 | + AbortError, | ||
| 12 | + uvException, | ||
| 13 | + codes: { | ||
| 14 | + ERR_INVALID_ARG_VALUE, | ||
| 15 | + }, | ||
| 16 | + } = require('internal/errors'); | ||
| 17 | + | ||
| 10 | 18 | const { | |
| 11 | 19 | kFsStatsFieldsNumber, | |
| 12 | 20 | StatWatcher: _StatWatcher | |
| 13 | 21 | } = internalBinding('fs'); | |
| 22 | + | ||
| 14 | 23 | const { FSEvent } = internalBinding('fs_event_wrap'); | |
| 15 | 24 | const { UV_ENOSPC } = internalBinding('uv'); | |
| 16 | 25 | const { EventEmitter } = require('events'); | |
| 26 | + | ||
| 17 | 27 | const { | |
| 18 | 28 | getStatsFromBinding, | |
| 19 | 29 | getValidatedPath | |
| 20 | 30 | } = require('internal/fs/utils'); | |
| 31 | + | ||
| 21 | 32 | const { | |
| 22 | 33 | defaultTriggerAsyncIdScope, | |
| 23 | 34 | symbols: { owner_symbol } | |
| 24 | 35 | } = require('internal/async_hooks'); | |
| 36 | + | ||
| 25 | 37 | const { toNamespacedPath } = require('path'); | |
| 26 | - const { validateUint32 } = require('internal/validators'); | ||
| 38 | + | ||
| 39 | + const { | ||
| 40 | + validateAbortSignal, | ||
| 41 | + validateBoolean, | ||
| 42 | + validateObject, | ||
| 43 | + validateUint32, | ||
| 44 | + } = require('internal/validators'); | ||
| 45 | + | ||
| 46 | + const { | ||
| 47 | + Buffer: { | ||
| 48 | + isEncoding, | ||
| 49 | + }, | ||
| 50 | + } = require('buffer'); | ||
| 51 | + | ||
| 27 | 52 | const assert = require('internal/assert'); | |
| 28 | 53 | ||
| 29 | 54 | const kOldStatus = Symbol('kOldStatus'); | |
@@ -90,7 +115,7 @@ StatWatcher.prototype[kFSStatWatcherStart] = function(filename, | |||
| 90 | 115 | validateUint32(interval, 'interval'); | |
| 91 | 116 | const err = this._handle.start(toNamespacedPath(filename), interval); | |
| 92 | 117 | if (err) { | |
| 93 | - const error = errors.uvException({ | ||
| 118 | + const error = uvException({ | ||
| 94 | 119 | errno: err, | |
| 95 | 120 | syscall: 'watch', | |
| 96 | 121 | path: filename | |
@@ -175,7 +200,7 @@ function FSWatcher() { | |||
| 175 | 200 | this._handle.close(); | |
| 176 | 201 | this._handle = null; // Make the handle garbage collectable. | |
| 177 | 202 | } | |
| 178 | - const error = errors.uvException({ | ||
| 203 | + const error = uvException({ | ||
| 179 | 204 | errno: status, | |
| 180 | 205 | syscall: 'watch', | |
| 181 | 206 | path: filename | |
@@ -215,7 +240,7 @@ FSWatcher.prototype[kFSWatchStart] = function(filename, | |||
| 215 | 240 | recursive, | |
| 216 | 241 | encoding); | |
| 217 | 242 | if (err) { | |
| 218 | - const error = errors.uvException({ | ||
| 243 | + const error = uvException({ | ||
| 219 | 244 | errno: err, | |
| 220 | 245 | syscall: 'watch', | |
| 221 | 246 | path: filename, | |
@@ -269,10 +294,94 @@ ObjectDefineProperty(FSEvent.prototype, 'owner', { | |||
| 269 | 294 | set(v) { return this[owner_symbol] = v; } | |
| 270 | 295 | }); | |
| 271 | 296 | ||
| 297 | + async function* watch(filename, options = {}) { | ||
| 298 | + const path = toNamespacedPath(getValidatedPath(filename)); | ||
| 299 | + validateObject(options, 'options'); | ||
| 300 | + | ||
| 301 | + const { | ||
| 302 | + persistent = true, | ||
| 303 | + recursive = false, | ||
| 304 | + encoding = 'utf8', | ||
| 305 | + signal, | ||
| 306 | + } = options; | ||
| 307 | + | ||
| 308 | + validateBoolean(persistent, 'options.persistent'); | ||
| 309 | + validateBoolean(recursive, 'options.recursive'); | ||
| 310 | + validateAbortSignal(signal, 'options.signal'); | ||
| 311 | + | ||
| 312 | + if (encoding && !isEncoding(encoding)) { | ||
| 313 | + const reason = 'is invalid encoding'; | ||
| 314 | + throw new ERR_INVALID_ARG_VALUE(encoding, 'encoding', reason); | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + if (signal?.aborted) | ||
| 318 | + throw new AbortError(); | ||
| 319 | + | ||
| 320 | + const handle = new FSEvent(); | ||
| 321 | + let res; | ||
| 322 | + let rej; | ||
| 323 | + const oncancel = () => { | ||
| 324 | + handle.close(); | ||
| 325 | + rej(new AbortError()); | ||
| 326 | + }; | ||
| 327 | + | ||
| 328 | + try { | ||
| 329 | + signal?.addEventListener('abort', oncancel, { once: true }); | ||
| 330 | + | ||
| 331 | + let promise = new Promise((resolve, reject) => { | ||
| 332 | + res = resolve; | ||
| 333 | + rej = reject; | ||
| 334 | + }); | ||
| 335 | + | ||
| 336 | + handle.onchange = (status, eventType, filename) => { | ||
| 337 | + if (status < 0) { | ||
| 338 | + const error = uvException({ | ||
| 339 | + errno: status, | ||
| 340 | + syscall: 'watch', | ||
| 341 | + path: filename | ||
| 342 | + }); | ||
| 343 | + error.filename = filename; | ||
| 344 | + handle.close(); | ||
| 345 | + rej(error); | ||
| 346 | + return; | ||
| 347 | + } | ||
| 348 | + | ||
| 349 | + res({ eventType, filename }); | ||
| 350 | + }; | ||
| 351 | + | ||
| 352 | + const err = handle.start(path, persistent, recursive, encoding); | ||
| 353 | + if (err) { | ||
| 354 | + const error = uvException({ | ||
| 355 | + errno: err, | ||
| 356 | + syscall: 'watch', | ||
| 357 | + path: filename, | ||
| 358 | + message: err === UV_ENOSPC ? | ||
| 359 | + 'System limit for number of file watchers reached' : '' | ||
| 360 | + }); | ||
| 361 | + error.filename = filename; | ||
| 362 | + handle.close(); | ||
| 363 | + throw error; | ||
| 364 | + } | ||
| 365 | + | ||
| 366 | + while (!signal?.aborted) { | ||
| 367 | + yield await promise; | ||
| 368 | + promise = new Promise((resolve, reject) => { | ||
| 369 | + res = resolve; | ||
| 370 | + rej = reject; | ||
| 371 | + }); | ||
| 372 | + } | ||
| 373 | + throw new AbortError(); | ||
| 374 | + } finally { | ||
| 375 | + handle.close(); | ||
| 376 | + signal?.removeEventListener('abort', oncancel); | ||
| 377 | + } | ||
| 378 | + } | ||
| 379 | + | ||
| 272 | 380 | module.exports = { | |
| 273 | 381 | FSWatcher, | |
| 274 | 382 | StatWatcher, | |
| 275 | 383 | kFSWatchStart, | |
| 276 | 384 | kFSStatWatcherStart, | |
| 277 | 385 | kFSStatWatcherAddOrCleanRef, | |
| 386 | + watch, | ||
| 278 | 387 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,6 +17,7 @@ const expectedModules = new Set([ | |||
| 17 | 17 | 'Internal Binding credentials', | |
| 18 | 18 | 'Internal Binding fs', | |
| 19 | 19 | 'Internal Binding fs_dir', | |
| 20 | + 'Internal Binding fs_event_wrap', | ||
| 20 | 21 | 'Internal Binding messaging', | |
| 21 | 22 | 'Internal Binding module_wrap', | |
| 22 | 23 | 'Internal Binding native_module', | |
@@ -31,6 +32,7 @@ const expectedModules = new Set([ | |||
| 31 | 32 | 'Internal Binding types', | |
| 32 | 33 | 'Internal Binding url', | |
| 33 | 34 | 'Internal Binding util', | |
| 35 | + 'Internal Binding uv', | ||
| 34 | 36 | 'NativeModule async_hooks', | |
| 35 | 37 | 'NativeModule buffer', | |
| 36 | 38 | 'NativeModule events', | |
@@ -49,6 +51,7 @@ const expectedModules = new Set([ | |||
| 49 | 51 | 'NativeModule internal/fs/utils', | |
| 50 | 52 | 'NativeModule internal/fs/promises', | |
| 51 | 53 | 'NativeModule internal/fs/rimraf', | |
| 54 | + 'NativeModule internal/fs/watchers', | ||
| 52 | 55 | 'NativeModule internal/idna', | |
| 53 | 56 | 'NativeModule internal/linkedlist', | |
| 54 | 57 | 'NativeModule internal/modules/run_main', | |
| Back | FazBrowse Home | New Git URL |
0 commit comments