@@ -62,6 +62,10 @@ final class _Watcher {
6262  /// The graph of stylesheets being compiled. 
6363final  StylesheetGraph  _graph;
6464
65+   /// A map from source paths to destinations that need to be recompiled once 
66+   /// the current batch of events has been processed. 
67+ final  Map <String , String > _toRecompile =  {};
68+ 
6569  _Watcher (this ._options, this ._graph);
6670
6771  /// Deletes the file at [path]  and prints a message about it. 
@@ -82,70 +86,75 @@ final class _Watcher {
8286  /// 
8387  /// Returns a future that will only complete if an unexpected error occurs. 
8488Future <void > watch (MultiDirWatcher  watcher) async  {
85-     await  for  (var  event in  _debounceEvents (watcher.events)) {
86-       var  extension  =  p.extension (event.path);
87-       if  (extension  !=  '.sass'  &&  extension  !=  '.scss'  &&  extension  !=  '.css' ) {
88-         continue ;
89+     await  for  (var  batch in  _debounceEvents (watcher.events)) {
90+       for  (var  event in  batch) {
91+         var  extension  =  p.extension (event.path);
92+         if  (extension  !=  '.sass'  && 
93+             extension  !=  '.scss'  && 
94+             extension  !=  '.css' ) {
95+           continue ;
96+         }
97+ 
98+         switch  (event.type) {
99+           case  ChangeType .MODIFY : 
100+             _handleModify (event.path);
101+ 
102+           case  ChangeType .ADD : 
103+             _handleAdd (event.path);
104+ 
105+           case  ChangeType .REMOVE : 
106+             _handleRemove (event.path);
107+         }
89108      }
90109
91-       switch  (event.type) {
92-         case  ChangeType .MODIFY : 
93-           var  success =  await  _handleModify (event.path);
94-           if  (! success &&  _options.stopOnError) return ;
95- 
96-         case  ChangeType .ADD : 
97-           var  success =  await  _handleAdd (event.path);
98-           if  (! success &&  _options.stopOnError) return ;
99- 
100-         case  ChangeType .REMOVE : 
101-           var  success =  await  _handleRemove (event.path);
102-           if  (! success &&  _options.stopOnError) return ;
103-       }
110+       var  toRecompile =  {..._toRecompile};
111+       _toRecompile.clear ();
112+       var  success =  await  compileStylesheets (_options, _graph, toRecompile,
113+           ifModified:  true );
114+       if  (! success &&  _options.stopOnError) return ;
104115    }
105116  }
106117
107118  /// Handles a modify event for the stylesheet at [path] . 
108119  /// 
109120  /// Returns whether all necessary recompilations succeeded. 
110- Future < bool >  _handleModify (String  path)  async  {
121+ void  _handleModify (String  path) {
111122    var  url =  _canonicalize (path);
112123
113124    // It's important to access the node ahead-of-time because it's possible 
114125    // that `_graph.reload()` notices the file has been deleted and removes it 
115126    // from the graph. 
116127    if  (_graph.nodes[url] case  var  node? ) {
117128      _graph.reload (url);
118-       return   await   _recompileDownstream ([node]);
129+       _recompileDownstream ([node]);
119130    } else  {
120-       return   _handleAdd (path);
131+       _handleAdd (path);
121132    }
122133  }
123134
124135  /// Handles an add event for the stylesheet at [url] . 
125136  /// 
126137  /// Returns whether all necessary recompilations succeeded. 
127- Future < bool >  _handleAdd (String  path)  async  {
138+ void  _handleAdd (String  path) {
128139    var  destination =  _destinationFor (path);
129-     var  success =  destination ==  null  || 
130-         await  compileStylesheets (_options, _graph, {path:  destination},
131-             ifModified:  true );
140+     if  (destination !=  null ) _toRecompile[path] =  destination;
132141    var  downstream =  _graph.addCanonical (
133142        FilesystemImporter .cwd, _canonicalize (path), p.toUri (path));
134-     return   await   _recompileDownstream (downstream)  &&  success ;
143+     _recompileDownstream (downstream);
135144  }
136145
137146  /// Handles a remove event for the stylesheet at [url] . 
138147  /// 
139148  /// Returns whether all necessary recompilations succeeded. 
140- Future < bool >  _handleRemove (String  path) async  {
149+ void  _handleRemove (String  path) async  {
141150    var  url =  _canonicalize (path);
142151
143152    if  (_graph.nodes.containsKey (url)) {
144153      if  (_destinationFor (path) case  var  destination? ) _delete (destination);
145154    }
146155
147156    var  downstream =  _graph.remove (FilesystemImporter .cwd, url);
148-     return   await   _recompileDownstream (downstream);
157+     _recompileDownstream (downstream);
149158  }
150159
151160  /// Returns the canonical URL for the stylesheet path [path] . 
@@ -154,9 +163,10 @@ final class _Watcher {
154163  /// Combine [WatchEvent] s that happen in quick succession. 
155164  /// 
156165  /// Otherwise, if a file is erased and then rewritten, we can end up reading 
157-   /// the intermediate erased version. 
158- Stream <WatchEvent > _debounceEvents (Stream <WatchEvent > events) {
159-     return  events.debounceBuffer (Duration (milliseconds:  25 )).expand ((buffer) {
166+   /// the intermediate erased version. This returns a stream of batches of 
167+   /// events that all happened in succession. 
168+ Stream <List <WatchEvent >> _debounceEvents (Stream <WatchEvent > events) {
169+     return  events.debounceBuffer (Duration (milliseconds:  25 )).map ((buffer) {
160170      var  typeForPath =  p.PathMap <ChangeType >();
161171      for  (var  event in  buffer) {
162172        var  oldType =  typeForPath[event.path];
@@ -175,32 +185,20 @@ final class _Watcher {
175185    });
176186  }
177187
178-   /// Recompiles [nodes]  and everything that transitively imports them, if 
179-   /// necessary. 
180-   /// 
181-   /// Returns whether all recompilations succeeded. 
182- Future <bool > _recompileDownstream (Iterable <StylesheetNode > nodes) async  {
188+   /// Marks [nodes]  and everything that transitively imports them for 
189+   /// recompilation, if necessary. 
190+ void  _recompileDownstream (Iterable <StylesheetNode > nodes) {
183191    var  seen =  < StylesheetNode > {};
184-     var  allSucceeded =  true ;
185192    while  (nodes.isNotEmpty) {
186193      nodes =  [
187194        for  (var  node in  nodes)
188195          if  (seen.add (node)) node
189196      ];
190197
191-       var  sourcesToDestinations =  _sourceEntrypointsToDestinations (nodes);
192-       if  (sourcesToDestinations.isNotEmpty) {
193-         var  success =  await  compileStylesheets (
194-             _options, _graph, sourcesToDestinations,
195-             ifModified:  true );
196-         if  (! success &&  _options.stopOnError) return  false ;
197- 
198-         allSucceeded =  allSucceeded &&  success;
199-       }
198+       _toRecompile.addAll (_sourceEntrypointsToDestinations (nodes));
200199
201200      nodes =  [for  (var  node in  nodes) ...node.downstream];
202201    }
203-     return  allSucceeded;
204202  }
205203
206204  /// Returns a sourcesToDestinations mapping for nodes that are entrypoints. 
0 commit comments