import * as fs from 'fs' ; import * as glob from 'glob' ; import * as path from 'path' ; import { Stats , WriteFileOptions } from 'fs' ; import { isString , isFunction , isLegalString , isLegalArray } from '../utils' ; author CaMnter
  interface OverrideOptions { flag ? : string ; encoding ? : string | null ; es5 ? : boolean ; filter ? : Array < string > ; hitFilter ? : ( absolutePath : string ) => void ; override ? : ( content : string , absolutePath : string , relativePath : string ) => { content ? : string ; filePath ? : string ; normalCopy ? : boolean ; } | undefined ; [ option ] : any ; } param input param output param options export function overrideSync ( input , output , options ) { if ( ! ( input && isString ( input ) ) ) { return ; } if ( ! ( output && isString ( output ) ) ) { return ; } const expectOptions = { encoding : 'utf8' , ... options , } ; const stats = fs . statSync ( input ) ; const isFile = stats . isFile ( ) ; const isDirectory = stats . isDirectory ( ) ; if ( isFile ) { overrideFileSync ( input , output , expectOptions ) ; } else if ( isDirectory ) { overrideDirSync ( input , output , expectOptions ) ; } } param input param output param options export function overrideFileSync ( input , output , options ) { const mkFile = mkFileSync ( output ) ; if ( ! mkFile ) { throw new Error ( `mkFile error, path = ${ output }` ) ; return ; } let content = fs . readFileSync ( input , options ) as string ; let filePath = output ; let normalCopy = false ; let inputAbsolutePath = input ; if ( options && options . override && isFunction ( options . override ) ) { if ( isLegalString ( inputAbsolutePath ) && ! inputAbsolutePath . startsWith ( path . sep ) ) { inputAbsolutePath = path . join ( process . cwd ( ) , input ) ; } const relativePath = path . relative ( inputAbsolutePath , input ) ; const result = options . override ( content , inputAbsolutePath , relativePath ) ; if ( result && result . content ) { content = result . content ; } if ( result && result . filePath ) { filePath = result . filePath ; } if ( result && result . normalCopy ) { normalCopy = result . normalCopy ; } } if ( normalCopy ) { copyFileSync ( input , filePath ) ; } else { writeFileSync ( filePath , content ) ; } /**
     * in the same directory
     * acss -> wxss
     *
     * remove acss
     */ if ( filePath !== inputAbsolutePath && isTheSameDirectory ( filePath , inputAbsolutePath ) ) { fs . unlinkSync ( inputAbsolutePath ) ; } } param input param output param options export function overrideDirSync ( input , output , options ) { const mkdir = mkdirSync ( output ) ; if ( ! mkdir ) { throw new Error ( `mkdir error, path = ${ output }` ) ; return ; } const currentDirPath = process . cwd ( ) ; const inputAbsolutePath = input ; const globPattern = inputAbsolutePath + '/**/*.*' ; const globResult = glob . sync ( globPattern ) ; const { filter , hitFilter } = options ; globResult . forEach ( filePath => { if ( isLegalArray ( filter ) && matchFilter ( filePath , filter ) ) { if ( hitFilter && isFunction ( hitFilter ) ) { hitFilter ( filePath ) ; } } else { options . relativePath = input ; options . absolutePath = path . join ( currentDirPath , filePath ) ; const basename = path . basename ( filePath ) ; const createFilePath = path . join ( output , basename ) ; overrideFileSync ( filePath , createFilePath , options ) ; } } ) ; } param path param filter export function matchFilter ( path , filter ) { if ( ! isLegalString ( path ) ) { return false ; } if ( ! filter || ! Array . isArray ( filter ) || filter . length <= 0 ) { return false ; } return filter . some ( ( key ) => { return matchKey ( path , key ) ; } ) ; } param path param key export function matchKey ( path , key ) { const start = new RegExp ( `^${ key }.*` ) ; const include = new RegExp ( `\/${ key }` ) ; return start . test ( path ) || include . test ( path ) ; } param input param output export function copyFileSync ( input , output ) { if ( ! ( output && isString ( output ) ) ) { return ; } const dir = path . dirname ( output ) ; mkdirSync ( dir ) ; fs . copyFileSync ( input , output ) ; } param filePath param content param options export function writeFileSync ( filePath , content , options ? ) { if ( ! ( filePath && isString ( filePath ) ) ) { return ; } const dir = path . dirname ( filePath ) ; mkdirSync ( dir ) ; fs . writeFileSync ( filePath , content , options ) ; } param input export function mkFileSync ( input ) { if ( ! ( input && isString ( input ) ) ) { return false ; } const targetFilePath = path . join ( input ) ; if ( targetFilePath && fs . existsSync ( targetFilePath ) ) { return true ; } const targetDirPath = path . dirname ( targetFilePath ) ; if ( fs . existsSync ( targetDirPath ) ) { return true ; } fs . mkdirSync ( targetDirPath ) ; return true ; } param input export function mkdirSync ( input ) { if ( ! ( input && isString ( input ) ) ) { return false ; } let targetDirPath = path . join ( input ) ; if ( targetDirPath && fs . existsSync ( targetDirPath ) ) { return true ; } let actualDeepestPath = getActualDeepestPath ( input ) ; let actualChildrenPath = path . relative ( actualDeepestPath , input ) ; if ( ! actualChildrenPath ) { return true ; } /**
     * eg:
     *
     *「input」'app/page/my/index.js'
     *「actualDeepestPath」'app/page'
     *「actualChildrenPath」'my/index.js'
     *
     *「actualChildrenPathList」['my', 'index.js']
     */ const startsWithSlash = targetDirPath . startsWith ( path . sep ) ; const startsWithFallbackSymbol = targetDirPath . startsWith ( `..${ path . sep }` ) ; let actualPath = '' ; if ( startsWithSlash ) { /**
         * /**
         */ actualPath = path . join ( targetDirPath ) ; actualDeepestPath = getActualDeepestPath ( actualPath ) ; actualChildrenPath = path . relative ( actualDeepestPath , actualPath ) ; mkDirsSync ( actualDeepestPath , actualChildrenPath ) ; } else if ( startsWithFallbackSymbol ) { /**
         * ../**
         */ actualPath = path . resolve ( process . cwd ( ) , targetDirPath ) ; actualDeepestPath = getActualDeepestPath ( actualPath ) ; actualChildrenPath = path . relative ( actualDeepestPath , actualPath ) ; mkDirsSync ( actualDeepestPath , actualChildrenPath ) ; } else { /**
         * **
         * normal
         */ mkDirsSync ( actualDeepestPath , actualChildrenPath ) ; } return true ; } param actualDeepestPath param actualChildrenPath export function mkDirsSync ( actualDeepestPath , actualChildrenPath ) { let outputDirPath = actualDeepestPath ; const actualChildrenPathList = actualChildrenPath . split ( path . sep ) ; actualChildrenPathList . forEach ( ( dirname ) => { outputDirPath = path . join ( outputDirPath , dirname ) ; const exists = fs . existsSync ( outputDirPath ) ; if ( ! exists ) { fs . mkdirSync ( outputDirPath ) ; } } ) ; } param input export function getActualDeepestPath ( input ) { const exists = fs . existsSync ( input ) ; if ( ! exists ) { return getActualDeepestPath ( path . dirname ( input ) ) ; } else { return input ; } } param firstPath param secondPath export function isTheSameDirectory ( firstPath , secondPath ) { return path . dirname ( firstPath ) === path . dirname ( secondPath ) ; }