| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b2b6411 commit 88d3f74
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1189,6 +1189,55 @@ The `atime` and `mtime` arguments follow these rules: | |||
| 1189 | 1189 | * If the value can not be converted to a number, or is `NaN`, `Infinity` or | |
| 1190 | 1190 | `-Infinity`, an `Error` will be thrown. | |
| 1191 | 1191 | ||
| 1192 | + ### `fsPromises.watch(filename[, options])` | ||
| 1193 | + <!-- YAML | ||
| 1194 | + added: REPLACEME | ||
| 1195 | + --> | ||
| 1196 | + | ||
| 1197 | + * `filename` {string|Buffer|URL} | ||
| 1198 | + * `options` {string|Object} | ||
| 1199 | + * `persistent` {boolean} Indicates whether the process should continue to run | ||
| 1200 | + as long as files are being watched. **Default:** `true`. | ||
| 1201 | + * `recursive` {boolean} Indicates whether all subdirectories should be | ||
| 1202 | + watched, or only the current directory. This applies when a directory is | ||
| 1203 | + specified, and only on supported platforms (See [caveats][]). **Default:** | ||
| 1204 | + `false`. | ||
| 1205 | + * `encoding` {string} Specifies the character encoding to be used for the | ||
| 1206 | + filename passed to the listener. **Default:** `'utf8'`. | ||
| 1207 | + * `signal` {AbortSignal} An {AbortSignal} used to signal when the watcher | ||
| 1208 | + should stop. | ||
| 1209 | + * Returns: {AsyncIterator} of objects with the properties: | ||
| 1210 | + * `eventType` {string} The type of change | ||
| 1211 | + * `filename` {string|Buffer} The name of the file changed. | ||
| 1212 | + | ||
| 1213 | + Returns an async iterator that watches for changes on `filename`, where `filename` | ||
| 1214 | + is either a file or a directory. | ||
| 1215 | + | ||
| 1216 | + ```js | ||
| 1217 | + const { watch } = require('fs/promises'); | ||
| 1218 | + | ||
| 1219 | + const ac = new AbortController(); | ||
| 1220 | + const { signal } = ac; | ||
| 1221 | + setTimeout(() => ac.abort(), 10000); | ||
| 1222 | + | ||
| 1223 | + (async () => { | ||
| 1224 | + try { | ||
| 1225 | + const watcher = watch(__filename, { signal }); | ||
| 1226 | + for await (const event of watcher) | ||
| 1227 | + console.log(event); | ||
| 1228 | + } catch (err) { | ||
| 1229 | + if (err.name === 'AbortError') | ||
| 1230 | + return; | ||
| 1231 | + throw err; | ||
| 1232 | + } | ||
| 1233 | + })(); | ||
| 1234 | + ``` | ||
| 1235 | + | ||
| 1236 | + On most platforms, `'rename'` is emitted whenever a filename appears or | ||
| 1237 | + disappears in the directory. | ||
| 1238 | + | ||
| 1239 | + All the [caveats][] for `fs.watch()` also apply to `fsPromises.watch()`. | ||
| 1240 | + | ||
| 1192 | 1241 | ### `fsPromises.writeFile(file, data[, options])` | |
| 1193 | 1242 | <!-- YAML | |
| 1194 | 1243 | added: v10.0.0 | |
@@ -3477,7 +3526,7 @@ changes: | |||
| 3477 | 3526 | as long as files are being watched. **Default:** `true`. | |
| 3478 | 3527 | * `recursive` {boolean} Indicates whether all subdirectories should be | |
| 3479 | 3528 | watched, or only the current directory. This applies when a directory is | |
| 3480 | - specified, and only on supported platforms (See [Caveats][]). **Default:** | ||
| 3529 | + specified, and only on supported platforms (See [caveats][]). **Default:** | ||
| 3481 | 3530 | `false`. | |
| 3482 | 3531 | * `encoding` {string} Specifies the character encoding to be used for the | |
| 3483 | 3532 | filename passed to the listener. **Default:** `'utf8'`. | |
@@ -6550,7 +6599,6 @@ A call to `fs.ftruncate()` or `filehandle.truncate()` can be used to reset | |||
| 6550 | 6599 | the file contents. | |
| 6551 | 6600 | ||
| 6552 | 6601 | [#25741]: https://github.com/nodejs/node/issues/25741 | |
| 6553 | - [Caveats]: #fs_caveats | ||
| 6554 | 6602 | [Common System Errors]: errors.md#errors_common_system_errors | |
| 6555 | 6603 | [File access constants]: #fs_file_access_constants | |
| 6556 | 6604 | [MDN-Date]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date | |
@@ -6560,6 +6608,7 @@ the file contents. | |||
| 6560 | 6608 | [Naming Files, Paths, and Namespaces]: https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file | |
| 6561 | 6609 | [Readable Stream]: stream.md#stream_class_stream_readable | |
| 6562 | 6610 | [Writable Stream]: stream.md#stream_class_stream_writable | |
| 6611 | + [caveats]: #fs_caveats | ||
| 6563 | 6612 | [`AHAFS`]: https://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ | |
| 6564 | 6613 | [`Buffer.byteLength`]: buffer.md#buffer_static_method_buffer_bytelength_string_encoding | |
| 6565 | 6614 | [`FSEvents`]: https://developer.apple.com/documentation/coreservices/file_system_events | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -74,6 +74,7 @@ const { | |||
| 74 | 74 | const pathModule = require('path'); | |
| 75 | 75 | const { promisify } = require('internal/util'); | |
| 76 | 76 | const { EventEmitterMixin } = require('internal/event_target'); | |
| 77 | + const { watch } = require('internal/fs/watchers'); | ||
| 77 | 78 | ||
| 78 | 79 | const kHandle = Symbol('kHandle'); | |
| 79 | 80 | const kFd = Symbol('kFd'); | |
@@ -724,6 +725,7 @@ module.exports = { | |||
| 724 | 725 | writeFile, | |
| 725 | 726 | appendFile, | |
| 726 | 727 | readFile, | |
| 728 | + watch, | ||
| 727 | 729 | }, | |
| 728 | 730 | ||
| 729 | 731 | FileHandle, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,27 +4,52 @@ const { | |||
| 4 | 4 | FunctionPrototypeCall, | |
| 5 | 5 | ObjectDefineProperty, | |
| 6 | 6 | ObjectSetPrototypeOf, | |
| 7 | + Promise, | ||
| 7 | 8 | Symbol, | |
| 8 | 9 | } = primordials; | |
| 9 | 10 | ||
| 10 | - const errors = require('internal/errors'); | ||
| 11 | + const { | ||
| 12 | + AbortError, | ||
| 13 | + uvException, | ||
| 14 | + codes: { | ||
| 15 | + ERR_INVALID_ARG_VALUE, | ||
| 16 | + }, | ||
| 17 | + } = require('internal/errors'); | ||
| 18 | + | ||
| 11 | 19 | const { | |
| 12 | 20 | kFsStatsFieldsNumber, | |
| 13 | 21 | StatWatcher: _StatWatcher | |
| 14 | 22 | } = internalBinding('fs'); | |
| 23 | + | ||
| 15 | 24 | const { FSEvent } = internalBinding('fs_event_wrap'); | |
| 16 | 25 | const { UV_ENOSPC } = internalBinding('uv'); | |
| 17 | 26 | const { EventEmitter } = require('events'); | |
| 27 | + | ||
| 18 | 28 | const { | |
| 19 | 29 | getStatsFromBinding, | |
| 20 | 30 | getValidatedPath | |
| 21 | 31 | } = require('internal/fs/utils'); | |
| 32 | + | ||
| 22 | 33 | const { | |
| 23 | 34 | defaultTriggerAsyncIdScope, | |
| 24 | 35 | symbols: { owner_symbol } | |
| 25 | 36 | } = require('internal/async_hooks'); | |
| 37 | + | ||
| 26 | 38 | const { toNamespacedPath } = require('path'); | |
| 27 | - const { validateUint32 } = require('internal/validators'); | ||
| 39 | + | ||
| 40 | + const { | ||
| 41 | + validateAbortSignal, | ||
| 42 | + validateBoolean, | ||
| 43 | + validateObject, | ||
| 44 | + validateUint32, | ||
| 45 | + } = require('internal/validators'); | ||
| 46 | + | ||
| 47 | + const { | ||
| 48 | + Buffer: { | ||
| 49 | + isEncoding, | ||
| 50 | + }, | ||
| 51 | + } = require('buffer'); | ||
| 52 | + | ||
| 28 | 53 | const assert = require('internal/assert'); | |
| 29 | 54 | ||
| 30 | 55 | const kOldStatus = Symbol('kOldStatus'); | |
@@ -91,7 +116,7 @@ StatWatcher.prototype[kFSStatWatcherStart] = function(filename, | |||
| 91 | 116 | validateUint32(interval, 'interval'); | |
| 92 | 117 | const err = this._handle.start(toNamespacedPath(filename), interval); | |
| 93 | 118 | if (err) { | |
| 94 | - const error = errors.uvException({ | ||
| 119 | + const error = uvException({ | ||
| 95 | 120 | errno: err, | |
| 96 | 121 | syscall: 'watch', | |
| 97 | 122 | path: filename | |
@@ -176,7 +201,7 @@ function FSWatcher() { | |||
| 176 | 201 | this._handle.close(); | |
| 177 | 202 | this._handle = null; // Make the handle garbage collectable. | |
| 178 | 203 | } | |
| 179 | - const error = errors.uvException({ | ||
| 204 | + const error = uvException({ | ||
| 180 | 205 | errno: status, | |
| 181 | 206 | syscall: 'watch', | |
| 182 | 207 | path: filename | |
@@ -216,7 +241,7 @@ FSWatcher.prototype[kFSWatchStart] = function(filename, | |||
| 216 | 241 | recursive, | |
| 217 | 242 | encoding); | |
| 218 | 243 | if (err) { | |
| 219 | - const error = errors.uvException({ | ||
| 244 | + const error = uvException({ | ||
| 220 | 245 | errno: err, | |
| 221 | 246 | syscall: 'watch', | |
| 222 | 247 | path: filename, | |
@@ -270,10 +295,94 @@ ObjectDefineProperty(FSEvent.prototype, 'owner', { | |||
| 270 | 295 | set(v) { return this[owner_symbol] = v; } | |
| 271 | 296 | }); | |
| 272 | 297 | ||
| 298 | + async function* watch(filename, options = {}) { | ||
| 299 | + const path = toNamespacedPath(getValidatedPath(filename)); | ||
| 300 | + validateObject(options, 'options'); | ||
| 301 | + | ||
| 302 | + const { | ||
| 303 | + persistent = true, | ||
| 304 | + recursive = false, | ||
| 305 | + encoding = 'utf8', | ||
| 306 | + signal, | ||
| 307 | + } = options; | ||
| 308 | + | ||
| 309 | + validateBoolean(persistent, 'options.persistent'); | ||
| 310 | + validateBoolean(recursive, 'options.recursive'); | ||
| 311 | + validateAbortSignal(signal, 'options.signal'); | ||
| 312 | + | ||
| 313 | + if (encoding && !isEncoding(encoding)) { | ||
| 314 | + const reason = 'is invalid encoding'; | ||
| 315 | + throw new ERR_INVALID_ARG_VALUE(encoding, 'encoding', reason); | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + if (signal?.aborted) | ||
| 319 | + throw new AbortError(); | ||
| 320 | + | ||
| 321 | + const handle = new FSEvent(); | ||
| 322 | + let res; | ||
| 323 | + let rej; | ||
| 324 | + const oncancel = () => { | ||
| 325 | + handle.close(); | ||
| 326 | + rej(new AbortError()); | ||
| 327 | + }; | ||
| 328 | + | ||
| 329 | + try { | ||
| 330 | + signal?.addEventListener('abort', oncancel, { once: true }); | ||
| 331 | + | ||
| 332 | + let promise = new Promise((resolve, reject) => { | ||
| 333 | + res = resolve; | ||
| 334 | + rej = reject; | ||
| 335 | + }); | ||
| 336 | + | ||
| 337 | + handle.onchange = (status, eventType, filename) => { | ||
| 338 | + if (status < 0) { | ||
| 339 | + const error = uvException({ | ||
| 340 | + errno: status, | ||
| 341 | + syscall: 'watch', | ||
| 342 | + path: filename | ||
| 343 | + }); | ||
| 344 | + error.filename = filename; | ||
| 345 | + handle.close(); | ||
| 346 | + rej(error); | ||
| 347 | + return; | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + res({ eventType, filename }); | ||
| 351 | + }; | ||
| 352 | + | ||
| 353 | + const err = handle.start(path, persistent, recursive, encoding); | ||
| 354 | + if (err) { | ||
| 355 | + const error = uvException({ | ||
| 356 | + errno: err, | ||
| 357 | + syscall: 'watch', | ||
| 358 | + path: filename, | ||
| 359 | + message: err === UV_ENOSPC ? | ||
| 360 | + 'System limit for number of file watchers reached' : '' | ||
| 361 | + }); | ||
| 362 | + error.filename = filename; | ||
| 363 | + handle.close(); | ||
| 364 | + throw error; | ||
| 365 | + } | ||
| 366 | + | ||
| 367 | + while (!signal?.aborted) { | ||
| 368 | + yield await promise; | ||
| 369 | + promise = new Promise((resolve, reject) => { | ||
| 370 | + res = resolve; | ||
| 371 | + rej = reject; | ||
| 372 | + }); | ||
| 373 | + } | ||
| 374 | + throw new AbortError(); | ||
| 375 | + } finally { | ||
| 376 | + handle.close(); | ||
| 377 | + signal?.removeEventListener('abort', oncancel); | ||
| 378 | + } | ||
| 379 | + } | ||
| 380 | + | ||
| 273 | 381 | module.exports = { | |
| 274 | 382 | FSWatcher, | |
| 275 | 383 | StatWatcher, | |
| 276 | 384 | kFSWatchStart, | |
| 277 | 385 | kFSStatWatcherStart, | |
| 278 | 386 | kFSStatWatcherAddOrCleanRef, | |
| 387 | + watch, | ||
| 279 | 388 | }; | |
| 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 | 'Internal Binding worker', | |
| 35 | 37 | 'NativeModule buffer', | |
| 36 | 38 | 'NativeModule events', | |
@@ -51,6 +53,7 @@ const expectedModules = new Set([ | |||
| 51 | 53 | 'NativeModule internal/fs/utils', | |
| 52 | 54 | 'NativeModule internal/fs/promises', | |
| 53 | 55 | 'NativeModule internal/fs/rimraf', | |
| 56 | + 'NativeModule internal/fs/watchers', | ||
| 54 | 57 | 'NativeModule internal/idna', | |
| 55 | 58 | 'NativeModule internal/linkedlist', | |
| 56 | 59 | 'NativeModule internal/modules/run_main', | |
| Back | FazBrowse Home | New Git URL |
0 commit comments