373 lines
7.7 KiB
TypeScript
373 lines
7.7 KiB
TypeScript
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<boolean> = null, action:(p:PathReference)=>Promise<void> = null ):Promise<PathReference[]>
|
|
{
|
|
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<boolean> = null, action:(p:PathReference)=>Promise<void> = null ):Promise<PathReference[]>
|
|
{
|
|
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<boolean>
|
|
{
|
|
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<Date>
|
|
{
|
|
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<boolean>
|
|
{
|
|
let mDate = await this.getModificationDate( filePath );
|
|
|
|
return Promise.resolve( DateMath.isAfter( mDate, date ) );
|
|
}
|
|
|
|
static async isDirectory( filePath:string ):Promise<boolean>
|
|
{
|
|
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<boolean>
|
|
{
|
|
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<boolean>
|
|
{
|
|
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<boolean>
|
|
{
|
|
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<void>
|
|
{
|
|
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<void>
|
|
{
|
|
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<boolean>
|
|
{
|
|
try
|
|
{
|
|
await fs.unlink( filePath );
|
|
}
|
|
catch( e )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
return Promise.resolve( true );
|
|
|
|
}
|
|
|
|
|
|
static async loadUTF8( filePath:string ):Promise<string>
|
|
{
|
|
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<T>( filePath:string ):Promise<T>
|
|
{
|
|
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<boolean>
|
|
{
|
|
try
|
|
{
|
|
await fs.writeFile( filePath, text );
|
|
return Promise.resolve( true );
|
|
}
|
|
catch ( exception )
|
|
{
|
|
RJLog.log( exception );
|
|
}
|
|
|
|
return Promise.resolve( false );
|
|
|
|
}
|
|
|
|
static async saveJSON<T>( filePath:string, data:T ):Promise<boolean>
|
|
{
|
|
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<void>
|
|
{
|
|
let domShim = DOMShim.$;
|
|
|
|
let nodeName = rootElement.nodeName;
|
|
let xmlHeader = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + "\n";
|
|
let serializedXML = `${xmlHeader}<${nodeName}>${rootElement.innerHTML}</${nodeName}>` ;
|
|
|
|
//RJLog.log( rootElement, serializedXML );
|
|
|
|
await Files.saveUTF8( filePath, serializedXML );
|
|
|
|
return Promise.resolve();
|
|
}
|
|
|
|
static async loadXML( filePath:string ):Promise<Document>
|
|
{
|
|
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<Document>
|
|
{
|
|
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<void>
|
|
{
|
|
let domShim = DOMShim.$;
|
|
|
|
await Files.saveUTF8( filePath, rootElement.outerHTML );
|
|
|
|
return Promise.resolve();
|
|
}
|
|
} |