import { promises as fs } from "fs"; import * as path from "path"; import { RJLog } from "../log/RJLog"; import { PathReference } from "./PathReference"; import { DOMShim } from "../DOMShim"; import { DateMath } from "../../browser/date/DateMath"; export class Files { static parentPath( filePath:string ) { return path.dirname( filePath ); } static async forAllIn( filePath:string, filter:(p:PathReference)=>Promise = null, action:(p:PathReference)=>Promise = null ):Promise { let files = await fs.readdir( filePath ); let root = new PathReference( filePath ); let pathReferences = files.map( f => root.createRelative( f ) ); if ( filter ) { let filteredPaths = []; for ( let p of pathReferences ) { if ( await filter( p ) ) { filteredPaths.push( p ); } } pathReferences = filteredPaths; }; for ( let p of pathReferences ) { let isDirectory = await p.isDirectory(); if ( isDirectory ) { await this.forAllIn( p.absolutePath, filter, action ); } } if ( action ) { for ( let p of pathReferences ) { await action( p ); } } return Promise.resolve( pathReferences ); } static async forDirectChildrenIn( filePath:string, filter:(p:PathReference)=>Promise = null, action:(p:PathReference)=>Promise = null ):Promise { let files = await fs.readdir( filePath ); let root = new PathReference( filePath ); let pathReferences = files.map( f => root.createRelative( f ) ); if ( filter ) { let filteredPaths = []; for ( let p of pathReferences ) { if ( await filter( p ) ) { filteredPaths.push( p ); } } pathReferences = filteredPaths; }; if ( action ) { for ( let p of pathReferences ) { await action( p ); } } return Promise.resolve( pathReferences ); } static joinPaths( pathFragments:string[] ) { return path.join.apply( path, pathFragments ); } static async existsIn( directoryPath:string, fileName:string ):Promise { let combinedPath = Files.joinPaths( [ directoryPath, fileName ] ); let result = await Files.exists( combinedPath ); return Promise.resolve( result ); } static async getStatistics( filePath:string ) { return fs.stat( filePath ); } static async getModificationDate( filePath:string ):Promise { let stats = await this.getStatistics( filePath ); if ( ! stats ) { return Promise.resolve( null ); } return new Date( stats.mtimeMs ); } static async isNewerThan( filePath:string, date:Date ):Promise { let mDate = await this.getModificationDate( filePath ); return Promise.resolve( DateMath.isAfter( mDate, date ) ); } static async isDirectory( filePath:string ):Promise { try { let stats = await fs.stat( filePath ); return Promise.resolve( stats !== null && stats !== undefined && stats.isDirectory() ); } catch( e ) { return false; } return Promise.resolve( false ); } static async isFile( filePath:string ):Promise { try { let stats = await fs.stat( filePath ); return Promise.resolve( stats !== null && stats !== undefined && stats.isFile() ); } catch( e ) { return false; } return Promise.resolve( false ); } static async isSymbolicLink( filePath:string ):Promise { try { let stats = await fs.stat( filePath ); return Promise.resolve( stats !== null && stats !== undefined && stats.isSymbolicLink() ); } catch( e ) { return false; } return Promise.resolve( false ); } static async exists( filePath:string ):Promise { try { let stats = await fs.stat( filePath ); return Promise.resolve( stats !== null && stats !== undefined ); } catch( e ) { return false; } return Promise.resolve( false ); } static async ensureDirectoryExists( path:string ):Promise { let exists = await Files.exists( path ); if ( exists ) { return Promise.resolve(); } await fs.mkdir( path, { recursive: true } ); return Promise.resolve(); } static async ensureParentDirectoryExists( filePath:string ):Promise { let path = Files.parentPath( filePath ); let exists = await Files.exists( path ); if ( exists ) { return Promise.resolve(); } await fs.mkdir( path ); return Promise.resolve(); } static async deleteFile( filePath:string ):Promise { try { await fs.unlink( filePath ); } catch( e ) { return Promise.resolve( false ); } return Promise.resolve( true ); } static async loadUTF8( filePath:string ):Promise { try { let data = await fs.readFile( filePath ); let stringData = data.toString(); return Promise.resolve( stringData ); } catch ( exception ) { RJLog.log( exception ); } return Promise.resolve( null ); } static async moveFile( oldPath:string, newPath:string ) { try { await fs.rename( oldPath, newPath ); } catch ( e ) { await fs.copyFile( oldPath, newPath ); await fs.unlink( oldPath ); } } static async loadJSON( filePath:string ):Promise { let text = await Files.loadUTF8( filePath ); if ( text === null ) { return Promise.resolve( null ); } try { let jsonObject = JSON.parse( text ); return Promise.resolve( jsonObject as T ); } catch ( exception ) { RJLog.log( exception ); } return Promise.resolve( null ); } static async saveUTF8( filePath:string, text:string ):Promise { try { await fs.writeFile( filePath, text ); return Promise.resolve( true ); } catch ( exception ) { RJLog.log( exception ); } return Promise.resolve( false ); } static async saveJSON( filePath:string, data:T ):Promise { try { let jsonData = JSON.stringify( data ); let result = await Files.saveUTF8( filePath, jsonData ); return Promise.resolve( result ); } catch( e ) { RJLog.log( e ); } return Promise.resolve( false ); } static async saveXML( filePath:string, rootElement:Element ):Promise { let domShim = DOMShim.$; let nodeName = rootElement.nodeName; let xmlHeader = `` + "\n"; let serializedXML = `${xmlHeader}<${nodeName}>${rootElement.innerHTML}` ; //RJLog.log( rootElement, serializedXML ); await Files.saveUTF8( filePath, serializedXML ); return Promise.resolve(); } static async loadXML( filePath:string ):Promise { let domShim = DOMShim.$; let stringData = await Files.loadUTF8( filePath ); let parser = new DOMParser(); let xmlDoc = parser.parseFromString( stringData, "text/xml" ); return xmlDoc; } static async loadHTML( filePath:string ):Promise { let domShim = DOMShim.$; let stringData = await Files.loadUTF8( filePath ); let parser = new DOMParser(); let xmlDoc = parser.parseFromString( stringData, "text/html" ); return xmlDoc; } static async saveHTML( filePath:string, rootElement:Element ):Promise { let domShim = DOMShim.$; await Files.saveUTF8( filePath, rootElement.outerHTML ); return Promise.resolve(); } }