1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | const highlight_js_1 = __importDefault(require("highlight.js"));
|
6 | const strip_indent_1 = __importDefault(require("strip-indent"));
|
7 |
|
8 | const alias = require('../highlight_alias.json');
|
9 | function highlightUtil(str, options = {}) {
|
10 | if (typeof str !== 'string')
|
11 | throw new TypeError('str must be a string!');
|
12 | str = (0, strip_indent_1.default)(str);
|
13 | const useHljs = Object.prototype.hasOwnProperty.call(options, 'hljs') ? options.hljs : false;
|
14 | const { gutter = true, firstLine = 1, caption, mark = [], languageAttr = false, tab } = options;
|
15 | let { wrap = true } = options;
|
16 | highlight_js_1.default.configure({ classPrefix: useHljs ? 'hljs-' : '' });
|
17 | const data = highlight(str, options);
|
18 | const lang = options.lang || data.language || '';
|
19 | const classNames = (useHljs ? 'hljs' : 'highlight') + (lang ? ` ${lang}` : '');
|
20 | if (gutter && !wrap)
|
21 | wrap = true;
|
22 | const before = useHljs ? `<pre><code class="${classNames}"${languageAttr && lang ? ` data-language="${lang}"` : ''}>` : '<pre>';
|
23 | const after = useHljs ? '</code></pre>' : '</pre>';
|
24 | const lines = data.value.split('\n');
|
25 | let numbers = '';
|
26 | let content = '';
|
27 | for (let i = 0, len = lines.length; i < len; i++) {
|
28 | let line = lines[i];
|
29 | if (tab)
|
30 | line = replaceTabs(line, tab);
|
31 | numbers += `<span class="line">${Number(firstLine) + i}</span><br>`;
|
32 | content += formatLine(line, Number(firstLine) + i, mark, options, wrap);
|
33 | }
|
34 | let codeCaption = '';
|
35 | if (caption) {
|
36 | codeCaption = wrap ? `<figcaption>${caption}</figcaption>` : `<div class="caption">${caption}</div>`;
|
37 | }
|
38 | if (!wrap) {
|
39 |
|
40 | content = /\r?\n$/.test(data.value) ? content.replace(/\n$/, '') : content.trimEnd();
|
41 | return `<pre>${codeCaption}<code class="${classNames}"${languageAttr && lang ? ` data-language="${lang}"` : ''}>${content}</code></pre>`;
|
42 | }
|
43 | let result = `<figure class="highlight${data.language ? ` ${data.language}` : ''}"${languageAttr && lang ? ` data-language="${lang}"` : ''}>`;
|
44 | result += codeCaption;
|
45 | result += '<table><tr>';
|
46 | if (gutter) {
|
47 | result += `<td class="gutter"><pre>${numbers}</pre></td>`;
|
48 | }
|
49 | result += `<td class="code">${before}${content}${after}</td>`;
|
50 | result += '</tr></table></figure>';
|
51 | return result;
|
52 | }
|
53 | function formatLine(line, lineno, marked, options, wrap) {
|
54 | const useHljs = (options.hljs || false) || !wrap;
|
55 | const br = wrap ? '<br>' : '\n';
|
56 | let res = useHljs ? '' : '<span class="line';
|
57 | if (marked.includes(lineno)) {
|
58 |
|
59 | res += useHljs ? `<mark>${line}</mark>` : ` marked">${line}</span>`;
|
60 | }
|
61 | else {
|
62 | res += useHljs ? line : `">${line}</span>`;
|
63 | }
|
64 | res += br;
|
65 | return res;
|
66 | }
|
67 | function replaceTabs(str, tab) {
|
68 | return str.replace(/\t+/, match => tab.repeat(match.length));
|
69 | }
|
70 | function highlight(str, options) {
|
71 | let { lang } = options;
|
72 | const { autoDetect = false } = options;
|
73 | if (lang) {
|
74 | lang = lang.toLowerCase();
|
75 | }
|
76 | else if (autoDetect) {
|
77 | const result = highlight_js_1.default.highlightAuto(str);
|
78 | return closeTags(result);
|
79 | }
|
80 | if (!lang || !alias.aliases[lang]) {
|
81 | lang = 'plaintext';
|
82 | }
|
83 | const res = highlight_js_1.default.highlight(str, {
|
84 | language: lang,
|
85 | ignoreIllegals: true
|
86 | });
|
87 | return closeTags(res);
|
88 | }
|
89 |
|
90 | function closeTags(res) {
|
91 | const tokenStack = [];
|
92 | res.value = res.value.split('\n').map(line => {
|
93 | const prepend = tokenStack.map(token => `<span class="${token}">`).join('');
|
94 | const matches = line.matchAll(/(<span class="(.*?)">|<\/span>)/g);
|
95 | for (const match of matches) {
|
96 | if (match[0] === '</span>')
|
97 | tokenStack.shift();
|
98 | else
|
99 | tokenStack.unshift(match[2]);
|
100 | }
|
101 | const append = '</span>'.repeat(tokenStack.length);
|
102 | return prepend + line + append;
|
103 | }).join('\n');
|
104 | return res;
|
105 | }
|
106 | module.exports = highlightUtil;
|
107 |
|
\ | No newline at end of file |