import path , { normalize } from 'path' ; import iconv from 'iconv-lite' ; import fs from 'fs-extra' ; import { Config } from '~/core' ; interface FileEncoding { encoding : string ; bom : boolean ; } interface DecodeData { encoding : string ; bom : boolean ; content : string ; } const defaultEncoding = 'utf-8' ; const encodingMapping = { ascii : defaultEncoding , 'windows-1252' : defaultEncoding , } ; export class File { private static _fileEncoding : Record < string , FileEncoding > = { } ; private static __setFileEncoding ( filepath , encoding ) { filepath = normalize ( filepath ) ; this . _fileEncoding [ filepath ] = encoding ; } private static __getFileEncoding ( filepath ) { filepath = normalize ( filepath ) ; const info = this . _fileEncoding [ filepath ] || { encoding : '' , bom : false , } ; if ( ! info . encoding && Config . encoding !== 'auto' ) info . encoding = Config . encoding ; if ( ! info . encoding ) info . encoding = defaultEncoding ; return info ; } static async read ( filepath , encodingConfig = Config . encoding ) { const raw = await fs . readFile ( filepath ) ; const { encoding , bom , content } = File . decode ( raw , encodingConfig ) ; this . __setFileEncoding ( filepath , { encoding , bom } ) ; return content ; } static readSync ( filepath , encodingConfig = Config . encoding ) { const raw = fs . readFileSync ( filepath ) ; const { encoding , bom , content } = File . decode ( raw , encodingConfig ) ; this . __setFileEncoding ( filepath , { encoding , bom } ) ; return content ; } static async write ( filepath , data , opts ? ) { const { encoding , bom } = opts || this . __getFileEncoding ( filepath ) ; await fs . ensureDir ( path . dirname ( filepath ) ) ; const buffer = Buffer . from ( File . encode ( data , encoding , bom ) ) ; await fs . writeFile ( filepath , buffer ) ; } static writeSync ( filepath , data , opts ? ) { const { encoding , bom } = opts || this . __getFileEncoding ( filepath ) ; fs . ensureDirSync ( path . dirname ( filepath ) ) ; const buffer = Buffer . from ( File . encode ( data , encoding , bom ) ) ; fs . writeFileSync ( filepath , buffer ) ; } static decode ( buffer , encoding ? ) { if ( ! encoding ) encoding = defaultEncoding ; if ( encodingMapping [ encoding ] ) encoding = encodingMapping [ encoding ] ; const content = iconv . decode ( buffer , encoding ) ; let bom = false ; if ( buffer [ 0 ] === 0xEF && buffer [ 1 ] === 0xBB && buffer [ 2 ] === 0xBF ) bom = true ; return { encoding , content , bom , } ; } static encode ( string , encoding , addBOM = true ) { return iconv . encode ( string , encoding , { addBOM } ) ; } }