blog/themes/fluid/scripts/events/lib/highlight.js

155 lines
5.5 KiB
JavaScript
Raw Normal View History

2024-11-16 11:34:10 +08:00
'use strict';
let css;
try {
css = require('css');
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
css = require('@adobe/css-tools');
} else {
throw error;
}
}
const fs = require('fs');
const objUtil = require('../../utils/object');
const resolveModule = require('../../utils/resolve');
module.exports = (hexo) => {
function resolveHighlight(name) {
if (!name) {
name = 'github-gist';
}
const cssName = name.toLowerCase().replace(/([^0-9])\s+?([^0-9])/g, '$1-$2').replace(/\s/g, '');
let file = resolveModule('highlight.js', `styles/${cssName}.css`);
if (cssName === 'github-gist' && !fs.existsSync(file)) {
file = resolveModule('highlight.js', 'styles/github.css');
}
let backgroundColor;
if (fs.existsSync(file)) {
const content = fs.readFileSync(file, 'utf8');
css.parse(content).stylesheet.rules
.filter(rule => rule.type === 'rule' && rule.selectors.some(selector => selector.endsWith('.hljs')))
.flatMap(rule => rule.declarations)
.forEach(declaration => {
if (declaration.property === 'background' || declaration.property === 'background-color') {
backgroundColor = declaration.value;
}
});
} else {
hexo.log.error(`[Fluid] highlightjs style '${name}' not found`);
return {};
}
if (backgroundColor === 'white' || backgroundColor === '#ffffff') {
backgroundColor = '#fff';
}
return { file, backgroundColor };
}
function resolvePrism(name) {
if (!name) {
name = 'default';
}
let cssName = name.toLowerCase().replace(/[\s-]/g, '');
if (cssName === 'prism' || cssName === 'default') {
cssName = '';
} else if (cssName === 'tomorrownight') {
cssName = 'tomorrow';
}
let file = resolveModule('prismjs', `themes/${cssName ? 'prism-' + cssName : 'prism'}.css`);
if (!fs.existsSync(file)) {
file = resolveModule('prism-themes', `themes/${cssName}.css`);
}
if (!fs.existsSync(file)) {
hexo.log.error(`[Fluid] prismjs style '${name}' not found`);
return {};
}
return { file };
}
const config = hexo.theme.config;
if (!config.code || !config.code.highlight.enable) {
return;
}
if (config.code.highlight.lib === 'highlightjs') {
// Force set hexo config
hexo.config.prismjs = objUtil.merge({}, hexo.config.prismjs, {
enable: false
});
hexo.config.highlight = objUtil.merge({}, hexo.config.highlight, {
enable : true,
hljs : true,
wrap : false,
auto_detect: true,
line_number: config.code.highlight.line_number || false
});
hexo.theme.config.code.highlight.highlightjs = objUtil.merge({}, hexo.theme.config.code.highlight.highlightjs, {
light: resolveHighlight(hexo.theme.config.code.highlight.highlightjs.style),
dark : hexo.theme.config.dark_mode.enable && resolveHighlight(hexo.theme.config.code.highlight.highlightjs.style_dark)
});
hexo.extend.filter.register('after_post_render', (page) => {
if (hexo.config.highlight.line_number) {
page.content = page.content.replace(/<figure[^>]+?highlight.+?<td[^>]+?code[^>]+?>.*?(<pre.+?<\/pre>).+?<\/figure>/gims, (str, p1) => {
if (/<code[^>]+?mermaid[^>]+?>/ims.test(p1)) {
return p1.replace(/(class="[^>]*?)hljs([^>]*?")/gims, '$1$2').replace(/<br>/gims, '\n');
}
return str;
});
} else {
page.content = page.content.replace(/(?<!<div class="code-wrapper">)<pre.+?<\/pre>/gims, (str) => {
if (/<code[^>]+?mermaid[^>]+?>/ims.test(str)) {
return str.replace(/(class=".*?)hljs(.*?")/gims, '$1$2');
}
return `<div class="code-wrapper">${str}</div>`;
});
}
// 适配缩进型代码块
page.content = page.content.replace(/<pre><code>/gims, (str) => {
return '<pre><code class="hljs">';
});
return page;
});
} else if (config.code.highlight.lib === 'prismjs') {
// Force set hexo config
hexo.config.highlight = objUtil.merge({}, hexo.config.highlight, {
enable: false
});
hexo.config.prismjs = objUtil.merge({}, hexo.config.prismjs, {
enable : true,
preprocess : config.code.highlight.prismjs.preprocess || false,
line_number: config.code.highlight.line_number || false
});
hexo.theme.config.code.highlight.prismjs = objUtil.merge({}, hexo.theme.config.code.highlight.prismjs, {
light: resolvePrism(hexo.theme.config.code.highlight.prismjs.style),
dark : hexo.theme.config.dark_mode.enable && resolvePrism(hexo.theme.config.code.highlight.prismjs.style_dark)
});
hexo.extend.filter.register('after_post_render', (page) => {
page.content = page.content.replace(/(?<!<div class="code-wrapper">)<pre.+?<\/pre>/gims, (str) => {
if (/<code[^>]+?mermaid[^>]+?>/ims.test(str)) {
if (hexo.config.highlight.line_number) {
str = str.replace(/<span[^>]+?line-numbers-rows[^>]+?>.+?<\/span><\/code>/, '</code>');
}
str = str.replace(/<pre[^>]*?>/gims, '<pre>')
.replace(/(class=".*?)language-mermaid(.*?")/gims, '$1mermaid$2')
.replace(/<span[^>]+?>(.+?)<\/span>/gims, '$1');
return str;
}
return `<figure><div class="code-wrapper">${str}</div></figure>`;
});
// 适配缩进型代码块
page.content = page.content.replace(/<pre><code>/gims, (str) => {
return '<pre class="language-none"><code class="language-none">';
});
return page;
});
}
};