"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocDir = void 0;
const globby_1 = __importDefault(require("globby"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const slash2_1 = __importDefault(require("slash2"));
const file_1 = require("./file");
const languages_1 = require("./languages");
const defaultInfo = {
    total: 0,
    code: 0,
    comment: 0,
};
const defaultExclude = [
    // javascript
    '**/*.map',
    '**/yarn**',
    '**/.github',
    '**/node_modules/**',
    '**/dist/**',
    '**/*.snap',
    // java
    '**/target',
    '**/*.class',
    '**/*.o',
    '**/bin',
    '**/*.map',
    // python
    '**/*.pyc',
    '**/*.pyo',
    // other
    '**/*.dil',
    '**/*.ra',
    // images
    '**/*.png',
    '**/*.jpg',
    '**/*.jpeg',
    '**/*.gif',
    '**/*.ico',
    '**/*.bmp',
    '**/*.webp',
    '**/*.tiff',
    '**/*.psd',
    '**/*.ai',
    '**/*.ps',
    '**/*.eps',
    // fonts
    '**/*.ttf',
    '**/*.otf',
    '**/*.woff',
    '**/*.woff2',
    '**/*.eot',
    '**/*.ttc',
    // audio
    '**/*.mp3',
    '**/*.wav',
    '**/*.ogg',
    '**/*.flac',
    '**/*.aac',
    '**/*.m4a',
    '**/*.aif*',
    // video
    '**/*.mp4',
    '**/*.mkv',
    '**/*.avi',
    '**/*.mov',
    '**/*.wmv',
    '**/*.mpg',
    '**/*.mpeg',
    '**/*.m2v',
    '**/*.m4v',
    // office
    '**/*.doc',
    '**/*.docx',
    '**/*.docm',
    '**/*.dot',
    '**/*.dotx',
    '**/*.xls',
    '**/*.xlsx',
    // documents
    '**/*.pdf',
    '**/*.epub',
    '**/*.mobi',
    // archives
    '**/*.rar',
    '**/*.zip',
    '**/*.7z',
    '**/*.tar',
    '**/*.gz',
    '**/*.bz2',
    '**/*.bz',
    '**/*.tbz',
    '**/*.tgz',
];
function ensureArray(arr, dfault) {
    if (!arr) {
        return dfault ? [dfault] : [];
    }
    return Array.isArray(arr) ? arr : [arr];
}
/**
 * Collect the info of a directory.
 */
class LocDir {
    constructor(options) {
        Object.defineProperty(this, "cwd", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "include", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "exclude", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "analysisLanguages", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "allLanguages", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: new languages_1.Languages()
        });
        // ensure all excludes are globstar. Note that '**/*.ts/**' matches files
        // that end in .ts because the globstar indicates 0 or more directory paths.
        this.exclude = ensureArray(options.exclude)
            .concat(defaultExclude)
            .map((item) => (item.endsWith('**') ? item : `${item}/**`));
        // remove all leading './' since this messes up globstar matches in the
        // excludes.
        this.include = ensureArray(options.include, '**')
            .map((item) => (item.startsWith('./') ? item.substring(2) : item))
            .map((item) => (item.endsWith('**') ? item : `${item}/**`));
        this.cwd = options.cwd || process.cwd();
        this.analysisLanguages = options.analysisLanguages;
    }
    /**
     * Calculate directory info.
     */
    async loadInfo() {
        const paths = await globby_1.default(this.include, {
            cwd: this.cwd,
            ignore: this.exclude,
            nodir: true,
        });
        const files = [];
        const info = { ...defaultInfo };
        let languages = {};
        // We _could_ use Promise.all to count the files in parallel, but that
        // would lead to out of memory errors when there are many files.
        // eslint-disable-next-line no-restricted-syntax
        for (const pathItem of paths) {
            const fullPath = slash2_1.default(path_1.default.join(this.cwd, pathItem));
            if (!pathItem ||
                this.ignoreLanguage(pathItem) ||
                !(await fs_extra_1.default.pathExists(fullPath)) ||
                (await fs_extra_1.default.stat(fullPath)).isDirectory()) {
                continue;
            }
            const file = new file_1.LocFile(fullPath);
            const fileLineInfo = await file.getFileInfo();
            const { lines } = fileLineInfo;
            info.total += lines.total;
            info.code += lines.code;
            info.comment += lines.comment;
            const language = { ...languages[fileLineInfo.languages] };
            language.code = lines.code + (language.code || 0);
            language.sum = (language.sum || 0) + 1;
            language.comment = lines.comment + (language.comment || 0);
            language.total = lines.total + (language.total || 0);
            languages = {
                ...languages,
                [fileLineInfo.languages]: language,
            };
            files.push(fullPath);
        }
        return {
            files,
            info,
            languages,
        };
    }
    /**
     * Ignore analyzing this file if analysis languages are specified
     * and this language is not one of them.
     */
    ignoreLanguage(pathItem) {
        return (this.analysisLanguages &&
            !this.analysisLanguages.includes(this.allLanguages.getType(pathItem)));
    }
}
exports.LocDir = LocDir;
//# sourceMappingURL=directory.js.map