@@ -231,26 +231,50 @@ export class FileWatcher {
231231 const startTime = startHRTime ( )
232232 const normalizedPath = normalizePath ( path )
233233 const isConfigAppPath = path === this . app . configuration . path
234+ const isExtensionToml = path . endsWith ( '.extension.toml' )
234235
235236 outputDebug ( `🌀: ${ event } ${ path . replace ( this . app . directory , '' ) } \n` )
236237
237238 if ( isConfigAppPath ) {
238- this . handleEventForExtension ( event , path , this . app . directory , startTime )
239+ this . handleEventForExtension ( event , path , this . app . directory , startTime , false )
239240 } else {
240241 const affectedExtensions = this . extensionWatchedFiles . get ( normalizedPath )
242+ const isUnknownExtension = affectedExtensions === undefined || affectedExtensions . size === 0
243+
244+ if ( isUnknownExtension && ! isExtensionToml && ! isConfigAppPath ) {
245+ // Ignore an event if it's not part of an existing extension
246+ // Except if it is a toml file (either app config or extension config)
247+ outputDebug ( `🌀: File ${ path } is not watched by any extension` , this . options . stdout )
248+ return
249+ }
250+
241251 for ( const extensionPath of affectedExtensions ?? [ ] ) {
242- this . handleEventForExtension ( event , path , extensionPath , startTime )
252+ this . handleEventForExtension ( event , path , extensionPath , startTime , false )
253+ }
254+ if ( isUnknownExtension ) {
255+ this . handleEventForExtension ( event , path , this . app . directory , startTime , true )
243256 }
244257 }
245258 this . debouncedEmit ( )
246259 }
247260
248- private handleEventForExtension ( event : string , path : string , extensionPath : string , startTime : StartTime ) {
261+ private handleEventForExtension (
262+ event : string ,
263+ path : string ,
264+ extensionPath : string ,
265+ startTime : StartTime ,
266+ isUnknownExtension : boolean ,
267+ ) {
249268 const isExtensionToml = path . endsWith ( '.extension.toml' )
250269 const isConfigAppPath = path === this . app . configuration . path
251270
252271 switch ( event ) {
253272 case 'change' :
273+ if ( isUnknownExtension ) {
274+ // If the extension path is unknown, it means the extension was just created.
275+ // We need to wait for the lock file to disappear before triggering the event.
276+ break
277+ }
254278 if ( isExtensionToml || isConfigAppPath ) {
255279 this . pushEvent ( { type : 'extensions_config_updated' , path, extensionPath, startTime} )
256280 } else {
@@ -275,6 +299,8 @@ export class FileWatcher {
275299 clearInterval ( intervalId )
276300 this . extensionPaths . push ( realPath )
277301 this . pushEvent ( { type : 'extension_folder_created' , path : realPath , extensionPath, startTime} )
302+ // Force an emit because we are inside a timeout callback
303+ this . debouncedEmit ( )
278304 }
279305 if ( totalWaitedTime >= EXTENSION_CREATION_TIMEOUT_IN_MS ) {
280306 clearInterval ( intervalId )
@@ -294,7 +320,11 @@ export class FileWatcher {
294320 this . pushEvent ( { type : 'extension_folder_deleted' , path : extensionPath , extensionPath, startTime} )
295321 } else {
296322 setTimeout ( ( ) => {
323+ // If the extensionPath is not longer in the list, the extension was deleted while the timeout was running.
324+ if ( ! this . extensionPaths . includes ( extensionPath ) ) return
297325 this . pushEvent ( { type : 'file_deleted' , path, extensionPath, startTime} )
326+ // Force an emit because we are inside a timeout callback
327+ this . debouncedEmit ( )
298328 } , FILE_DELETE_TIMEOUT_IN_MS )
299329 }
300330 break
0 commit comments