Repository: ele828/hexo-prism-plugin Branch: master Commit: 1f133ff6688d Files: 5 Total size: 8.6 KB Directory structure: gitextract__4kl7k9z/ ├── .editorconfig ├── .gitignore ├── README.md ├── package.json └── src/ └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true ================================================ FILE: .gitignore ================================================ node_modules/ .vscode/ debug.log ================================================ FILE: README.md ================================================ # Hexo-Prism-Plugin [](https://www.npmjs.com/package/hexo-prism-plugin) Since `highlight.js` didn't support JSX syntax properly, I wrote this plugin to replace Hexo's default code highlight plugin. ## Install ``` npm i -S hexo-prism-plugin ``` ## Usage Firstly, you should edit your `_config.yml` by adding following configuration. ```yaml prism_plugin: mode: 'preprocess' # realtime/preprocess theme: 'default' line_number: false # default false custom_css: 'path/to/your/custom.css' # optional ``` After that, check `highlight` option in `_config.yml`. Make sure that default code highlight plugin is disabled. ```yaml highlight: enable: false ``` Finally, clean and re-generate your project by running following commands: ``` hexo clean ``` ``` hexo generate ``` ## Options - mode: - realtime (Parse code on browser in real time) - preprocess (Preprocess code in node) - theme: - default - coy - dark - funky - okaidia - solarizedlight - tomorrow - twilight - atom-dark - base16-ateliersulphurpool.light - cb - duotone-dark - duotone-earth - duotone-forest - duotone-light - duotone-sea - duotone-space - ghcolors - hopscotch - pojoaque - vs - xonokai - line_number: - true (Show line numbers) - false (Default, Hide line numbers) - no_assets - true (Stop loading asset files) - false (Default, load script and stylesheets files) ## Themes You can check out prism-themes project for additional theme preview: https://github.com/PrismJS/prism-themes#available-themes ## Supported languages You could find the supported languages here: http://prismjs.com/#languages-list ## License MIT ================================================ FILE: package.json ================================================ { "name": "hexo-prism-plugin", "version": "2.3.0", "description": "Hexo code highlight by Prism.js", "main": "src/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Eric Huang", "license": "MIT", "dependencies": { "dir-resolve": "^1.0.2", "hexo-fs": "^0.2.1", "node-prismjs": "^0.1.0", "prism-themes": "^1.0.0", "prismjs": "^1.6.0" } } ================================================ FILE: src/index.js ================================================ 'use strict'; const fs = require('hexo-fs'); const path = require('path'); const Prism = require('node-prismjs'); const dirResolve = require('dir-resolve'); const map = { ''': '\'', '&': '&', '>': '>', '<': '<', '"': '"' }; const themeRegex = /^prism-(.*).css$/; const regex = /
([\s\S]*?)<\/code><\/pre>/igm;
const captionRegex = /(?![\s\S]*<\/p>/igm;
/**
* Unescape from Marked escape
* @param {String} str
* @return {String}
*/
function unescape(str) {
if (!str || str === null) return '';
const re = new RegExp('(' + Object.keys(map).join('|') + ')', 'g');
return String(str).replace(re, (match) => map[match]);
}
/**
* Wrap theme file to unified format
* @param {String} basePath
* @param {String} filename
* @return {Object}
*/
function toThemeMap(basePath, filename) {
const matches = filename.match(themeRegex);
if (!matches)
return;
return {
name: matches[1],
filename,
path: path.join(basePath, filename)
};
}
const rootPath = hexo.config.root || '/';
const prismLineNumbersPluginDir = dirResolve('prismjs/plugins/line-numbers');
const prismThemeDir = dirResolve('prismjs/themes');
const extraThemeDir = dirResolve('prism-themes/themes');
const prismMainFile = require.resolve('prismjs');
const standardThemes = fs.listDirSync(prismThemeDir)
.map(themeFileName => toThemeMap(prismThemeDir, themeFileName));
const extraThemes = fs.listDirSync(extraThemeDir)
.map(themeFileName => toThemeMap(extraThemeDir, themeFileName));
// Since the regex will not match for the default "prism.css" theme,
// we filter the null theme out and manually add the default theme to the array
const themes = standardThemes.concat(extraThemes).filter(Boolean);
themes.push({
name: 'default',
filename: 'prism.css',
path: path.join(prismThemeDir, 'prism.css')
});
// If prism plugin has not been configured, it cannot be initialized properly.
if (!hexo.config.prism_plugin) {
throw new Error('`prism_plugin` options should be added to _config.yml file');
}
// Plugin settings from config
const prismThemeName = hexo.config.prism_plugin.theme || 'default';
const mode = hexo.config.prism_plugin.mode || 'preprocess';
const line_number = hexo.config.prism_plugin.line_number || false;
const custom_css = hexo.config.prism_plugin.custom_css || null;
const no_assets = hexo.config.prism_plugin.no_assets || false;
const prismTheme = themes.find(theme => theme.name === prismThemeName);
if (!prismTheme) {
throw new Error("Invalid theme " + prismThemeName + ". Valid Themes: \n" + themes.map(t => t.name).concat('\n'));
}
const prismThemeFileName = prismTheme.filename;
const prismThemeFilePath = custom_css === null ? prismTheme.path : path.join(hexo.base_dir, custom_css);
/**
* Code transform for prism plugin.
* @param {Object} data
* @return {Object}
*/
function PrismPlugin(data) {
// Patch for caption support
if (captionRegex.test(data.content)) {
// Attempt to parse the code
data.content = data.content.replace(captionRegex, (origin, lang, caption, code) => {
if (!lang || !caption || !code) return origin;
return `${caption} ${code}
`;
})
}
data.content = data.content.replace(regex, (origin, lang, code) => {
const lineNumbers = line_number ? 'line-numbers' : '';
const startTag = ``;
const endTag = `
`;
code = unescape(code);
let parsedCode = '';
if (Prism.languages[lang]) {
parsedCode = Prism.highlight(code, Prism.languages[lang]);
} else {
parsedCode = code;
}
if (line_number) {
const match = parsedCode.match(/\n(?!$)/g);
const linesNum = match ? match.length + 1 : 1;
let lines = new Array(linesNum + 1);
lines = lines.join('');
const startLine = '';
parsedCode += startLine + lines + endLine;
}
return startTag + parsedCode + endTag;
});
return data;
}
/**
* Copy asset to hexo public folder.
*/
function copyAssets() {
const assets = [{
path: `css/${prismThemeFileName}`,
data: () => fs.createReadStream(prismThemeFilePath)
}];
// If line_number is enabled in plugin config add the corresponding stylesheet
if (line_number) {
assets.push({
path: 'css/prism-line-numbers.css',
data: () => fs.createReadStream(path.join(prismLineNumbersPluginDir, 'prism-line-numbers.css'))
});
}
// If prism plugin config mode is realtime include prism.js and line-numbers.js
if (mode === 'realtime') {
assets.push({
path: 'js/prism.js',
data: () => fs.createReadStream(prismMainFile)
});
if (line_number) {
assets.push({
path: 'js/prism-line-numbers.min.js',
data: () => fs.createReadStream(path.join(prismLineNumbersPluginDir, 'prism-line-numbers.min.js'))
});
}
}
return assets;
}
/**
* Injects code to html for importing assets.
* @param {String} code
* @param {Object} data
*/
function importAssets(code, data) {
const js = [];
const css = [
``
];
if (line_number && custom_css === null) {
css.push(``);
}
if (mode === 'realtime') {
js.push(``);
if (line_number) {
js.push(``);
}
}
const imports = css.join('\n') + js.join('\n');
// Avoid duplicates
if (code.indexOf(imports) > -1) {
return code;
}
return code.replace(/<\s*\/\s*head\s*>/, imports + '');;
}
// Register prism plugin
// Set priority to make sure PrismPlugin executed first
// Lower priority means that it will be executed first. The default priority is 10.
hexo.extend.filter.register('after_post_render', PrismPlugin, 9);
if (custom_css === null && !no_assets) {
// Register to append static assets
hexo.extend.generator.register('prism_assets', copyAssets);
// Register for importing static assets
hexo.extend.filter.register('after_render:html', importAssets);
}