11'use strict' ;
22
33const {
4+ ArrayPrototypePush,
5+ ArrayPrototypeShift,
6+ Error,
47 FunctionPrototypeCall,
58 ObjectDefineProperty,
69 ObjectSetPrototypeOf,
@@ -12,9 +15,11 @@ const {
1215 AbortError,
1316 UVException,
1417 codes : {
18+ ERR_FS_WATCH_QUEUE_OVERFLOW ,
1519 ERR_INVALID_ARG_VALUE ,
1620 } ,
1721} = require ( 'internal/errors' ) ;
22+
1823const {
1924 kEmptyObject,
2025} = require ( 'internal/util' ) ;
@@ -45,6 +50,8 @@ const {
4550 validateBoolean,
4651 validateObject,
4752 validateUint32,
53+ validateInteger,
54+ validateOneOf,
4855} = require ( 'internal/validators' ) ;
4956
5057const {
@@ -309,11 +316,15 @@ async function* watch(filename, options = kEmptyObject) {
309316 persistent = true ,
310317 recursive = false ,
311318 encoding = 'utf8' ,
319+ maxQueue = 2048 ,
320+ overflow = 'ignore' ,
312321 signal,
313322 } = options ;
314323
315324 validateBoolean ( persistent , 'options.persistent' ) ;
316325 validateBoolean ( recursive , 'options.recursive' ) ;
326+ validateInteger ( maxQueue , 'options.maxQueue' ) ;
327+ validateOneOf ( overflow , 'options.overflow' , [ 'ignore' , 'error' ] ) ;
317328 validateAbortSignal ( signal , 'options.signal' ) ;
318329
319330 if ( encoding && ! isEncoding ( encoding ) ) {
@@ -325,10 +336,11 @@ async function* watch(filename, options = kEmptyObject) {
325336 throw new AbortError ( undefined , { cause : signal . reason } ) ;
326337
327338 const handle = new FSEvent ( ) ;
328- let { promise, resolve, reject } = PromiseWithResolvers ( ) ;
339+ let { promise, resolve } = PromiseWithResolvers ( ) ;
340+ const queue = [ ] ;
329341 const oncancel = ( ) => {
330342 handle . close ( ) ;
331- reject ( new AbortError ( undefined , { cause : signal ?. reason } ) ) ;
343+ resolve ( ) ;
332344 } ;
333345
334346 try {
@@ -345,11 +357,20 @@ async function* watch(filename, options = kEmptyObject) {
345357 } ) ;
346358 error . filename = filename ;
347359 handle . close ( ) ;
348- reject ( error ) ;
360+ ArrayPrototypePush ( queue , error ) ;
361+ resolve ( ) ;
349362 return ;
350363 }
351-
352- resolve ( { eventType, filename } ) ;
364+ if ( queue . length < maxQueue ) {
365+ ArrayPrototypePush ( queue , { __proto__ : null , eventType, filename } ) ;
366+ resolve ( ) ;
367+ } else if ( overflow === 'error' ) {
368+ queue . length = 0 ;
369+ ArrayPrototypePush ( queue , new ERR_FS_WATCH_QUEUE_OVERFLOW ( maxQueue ) ) ;
370+ resolve ( ) ;
371+ } else {
372+ process . emitWarning ( 'fs.watch maxQueue exceeded' ) ;
373+ }
353374 } ;
354375
355376 const err = handle . start ( path , persistent , recursive , encoding ) ;
@@ -367,10 +388,20 @@ async function* watch(filename, options = kEmptyObject) {
367388 }
368389
369390 while ( ! signal ?. aborted ) {
370- yield await promise ;
371- ( { promise, resolve, reject } = PromiseWithResolvers ( ) ) ;
391+ await promise ;
392+ while ( queue . length ) {
393+ const item = ArrayPrototypeShift ( queue ) ;
394+ if ( item instanceof Error ) {
395+ throw item ;
396+ } else {
397+ yield item ;
398+ }
399+ }
400+ ( { promise, resolve } = PromiseWithResolvers ( ) ) ;
401+ }
402+ if ( signal ?. aborted ) {
403+ throw new AbortError ( undefined , { cause : signal ?. reason } ) ;
372404 }
373- throw new AbortError ( undefined , { cause : signal ?. reason } ) ;
374405 } finally {
375406 handle . close ( ) ;
376407 signal ?. removeEventListener ( 'abort' , oncancel ) ;
0 commit comments