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 [![NPM](https://img.shields.io/npm/dm/hexo-prism-plugin.svg)](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); }