"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.IModelJsFs = exports.IModelJsFsStats = void 0;
/** @packageDocumentation
 * @module Portability
 */
// cspell: ignore wflag
const fs = require("fs-extra");
const readline = require("readline");
const path = require("path");
/* TODO: define File Mode Constants: S_IWUSR, et al. */
/** Information about a file. See [[IModelJsFs.lstatSync]]
 * @public
 */
class IModelJsFsStats {
    size;
    atimeMs;
    mtimeMs;
    birthtimeMs;
    isDirectory;
    isFile;
    isSocket;
    isSymbolicLink;
    isReadOnly;
    constructor(size, atimeMs, mtimeMs, birthtimeMs, isDirectory, isFile, isSocket, isSymbolicLink, isReadOnly) {
        this.size = size;
        this.atimeMs = atimeMs;
        this.mtimeMs = mtimeMs;
        this.birthtimeMs = birthtimeMs;
        this.isDirectory = isDirectory;
        this.isFile = isFile;
        this.isSocket = isSocket;
        this.isSymbolicLink = isSymbolicLink;
        this.isReadOnly = isReadOnly;
    }
}
exports.IModelJsFsStats = IModelJsFsStats;
/** File system operations that are defined on all platforms. See also [[Platform]] and [[KnownLocations]]
 * @public
 */
class IModelJsFs {
    /** Does file or directory exist? */
    static existsSync(pathname) { return fs.existsSync(pathname); }
    /** Delete a file. */
    static unlinkSync(pathname) { fs.unlinkSync(pathname); }
    /** Delete a file or remove a directory (rm -r). */
    static removeSync(pathname) { fs.removeSync(pathname); }
    /** Create a directory. */
    static mkdirSync(pathname) { fs.mkdirSync(pathname); }
    /** Remove a directory. */
    static rmdirSync(pathname) { fs.rmdirSync(pathname); }
    /** Write to a file. */
    static writeFileSync(pathname, data, wflag = "w") { fs.writeFileSync(pathname, data, { flag: wflag }); }
    /** Append to a file. */
    static appendFileSync(pathname, str) { fs.appendFileSync(pathname, str); }
    /** Make a copy of a file */
    static copySync(src, dest, opts) { fs.copySync(src, dest, opts); }
    /** Gets the file and directory names in the specified directory. Excludes "." and "..". Returns an empty array if the specified directory does not exist. */
    static readdirSync(pathname) { return fs.existsSync(pathname) ? fs.readdirSync(pathname) : []; }
    /** Read file */
    static readFileSync(pathname) { return fs.readFileSync(pathname); }
    /** Read file with encoding */
    static readFileWithEncodingSync(pathname, encoding) { return fs.readFileSync(pathname, { encoding }); }
    /** Reads a file line by line as an async iterable, without loading the entire file into memory. */
    static async *readLines(pathname) {
        const stream = fs.createReadStream(pathname);
        const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
        try {
            for await (const line of rl)
                yield line;
        }
        finally {
            rl.close();
            stream.destroy();
        }
    }
    /** Test if the current user has permission to write to a file. */
    static isFileWritable(pathname) {
        try {
            fs.accessSync(pathname, fs.constants.W_OK);
            return true;
        }
        catch {
            return false;
        }
    }
    /** Get information about a file. */
    static lstatSync(pathname) {
        const stats = fs.lstatSync(pathname);
        if (stats === undefined)
            return undefined;
        return new IModelJsFsStats(stats.size, stats.atime.getTime(), stats.mtime.getTime(), stats.birthtime.getTime(), stats.isDirectory(), stats.isFile(), stats.isSocket(), stats.isSymbolicLink(), !IModelJsFs.isFileWritable(pathname));
    }
    /**
     * Finds files recursively based on a pattern
     * @param rootDir Directory from where to start searching for files.
     * @param pattern A Regex that would be match to basename of files including extension
     * @returns list of file that match the pattern.
     */
    static recursiveFindSync(rootDir, pattern) {
        const files = [];
        IModelJsFs.walkDirSync(rootDir, (pathname, isDir) => {
            if (!isDir) {
                const fileName = path.basename(pathname);
                if (pattern.test(fileName)) {
                    files.push(pathname);
                }
            }
            return true;
        });
        return files;
    }
    /**
     * Walks a directory in breadth first fashion
     * @param rootDir  directory from where the traversal starts
     * @param cb callback that would be called with full path of file or directory
     */
    static walkDirSync(rootDir, cb) {
        const subDir = [];
        for (const childPath of IModelJsFs.readdirSync(rootDir)) {
            const fullPath = path.join(rootDir, childPath);
            const isDir = IModelJsFs.lstatSync(fullPath)?.isDirectory;
            if (!cb(fullPath, isDir ?? false)) {
                return;
            }
            // Need to check if the directory still exists in case the callback has deleted it.
            if (isDir && IModelJsFs.existsSync(fullPath)) {
                subDir.push(fullPath);
            }
        }
        subDir.forEach((v) => {
            IModelJsFs.walkDirSync(v, cb);
        });
    }
    /** Create a directory, recursively setting up the path as necessary */
    static recursiveMkDirSync(dirPath) {
        if (IModelJsFs.existsSync(dirPath))
            return;
        const parentPath = path.dirname(dirPath);
        if (parentPath !== dirPath)
            IModelJsFs.recursiveMkDirSync(parentPath);
        try {
            IModelJsFs.mkdirSync(dirPath);
        }
        catch (err) {
            // Ignore the error if the folder has been created since the existence check
            if (err?.code !== "EEXIST")
                throw err;
        }
    }
    /** Remove a directory, recursively */
    static purgeDirSync(dirPath) {
        if (!IModelJsFs.existsSync(dirPath))
            return;
        IModelJsFs.walkDirSync(dirPath, (pathName, isDir) => {
            if (isDir) {
                IModelJsFs.purgeDirSync(pathName);
                IModelJsFs.removeSync(pathName);
            }
            else {
                IModelJsFs.unlinkSync(pathName);
            }
            return true;
        });
    }
}
exports.IModelJsFs = IModelJsFs;
//# sourceMappingURL=IModelJsFs.js.map