import { appendFile , copyFile , mkdir , readdir , readFile , rm , stat , writeFile } from 'fs' ; import { dirname , join } from 'path' ; import { watch } from 'chokidar' ; import { FileContext , Stats } from './file-context' ; function handleCallback < T > ( callback ) ; function handleCallback ( callback ) ; function handleCallback ( callback ) { return new Promise < any > ( ( resolve , reject ) => { callback ( ( err , value ) => { if ( err ) { reject ( err ) ; } else { resolve ( value ) ; } } ) ; } ) ; } export function getFileContext ( ) { return { stats ( path ) { return new Promise < Stats > ( ( resolve , reject ) => { stat ( path , ( err , stats ) => { if ( err ) { reject ( err ) ; } else { if ( stats . isDirectory ( ) ) { resolve ( { type : 'directory' } ) ; } else if ( stats . isFile ( ) ) { resolve ( { type : 'file' , lastModified : stats . mtimeMs } ) ; } else { resolve ( { type : 'other' } ) ; } } } ) ; } ) ; } , appendFile ( path , content ) { return handleCallback ( ( cb ) => appendFile ( path , content , cb ) ) ; } , writeFile ( path , content ) { return handleCallback ( ( cb ) => writeFile ( path , content , cb ) ) ; } , listFiles ( path ) { return handleCallback ( ( cb ) => readdir ( path , cb ) ) ; } , exists ( path ) { return handleCallback ( ( cb ) => stat ( path , ( err ) => { if ( err ) { cb ( null , false ) ; } else { cb ( null , true ) ; } } ) ) ; } , read ( path ) { return handleCallback ( ( cb ) => readFile ( path , ( err , content ) => { if ( err ) { cb ( err , null ) ; } else { cb ( null , content . toString ( ) ) ; } } ) ) ; } , async copy ( source , destination ) { const exists = await this . exists ( source ) ; if ( ! exists ) { return ; } const stats = await this . stats ( source ) ; if ( stats . type === 'directory' ) { await this . createDirectory ( destination ) ; for ( const child of await this . listFiles ( source ) ) { await this . copy ( join ( source , child ) , join ( destination , child ) ) ; } } else { const destinationDirectory = dirname ( destination ) ; const existsDestinationDirectory = await this . exists ( destinationDirectory ) ; if ( ! existsDestinationDirectory ) { await this . createDirectory ( destinationDirectory ) ; } return handleCallback ( ( cb ) => copyFile ( source , destination , cb ) ) ; } } , createDirectory ( path ) { return handleCallback ( ( cb ) => mkdir ( path , { recursive : true } , cb ) ) ; } , async remove ( path ) { if ( await this . exists ( path ) ) { return handleCallback ( ( cb ) => rm ( path , { recursive : true } , cb ) ) ; } } , watch ( path , callback ) { const watcher = watch ( path ) ; watcher . on ( 'add' , ( fileName ) => { callback ( fileName ) ; } ) ; watcher . on ( 'change' , ( fileName ) => { callback ( fileName ) ; } ) ; watcher . on ( 'unlink' , ( fileName ) => { callback ( fileName ) ; } ) ; return { close ( ) { watcher . close ( ) ; } , } ; } , } ; }