diff --git a/lib/extend/filter.js b/lib/extend/filter.js index ab08288cf9..966a971524 100644 --- a/lib/extend/filter.js +++ b/lib/extend/filter.js @@ -92,22 +92,6 @@ class Filter { return args[0]; } - - execFirstSync(type, data, options = {}) { - const filters = this.list(type); - const filtersLen = filters.length; - if (filtersLen === 0) return null; - - const ctx = options.context; - const args = options.args || []; - - args.unshift(data); - - const result = Reflect.apply(filters[0], ctx, args); - args[0] = result == null ? args[0] : result; - - return args[0]; - } } module.exports = Filter; diff --git a/lib/extend/highlight.js b/lib/extend/highlight.js new file mode 100644 index 0000000000..4419edb334 --- /dev/null +++ b/lib/extend/highlight.js @@ -0,0 +1,29 @@ +'use strict'; + +class Highlight { + constructor() { + this.store = {}; + } + + register(name, fn) { + if (typeof fn !== 'function') throw new TypeError('fn must be a function'); + + this.store[name] = fn; + } + + query(name) { + return name && this.store[name]; + } + + exec(name, options) { + const fn = this.store[name]; + + if (!fn) throw new TypeError(`highlighter ${name} is not registered`); + const ctx = options.context; + const args = options.args || []; + + return Reflect.apply(fn, ctx, args); + } +} + +module.exports = Highlight; diff --git a/lib/extend/index.js b/lib/extend/index.js index 5e4eb37b28..73ed1d602b 100644 --- a/lib/extend/index.js +++ b/lib/extend/index.js @@ -5,6 +5,7 @@ exports.Deployer = require('./deployer'); exports.Filter = require('./filter'); exports.Generator = require('./generator'); exports.Helper = require('./helper'); +exports.Highlight = require('./highlight'); exports.Injector = require('./injector'); exports.Migrator = require('./migrator'); exports.Processor = require('./processor'); diff --git a/lib/hexo/default_config.js b/lib/hexo/default_config.js index 07c0d5ed01..95ea520cc1 100644 --- a/lib/hexo/default_config.js +++ b/lib/hexo/default_config.js @@ -40,6 +40,7 @@ module.exports = { post_asset_folder: false, relative_link: false, future: true, + highlighter: 'highlight.js', highlight: { enable: true, auto_detect: false, diff --git a/lib/hexo/index.js b/lib/hexo/index.js index 61d637872c..7bbbdd2fb4 100644 --- a/lib/hexo/index.js +++ b/lib/hexo/index.js @@ -11,7 +11,7 @@ const Module = require('module'); const { runInThisContext } = require('vm'); const { version } = require('../../package.json'); const logger = require('hexo-log'); -const { Console, Deployer, Filter, Generator, Helper, Injector, Migrator, Processor, Renderer, Tag } = require('../extend'); +const { Console, Deployer, Filter, Generator, Helper, Highlight, Injector, Migrator, Processor, Renderer, Tag } = require('../extend'); const Render = require('./render'); const registerModels = require('./register_models'); const Post = require('./post'); @@ -123,6 +123,7 @@ class Hexo extends EventEmitter { filter: new Filter(), generator: new Generator(), helper: new Helper(), + highlight: new Highlight(), injector: new Injector(), migrator: new Migrator(), processor: new Processor(), @@ -479,10 +480,6 @@ class Hexo extends EventEmitter { }); } - queryFilterCount(type) { - return this.extend.filter.queryCount(type); - } - execFilter(type, data, options) { return this.extend.filter.exec(type, data, options); } @@ -490,10 +487,6 @@ class Hexo extends EventEmitter { execFilterSync(type, data, options) { return this.extend.filter.execSync(type, data, options); } - - execFirstFilterSync(type, data, options) { - return this.extend.filter.execFirstSync(type, data, options); - } } Hexo.lib_dir = libDir + sep; diff --git a/lib/hexo/load_highlight.js b/lib/hexo/load_highlight.js index c61572c3c8..7f352a5291 100644 --- a/lib/hexo/load_highlight.js +++ b/lib/hexo/load_highlight.js @@ -1,3 +1,3 @@ 'use strict'; -module.exports = require('../plugins/filter/highlight'); +module.exports = require('../plugins/highlight'); diff --git a/lib/plugins/filter/before_post_render/backtick_code_block.js b/lib/plugins/filter/before_post_render/backtick_code_block.js index 4f742c058c..4732537618 100644 --- a/lib/plugins/filter/before_post_render/backtick_code_block.js +++ b/lib/plugins/filter/before_post_render/backtick_code_block.js @@ -10,13 +10,13 @@ module.exports = ctx => { return function backtickCodeBlock(data) { const dataContent = data.content; - if ((!dataContent.includes('```') && !dataContent.includes('~~~')) || !ctx.queryFilterCount('highlight')) return; + if ((!dataContent.includes('```') && !dataContent.includes('~~~')) || !ctx.extend.highlight.query(ctx.config.highlighter)) return; data.content = dataContent.replace(rBacktick, ($0, start, $2, _args, _content, end) => { let content = _content.replace(/\n$/, ''); // neither highlight or prismjs is enabled, return escaped content directly. - if (!ctx.queryFilterCount('highlight')) return escapeSwigTag($0); + if (!ctx.extend.highlight.query(ctx.config.highlighter)) return escapeSwigTag($0); // Extract language and caption of code blocks const args = _args.split('=').shift(); @@ -58,7 +58,10 @@ module.exports = ctx => { if (_args.includes('=')) { options.firstLineNumber = _args.split('=')[1] || 1; } - content = ctx.execFirstFilterSync('highlight', content, { args: [options] }); + content = ctx.extend.highlight.exec(ctx.config.highlighter, { + context: ctx, + args: [content, options] + }); return start + '' diff --git a/lib/plugins/filter/highlight/index.js b/lib/plugins/filter/highlight/index.js deleted file mode 100644 index 9242397990..0000000000 --- a/lib/plugins/filter/highlight/index.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -module.exports = ctx => { - const { filter } = ctx.extend; - const hljsCfg = ctx.config.highlight || {}; - const prismCfg = ctx.config.prismjs || {}; - - // Since prismjs have better performance, so prismjs should have higher priority. - if (prismCfg.enable) { - filter.register('highlight', require('./prism')(ctx)); - } else if (hljsCfg.enable) { - filter.register('highlight', require('./highlight')(ctx)); - } -}; diff --git a/lib/plugins/filter/index.js b/lib/plugins/filter/index.js index f28ea91410..f349b99b29 100644 --- a/lib/plugins/filter/index.js +++ b/lib/plugins/filter/index.js @@ -9,7 +9,6 @@ module.exports = ctx => { require('./before_exit')(ctx); require('./before_generate')(ctx); require('./template_locals')(ctx); - require('./highlight')(ctx); filter.register('new_post_path', require('./new_post_path')); filter.register('post_permalink', require('./post_permalink')); diff --git a/lib/plugins/filter/highlight/highlight.js b/lib/plugins/highlight/highlight.js similarity index 100% rename from lib/plugins/filter/highlight/highlight.js rename to lib/plugins/highlight/highlight.js diff --git a/lib/plugins/highlight/index.js b/lib/plugins/highlight/index.js new file mode 100644 index 0000000000..c5ed14442d --- /dev/null +++ b/lib/plugins/highlight/index.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = ctx => { + const { highlight } = ctx.extend; + + highlight.register('highlight.js', require('./highlight')(ctx)); + highlight.register('prismjs', require('./prism')(ctx)); +}; diff --git a/lib/plugins/filter/highlight/prism.js b/lib/plugins/highlight/prism.js similarity index 100% rename from lib/plugins/filter/highlight/prism.js rename to lib/plugins/highlight/prism.js diff --git a/lib/plugins/tag/code.js b/lib/plugins/tag/code.js index 6a9250375c..ca6ead4f70 100644 --- a/lib/plugins/tag/code.js +++ b/lib/plugins/tag/code.js @@ -119,7 +119,7 @@ function parseArgs(args) { module.exports = ctx => function codeTag(args, content) { // If neither highlight.js nor prism.js is enabled, return escaped code directly - if (!ctx.queryFilterCount('highlight')) { + if (!ctx.extend.highlight.query(ctx.config.highlighter)) { return `
${escapeHTML(content)}
`; } @@ -140,7 +140,10 @@ module.exports = ctx => function codeTag(args, content) { const options = parseArgs(args); options.lines_length = content.split('\n').length; - content = ctx.execFirstFilterSync('highlight', content, { args: [options] }); + content = ctx.extend.highlight.exec(ctx.config.highlighter, { + context: ctx, + args: [content, options] + }); return content.replace(/{/g, '{').replace(/}/g, '}'); }; diff --git a/lib/plugins/tag/include_code.js b/lib/plugins/tag/include_code.js index bf457e27bd..4676eb135b 100644 --- a/lib/plugins/tag/include_code.js +++ b/lib/plugins/tag/include_code.js @@ -62,13 +62,16 @@ module.exports = ctx => function includeCodeTag(args) { const lines = code.split('\n'); code = lines.slice(from, to).join('\n').trim(); - if (ctx.queryFilterCount('highlight')) { + if (ctx.extend.highlight.query(ctx.config.highlighter)) { const options = { lang, caption, lines_length: lines.length }; - return ctx.execFirstFilterSync('highlight', code, { args: [options] }); + return ctx.extend.highlight.exec(ctx.config.highlighter, { + context: ctx, + args: [code, options] + }); } return `
${code}
`; diff --git a/test/scripts/filters/backtick_code_block.js b/test/scripts/filters/backtick_code_block.js index 24557dc6ff..c2f77d1a5e 100644 --- a/test/scripts/filters/backtick_code_block.js +++ b/test/scripts/filters/backtick_code_block.js @@ -6,6 +6,7 @@ const defaultConfig = require('../../../lib/hexo/default_config'); describe('Backtick code block', () => { const Hexo = require('../../../lib/hexo'); const hexo = new Hexo(); + require('../../../lib/plugins/highlight/')(hexo); const codeBlock = require('../../../lib/plugins/filter/before_post_render/backtick_code_block')(hexo); const code = [ @@ -47,7 +48,7 @@ describe('Backtick code block', () => { const data = {content}; - hexo.extend.filter.store.highlight = []; + hexo.config.highlighter = ''; codeBlock(data); data.content.should.eql(content); }); @@ -75,8 +76,7 @@ describe('Backtick code block', () => { describe('highlightjs', () => { beforeEach(() => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); it('shorthand', () => { @@ -507,8 +507,7 @@ describe('Backtick code block', () => { describe('prismjs', () => { beforeEach(() => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/prism')(hexo)); + hexo.config.highlighter = 'prismjs'; }); it('default', () => { diff --git a/test/scripts/hexo/post.js b/test/scripts/hexo/post.js index e07ae4cfe9..3a0584eddf 100644 --- a/test/scripts/hexo/post.js +++ b/test/scripts/hexo/post.js @@ -12,6 +12,7 @@ const escapeSwigTag = str => str.replace(/{/g, '{').replace(/}/g, '}') describe('Post', () => { const Hexo = require('../../../lib/hexo'); const hexo = new Hexo(join(__dirname, 'post_test')); + require('../../../lib/plugins/highlight/')(hexo); const { post } = hexo; const now = Date.now(); let clock; @@ -903,8 +904,7 @@ describe('Post', () => { }); it('render() - shouln\'t break curly brackets', async () => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/prism')(hexo)); + hexo.config.highlighter = 'prismjs'; const content = [ '\\begin{equation}', @@ -920,8 +920,7 @@ describe('Post', () => { data.content.should.include('\\begin{equation}'); data.content.should.include('\\end{equation}'); - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); // #2321 @@ -1320,8 +1319,7 @@ describe('Post', () => { }); it('render() - issue #4460', async () => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/prism')(hexo)); + hexo.config.highlighter = 'prismjs'; const content = fixture.content_for_issue_4460; @@ -1332,13 +1330,11 @@ describe('Post', () => { data.content.should.not.include('hexoPostRenderEscape'); - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); it('render() - empty tag name', async () => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/prism')(hexo)); + hexo.config.highlighter = 'prismjs'; const content = 'Disable rendering of Nunjucks tag `{{ }}` / `{% %}`'; @@ -1350,7 +1346,6 @@ describe('Post', () => { data.content.should.include(escapeSwigTag('{{ }}')); data.content.should.include(escapeSwigTag('{% %}')); - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); }); diff --git a/test/scripts/tags/code.js b/test/scripts/tags/code.js index bb0d868c5c..4300dad6f9 100644 --- a/test/scripts/tags/code.js +++ b/test/scripts/tags/code.js @@ -6,6 +6,7 @@ const cheerio = require('cheerio'); describe('code', () => { const Hexo = require('../../../lib/hexo'); const hexo = new Hexo(); + require('../../../lib/plugins/highlight/')(hexo); const codeTag = require('../../../lib/plugins/tag/code')(hexo); const { escapeHTML } = util; @@ -33,8 +34,7 @@ describe('code', () => { describe('highlightjs', () => { beforeEach(() => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); it('default', () => { @@ -119,12 +119,12 @@ describe('code', () => { }); it('disabled', () => { - hexo.extend.filter.store.highlight = []; + hexo.config.highlighter = ''; const result = code('', fixture); result.should.eql('
' + escapeHTML(fixture) + '
'); - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); it('first_line', () => { @@ -190,8 +190,7 @@ describe('code', () => { describe('prismjs', () => { beforeEach(() => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/prism')(hexo)); + hexo.config.highlighter = 'prismjs'; }); it('default', () => { @@ -251,12 +250,12 @@ describe('code', () => { }); it('disabled', () => { - hexo.extend.filter.store.highlight = []; + hexo.config.highlighter = ''; const result = code('', fixture); result.should.eql('
' + escapeHTML(fixture) + '
'); - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; }); it('first_line', () => { diff --git a/test/scripts/tags/include_code.js b/test/scripts/tags/include_code.js index f39c228e38..170e63887c 100644 --- a/test/scripts/tags/include_code.js +++ b/test/scripts/tags/include_code.js @@ -8,6 +8,7 @@ const Promise = require('bluebird'); describe('include_code', () => { const Hexo = require('../../../lib/hexo'); const hexo = new Hexo(join(__dirname, 'include_code_test')); + require('../../../lib/plugins/highlight/')(hexo); const includeCode = Promise.method(require('../../../lib/plugins/tag/include_code')(hexo)); const path = join(hexo.source_dir, hexo.config.code_dir, 'test.js'); const defaultCfg = JSON.parse(JSON.stringify(hexo.config)); @@ -30,8 +31,7 @@ describe('include_code', () => { describe('highlightjs', () => { it('default', async () => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/highlight')(hexo)); + hexo.config.highlighter = 'highlight.js'; const expected = highlight(fixture, { lang: 'js', @@ -124,7 +124,7 @@ describe('include_code', () => { }); it('disabled', async () => { - hexo.extend.filter.store.highlight = []; + hexo.config.highlighter = ''; const result = await code('test.js'); result.should.eql('
' + fixture + '
'); @@ -133,8 +133,7 @@ describe('include_code', () => { describe('prismjs', () => { beforeEach(() => { - hexo.extend.filter.store.highlight = []; - hexo.extend.filter.register('highlight', require('../../../lib/plugins/filter/highlight/prism')(hexo)); + hexo.config.highlighter = 'prismjs'; }); it('default', async () => { @@ -213,7 +212,7 @@ describe('include_code', () => { }); it('disabled', async () => { - hexo.extend.filter.store.highlight = []; + hexo.config.highlighter = ''; const result = await code('test.js'); result.should.eql('
' + fixture + '
');