"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
const strip_indent_1 = __importDefault(require("strip-indent"));
// eslint-disable-next-line @typescript-eslint/no-var-requires
const alias = require('../highlight_alias.json');
let hljs;
function highlightUtil(str, options = {}) {
    if (typeof str !== 'string')
        throw new TypeError('str must be a string!');
    const useHljs = Object.prototype.hasOwnProperty.call(options, 'hljs') ? options.hljs : false;
    const { gutter = true, firstLine = 1, caption, mark = [], languageAttr = false, tab, stripIndent: enableStripIndent = true } = options;
    let { wrap = true } = options;
    if (enableStripIndent) {
        str = (0, strip_indent_1.default)(str);
    }
    if (!hljs) {
        hljs = require('highlight.js');
    }
    hljs.configure({ classPrefix: useHljs ? 'hljs-' : '' });
    const data = highlight(str, options);
    const lang = options.lang || data.language || '';
    const classNames = (useHljs ? 'hljs' : 'highlight') + (lang ? ` ${lang}` : '');
    if (gutter && !wrap)
        wrap = true; // arbitrate conflict ("gutter:true" takes priority over "wrap:false")
    const before = useHljs ? `<pre><code class="${classNames}"${languageAttr && lang ? ` data-language="${lang}"` : ''}>` : '<pre>';
    const after = useHljs ? '</code></pre>' : '</pre>';
    const lines = data.value.split('\n');
    let numbers = '';
    let content = '';
    for (let i = 0, len = lines.length; i < len; i++) {
        let line = lines[i];
        if (tab)
            line = replaceTabs(line, tab);
        numbers += `<span class="line">${Number(firstLine) + i}</span><br>`;
        content += formatLine(line, Number(firstLine) + i, mark, options, wrap);
    }
    let codeCaption = '';
    if (caption) {
        codeCaption = wrap ? `<figcaption>${caption}</figcaption>` : `<div class="caption">${caption}</div>`;
    }
    if (!wrap) {
        // if original content has one trailing newline, replace it only once, else remove all trailing newlines
        content = /\r?\n$/.test(data.value) ? content.replace(/\n$/, '') : content.trimEnd();
        return `<pre>${codeCaption}<code class="${classNames}"${languageAttr && lang ? ` data-language="${lang}"` : ''}>${content}</code></pre>`;
    }
    let result = `<figure class="highlight${data.language ? ` ${data.language}` : ''}"${languageAttr && lang ? ` data-language="${lang}"` : ''}>`;
    result += codeCaption;
    result += '<table><tr>';
    if (gutter) {
        result += `<td class="gutter"><pre>${numbers}</pre></td>`;
    }
    result += `<td class="code">${before}${content}${after}</td>`;
    result += '</tr></table></figure>';
    return result;
}
function formatLine(line, lineno, marked, options, wrap) {
    const useHljs = (options.hljs || false) || !wrap;
    const br = wrap ? '<br>' : '\n';
    let res = useHljs ? '' : '<span class="line';
    if (marked.includes(lineno)) {
        // Handle marked lines.
        res += useHljs ? `<mark>${line}</mark>` : ` marked">${line}</span>`;
    }
    else {
        res += useHljs ? line : `">${line}</span>`;
    }
    res += br;
    return res;
}
function replaceTabs(str, tab) {
    return str.replace(/\t+/, match => tab.repeat(match.length));
}
function highlight(str, options) {
    let { lang } = options;
    const { autoDetect = false } = options;
    if (!hljs) {
        hljs = require('highlight.js');
    }
    if (lang) {
        lang = lang.toLowerCase();
    }
    else if (autoDetect) {
        const result = hljs.highlightAuto(str);
        return closeTags(result);
    }
    if (!lang || !alias.aliases[lang]) {
        lang = 'plaintext';
    }
    const res = hljs.highlight(str, {
        language: lang,
        ignoreIllegals: true
    });
    return closeTags(res);
}
// https://github.com/hexojs/hexo-util/issues/10
function closeTags(res) {
    const tokenStack = [];
    res.value = res.value.split('\n').map(line => {
        const prepend = tokenStack.map(token => `<span class="${token}">`).join('');
        const matches = line.matchAll(/(<span class="(.*?)">|<\/span>)/g);
        for (const match of matches) {
            if (match[0] === '</span>')
                tokenStack.shift();
            else
                tokenStack.unshift(match[2]);
        }
        const append = '</span>'.repeat(tokenStack.length);
        return prepend + line + append;
    }).join('\n');
    return res;
}
module.exports = highlightUtil;
//# sourceMappingURL=highlight.js.map