Source: sources/file-system/files.js

/**
 * @author [Tristan Valcke]{@link https://github.com/Itee}
 * @license [BSD-3-Clause]{@link https://opensource.org/licenses/BSD-3-Clause}
 *
 * @module sources/file-system/files
 * @description This is the files main export entry point.
 * It exposes all exports of the files validators.
 *
 */

import {
    readdirSync,
    statSync,
    existsSync,
    readFileSync
}                          from 'fs'
import path                from 'path'
import { isArray }         from 'itee-validators'
import { isInvalidPath }   from 'itee-validators/sources/file-system/paths/isValidPath'
import { isDirectoryPath } from 'itee-validators/sources/file-system/directories/isDirectoryPath'
import { isFilePath }      from 'itee-validators/sources/file-system/files/isFilePath'

// import { isArray, isDirectoryPath, isFilePath, isInvalidPath } from 'itee-validators'

function getPathsUnder( directoryPath ) {
    return readdirSync( directoryPath )
}

/**
 * Allow to search all files under filePaths in a recursive way
 *
 * @param {Array.<string>|string} paths - The files paths where search files
 * @returns {Array} - The paths of found files
 */
function getFilesPathsUnder( paths ) {

    const _paths = ( isArray( paths ) ) ? paths : [ paths ]
    let files    = []

    for ( let pathIndex = 0, numberOfPaths = _paths.length ; pathIndex < numberOfPaths ; pathIndex++ ) {

        const localPath = _paths[ pathIndex ]

        if ( isInvalidPath( localPath ) ) {

            throw new Error( `The path "${ localPath }" is not valid !` )

        } else if ( isFilePath( localPath ) ) {

            files.push( localPath )

        } else if ( isDirectoryPath( localPath ) ) {

            const subPaths      = getPathsUnder( localPath )
            const subFilesPaths = subPaths.map( ( subPath ) => { return getFilesPathsUnder( path.resolve( localPath, subPath ) ) } )
            if ( subFilesPaths ) {
                files = [].concat( ...subFilesPaths )
            }

        } else {

            // Ignoring block device, character device, symbolic link, fifo, and socket

        }

    }

    return files

}

/**
 * Return all the files paths under filePaths in a recursive way.
 *
 * @param {string} filePaths - An array of string, representing the base path where looking for get all files paths
 * @return {Array.<string>} - An array of files paths
 * @private
 */
function getFilesPathsUnder_1( filePaths ) {

    let files = []

    if ( Array.isArray( filePaths ) ) {

        let filePath = undefined
        for ( let pathIndex = 0, numberOfPaths = filePaths.length ; pathIndex < numberOfPaths ; pathIndex++ ) {

            filePath = filePaths[ pathIndex ]
            checkStateOf( filePath )

        }

    } else {

        checkStateOf( filePaths )

    }

    return files

    function getFilesPathsUnderFolder( folder ) {

        readdirSync( folder ).forEach( ( name ) => {

            const filePath = path.resolve( folder, name )
            checkStateOf( filePath )

        } )

    }

    function checkStateOf( filePath ) {

        if ( !fileExistForPath( filePath ) ) {
            // eslint-disable-next-line no-console
            console.error( 'ES6Converter: Invalid file path "' + filePath + '"' )
            return
        }

        const stats = statSync( filePath )
        if ( stats.isFile() ) {

            files.push( filePath )

        } else if ( stats.isDirectory() ) {

            Array.prototype.push.apply( files, getFilesPathsUnderFolder( filePath ) )

        } else {

            // eslint-disable-next-line no-console
            console.error( 'Invalid stat object !' )

        }

    }

}

function fileExistForPath( filePath ) {

    return existsSync( filePath )

}

function getFileForPath( filePath ) {

    // In case files doesn't exist
    if ( !fileExistForPath( filePath ) ) {
        throw new Error( `Invalid file path "${ filePath }" file does not exist !` )
    }

    return readFileSync( filePath, 'utf8' )

}

function getUncommentedFileForPath( filePath ) {

    return getFileForPath( filePath ).replace( /\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/g, '$1' )

}

/**
 * Will create an array without the strings in filePaths that are matched in excludes paths
 *
 * @param {Array.<string>} filePaths - An array of string to clean
 * @param {Array.<string>} excludes - The paths to remove
 * @return {Array.<string>} The cleaned filePaths of excludes paths
 * @private
 */
function excludesFilesPaths( filePaths, excludes ) {

    let filteredFilesPath = []

    let filePath = undefined
    for ( let filePathIndex = 0, numberOfFilePaths = filePaths.length ; filePathIndex < numberOfFilePaths ; filePathIndex++ ) {
        filePath = filePaths[ filePathIndex ]

        if ( isExclude( filePath ) ) {
            continue
        }

        filteredFilesPath.push( filePath )

    }

    return filteredFilesPath

    function isExclude( path ) {

        let isExclude      = false
        let excludePattern = undefined
        for ( let i = 0, pathLength = excludes.length ; i < pathLength ; i++ ) {

            excludePattern = excludes[ i ]

            // In case this is a file name it must fully match
            if ( excludePattern.indexOf( '.' ) > -1 ) {

                const fileName = path.replace( /^.*(\\|\/|\\:)/, '' )
                if ( fileName === excludePattern ) {
                    isExclude = true
                }

            } else if ( path.contains( excludePattern ) ) {
                isExclude = true
            }

        }

        return isExclude

    }

}

/**
 * Will filter file paths a keep only js files
 *
 * @param {Array.<string>} filePaths - An array of path to filter
 * @param {function} filter - An optional filter to apply instead of internal filter
 * @return {Array.<string>} The filtered path with only javascript files
 * @private
 */
function filterJavascriptFiles( filePaths, filter ) {

    let filteredFilesPath = []

    let filePath = undefined
    for ( let filePathIndex = 0, numberOfFilePaths = filePaths.length ; filePathIndex < numberOfFilePaths ; filePathIndex++ ) {

        filePath = filePaths[ filePathIndex ]

        // Not a js file like fonts or shaders
        if ( filter && !filter( filePath ) ) {
            continue
        } else {
            const fileExtension = path.extname( filePath )
            if ( filePath.indexOf( 'glsl' ) > -1 || fileExtension !== '.js' ) {
                continue
            }
        }

        filteredFilesPath.push( filePath )

    }

    return filteredFilesPath

}

export {
    getPathsUnder,
    getFilesPathsUnder,
    getFilesPathsUnder_1,
    fileExistForPath,
    getFileForPath,
    getUncommentedFileForPath,
    excludesFilesPaths,
    filterJavascriptFiles
}