"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Languages = void 0;
const languages_json_1 = __importDefault(require("language-map/languages.json"));
const utils_1 = require("./utils");
/**
 * The extension map can contain multiple languages with the same extension,
 * but we only want a single one. For the moment, these clashes are resolved
 * by the simple heuristic below listing high-priority languages. We may want
 * to consider smarter heuristics to correctly identify languages in cases
 * where the extension is ambiguous. The ordering of the list matters and
 * languages earlier on will get a higher priority when resolving clashes.
 */
const importantLanguages = [
    'javascript',
    'typescript',
    'ruby',
    'python',
    'java',
    'c',
    'c++',
    'c#',
    'rust',
    'scala',
    'perl',
    'go',
];
const ALL_REGEXES = {
    c: {
        // matches when // are the first two characters of a line
        singleLineComment: /^\/\//,
        // matches when /* exists in a line
        multiLineCommentOpen: /\/\*/,
        // matches when /* starts a line
        multiLineCommentOpenStart: /^\/\*/,
        // matches when */ exists a line
        multiLineCommentClose: /\*\//,
        // matches when */ ends a line
        multiLineCommentCloseEnd: /\*\/$/,
        // matches /* ... */
        multiLineCommentOpenAndClose: /\/\*.*\*\//,
    },
    python: {
        // matches when # the first character of a line
        singleLineComment: /^#/,
    },
    ruby: {
        // matches when # the first character of a line
        singleLineComment: /^#/,
        // For ruby multiline comments, =begin and =end must be
        // on their own lines
        // matches when =begin starts a line
        multiLineCommentOpen: /^=begin/,
        // matches when "begin starts a line
        multiLineCommentOpenStart: /^=begin/,
        // matches when "end ends a line
        multiLineCommentClose: /^=end/,
        // matches when "end ends a line
        multiLineCommentCloseEnd: /^=end$/,
        // not possible in ruby
        multiLineCommentOpenAndClose: /^\0$/,
    },
    html: {
        // There is no single line comment
        singleLineComment: /^\0$/,
        // matches when =begin starts a line
        multiLineCommentOpen: /<!--/,
        // matches when "begin starts a line
        multiLineCommentOpenStart: /^<!--/,
        // matches when "end ends a line
        multiLineCommentClose: /-->/,
        // matches when "end ends a line
        multiLineCommentCloseEnd: /-->$/,
        // matches <!-- ... -->
        multiLineCommentOpenAndClose: /<!--.*-->/,
    },
};
/**
 * detecte program language through file extension
 *
 * @export
 * @class LanguageDetector
 */
class Languages {
    /**
     * Creates an instance of Detector.
     */
    constructor() {
        Object.defineProperty(this, "extensionMap", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: {}
        });
        /**
         * load language before detecting
         */
        Object.defineProperty(this, "loadExtensionMap", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: () => {
                const extensions = {};
                Object.keys(languages_json_1.default).forEach((language) => {
                    const languageMode = languages_json_1.default[language];
                    const languageExtensions = (languageMode && languageMode.extensions) || [];
                    languageExtensions.forEach((extension) => {
                        const lowerCaseExtension = extension.toLowerCase();
                        const lowerCaseLanguage = language.toLowerCase();
                        if (!extensions[lowerCaseExtension]) {
                            extensions[lowerCaseExtension] = lowerCaseLanguage;
                        }
                        else {
                            const currentLanguagePriority = importantLanguages.indexOf(extensions[lowerCaseExtension]);
                            if (currentLanguagePriority === -1) {
                                extensions[lowerCaseExtension] = lowerCaseLanguage;
                            }
                            else {
                                const otherPriority = importantLanguages.indexOf(lowerCaseLanguage);
                                if (otherPriority !== -1 && otherPriority < currentLanguagePriority)
                                    extensions[lowerCaseExtension] = lowerCaseLanguage;
                            }
                        }
                    });
                });
                return { ...extensions, ...utils_1.ExtensionJustify };
            }
        });
        this.extensionMap = this.loadExtensionMap();
    }
    /**
     * Retrieve the regular expressions for a given language.
     * This is incomplete, but covers most of the languages we
     * see in the wild.
     *
     * @param language the language to retrieve regexes for
     */
    getRegexes(language) {
        switch (language) {
            case 'html':
            case 'xml':
                return ALL_REGEXES.html;
            case 'ruby':
                return ALL_REGEXES.ruby;
            case 'python':
                return ALL_REGEXES.python;
            default:
                // not exact, but likely the best guess for any other unspecified language.
                return ALL_REGEXES.c;
        }
    }
    /**
     * return extension map
     */
    getExtensionMap() {
        return this.extensionMap;
    }
    /**
     * get file type through a path
     */
    getType(path) {
        const fileExtension = `.${path.split('.').pop()}`;
        return this.extensionMap[fileExtension] || '';
    }
}
exports.Languages = Languages;
//# sourceMappingURL=languages.js.map