import MemoryFS from 'memory-fs' ; export interface CustomMemoryFs extends MemoryFS { statSync ( path ) : { isFile : ( ) => boolean ; isDirectory : ( ) => boolean ; isBlockDevice : ( ) => boolean ; isCharacterDevice : ( ) => boolean ; isSymbolicLink : ( ) => boolean ; isFIFO : ( ) => boolean ; isSocket : ( ) => boolean ; mtime : Date ; } ; } export function memoryFS ( ) { const mfs = new MemoryFS ( ) ; const lastModified = { } ; wrap ( 'writeFileSync' , writeFile ) ; wrap ( 'unlinkSync' , unlink ) ; wrap ( 'rmdirSync' , rmdir ) ; wrap ( 'statSync' , stat ) ; wrap ( 'mkdir' , mkdir ) ; type UnknownFunction = ( ... args : unknown [ ] ) => unknown ; function mkdir ( fn , args ) { if ( typeof args [ 2 ] === 'function' ) { return fn . apply ( mfs , [ args [ 0 ] , args [ 2 ] ] ) ; } else { return fn . apply ( mfs , args ) ; } } function writeFile ( fn , args ) { const filePath = args [ 0 ] ; const result = fn . apply ( mfs , args ) ; lastModified [ filePath as string ] = new Date ( ) ; return result ; } function unlink ( fn , args ) { const filePath = args [ 0 ] ; const result = fn . apply ( mfs , args ) ; delete lastModified [ filePath ] ; return result ; } function rmdir ( fn , args ) { const dir = args [ 0 ] ; const result = fn . apply ( mfs , args ) ; Object . keys ( lastModified ) . reduce < any > ( ( memo , filePath ) => { const mtime = lastModified [ filePath ] ; if ( ! filePath . startsWith ( dir ) ) { memo [ filePath ] = mtime ; } return memo ; } , { } ) ; return result ; } function stat ( fn , args ) { const filePath = args [ 0 ] ; const stats = fn . apply ( mfs , args ) ; ( stats as { mtime : Date ; } ) . mtime = lastModified [ filePath ] ; return stats ; } function wrap < T extends ( ... args : any [ ] ) => any > ( method , fn ) { const oldFn = mfs [ method ] ; mfs [ method ] = ( ... args ) => { return fn ( oldFn , args ) ; } ; } return mfs as CustomMemoryFs ; }