From 755803bdfde03be3216d46f0703195fb5a9e5aca Mon Sep 17 00:00:00 2001 From: SukkaW Date: Thu, 2 Jan 2020 23:42:10 +0800 Subject: [PATCH 01/12] feat(injector): bring up lib/extend/injector --- lib/extend/index.js | 1 + lib/extend/injector.js | 29 +++++++++++++++++++++++++++++ lib/hexo/index.js | 3 ++- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 lib/extend/injector.js diff --git a/lib/extend/index.js b/lib/extend/index.js index 3ad306245c..5e4eb37b28 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.Injector = require('./injector'); exports.Migrator = require('./migrator'); exports.Processor = require('./processor'); exports.Renderer = require('./renderer'); diff --git a/lib/extend/injector.js b/lib/extend/injector.js new file mode 100644 index 0000000000..51b3d28ab8 --- /dev/null +++ b/lib/extend/injector.js @@ -0,0 +1,29 @@ +'use strict'; + +class Injector { + constructor() { + this.store = { + head_start: new Set(), + head_end: new Set(), + body_begin: new Set(), + body_end: new Set() + }; + } + + list() { + return this.store; + } + + get(entry) { + return [...this.store[entry]]; + } + + register(entry, value) { + if (!entry) throw new TypeError('entry is required'); + if (typeof value === 'function') value = value(); + + this.store[entry].add(value); + } +} + +module.exports = Injector; diff --git a/lib/hexo/index.js b/lib/hexo/index.js index 18e7a89305..bad37ffa26 100644 --- a/lib/hexo/index.js +++ b/lib/hexo/index.js @@ -12,7 +12,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, Migrator, Processor, Renderer, Tag } = require('../extend'); +const { Console, Deployer, Filter, Generator, Helper, Injector, Migrator, Processor, Renderer, Tag } = require('../extend'); const Render = require('./render'); const registerModels = require('./register_models'); const Post = require('./post'); @@ -119,6 +119,7 @@ class Hexo { filter: new Filter(), generator: new Generator(), helper: new Helper(), + injector: new Injector(), migrator: new Migrator(), processor: new Processor(), renderer: new Renderer(), From 2da849c9afff02b70296d431fa8d731d5edd16b1 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Thu, 2 Jan 2020 23:55:13 +0800 Subject: [PATCH 02/12] test(injector): bring up extend/injector --- test/scripts/extend/injector.js | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/scripts/extend/injector.js diff --git a/test/scripts/extend/injector.js b/test/scripts/extend/injector.js new file mode 100644 index 0000000000..ab27945693 --- /dev/null +++ b/test/scripts/extend/injector.js @@ -0,0 +1,54 @@ +'use strict'; + +describe('Injector', () => { + const Injector = require('../../../lib/extend/injector'); + + it('register() - entry is required', () => { + const i = new Injector(); + + // no name + try { + i.register(); + } catch (err) { + err.should.be + .instanceOf(TypeError) + .property('message', 'entry is required'); + } + }); + + it('register() - string', () => { + const i = new Injector(); + + const str = ''; + i.register('head_start', str); + + i.get('head_start').should.contains(str); + }); + + it('register() - function', () => { + const i = new Injector(); + + const fn = () => ''; + i.register('head_start', fn); + + i.get('head_start').should.contains(fn()); + }); + + it('list()', () => { + const i = new Injector(); + + i.register('body_begin', ''); + + [...i.list().body_begin].should.not.be.empty; + }); + + it('get()', () => { + const i = new Injector(); + const str = ''; + + i.register('body_end', str); + + i.get('body_end').should.be.instanceOf(Array); + i.get('body_end').should.contains(str); + }); +}); From 06520fd9c734e04f1bfe93541661f49f8d5ea70a Mon Sep 17 00:00:00 2001 From: SukkaW Date: Fri, 3 Jan 2020 00:24:33 +0800 Subject: [PATCH 03/12] feat(injector): bring up filter --- lib/plugins/filter/after_render/index.js | 1 + lib/plugins/filter/after_render/injector.js | 73 +++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 lib/plugins/filter/after_render/injector.js diff --git a/lib/plugins/filter/after_render/index.js b/lib/plugins/filter/after_render/index.js index 655e4102e4..833dc83391 100644 --- a/lib/plugins/filter/after_render/index.js +++ b/lib/plugins/filter/after_render/index.js @@ -5,4 +5,5 @@ module.exports = ctx => { filter.register('after_route_render', require('./external_link')); filter.register('after_route_render', require('./meta_generator')); + filter.register('after_route_render', require('./injector')); }; diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js new file mode 100644 index 0000000000..9eeefe6541 --- /dev/null +++ b/lib/plugins/filter/after_render/injector.js @@ -0,0 +1,73 @@ +'use strict'; + +function injectFilter(data) { + const { inject: Inject } = this.extend; + + data = data.replace(/(?!<\/head>).+?<\/head>/s, str => { + // Inject head_begin + str.replace(//, headStartTag => { + if (str.includes('hexo injector head_begin')) return headStartTag; + + let code = ''; + for (const line of Inject.get('head_begin')) { + code += line; + } + + return headStartTag + + '' + + code + + ''; + }); + + // Inject head_end + str.replace('', headEndTag => { + if (str.includes('hexo injector head_end')) return headEndTag; + + let code = ''; + for (const line of Inject.get('head_end')) { + code += line; + } + + return '' + + code + + '' + + headEndTag; + }); + + return str; + }); + + // Inject body_begin + data = data.replace(//, bodyStartTag => { + if (data.includes('hexo injector body_begin')) return bodyStartTag; + + let code = ''; + for (const line of Inject.get('body_begin')) { + code += line; + } + + return bodyStartTag + + '' + + code + + ''; + }); + + // Inject body_end + data = data.replace('', bodyEndTag => { + if (data.includes('hexo injector body_end')) return bodyEndTag; + + let code = ''; + for (const line of Inject.get('body_end')) { + code += line; + } + + return '' + + code + + '' + + bodyEndTag; + }); + + return data; +} + +module.exports = injectFilter; From f5aeeb182d3f153ce914e78ef5328e0d3908eac0 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Fri, 3 Jan 2020 01:33:30 +0800 Subject: [PATCH 04/12] test(filter): bring up injectot test cases --- lib/extend/injector.js | 4 +- lib/plugins/filter/after_render/injector.js | 83 +++++++-------------- test/scripts/extend/index.js | 1 + test/scripts/extend/injector.js | 9 ++- test/scripts/filters/index.js | 1 + test/scripts/filters/injector.js | 83 +++++++++++++++++++++ 6 files changed, 121 insertions(+), 60 deletions(-) create mode 100644 test/scripts/filters/injector.js diff --git a/lib/extend/injector.js b/lib/extend/injector.js index 51b3d28ab8..f7d5b180db 100644 --- a/lib/extend/injector.js +++ b/lib/extend/injector.js @@ -3,7 +3,7 @@ class Injector { constructor() { this.store = { - head_start: new Set(), + head_begin: new Set(), head_end: new Set(), body_begin: new Set(), body_end: new Set() @@ -15,7 +15,7 @@ class Injector { } get(entry) { - return [...this.store[entry]]; + return Array.from(this.store[entry]); } register(entry, value) { diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index 9eeefe6541..df9f500bde 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -1,71 +1,46 @@ 'use strict'; function injectFilter(data) { - const { inject: Inject } = this.extend; + const { injector: _Injector } = this.extend; - data = data.replace(/(?!<\/head>).+?<\/head>/s, str => { - // Inject head_begin - str.replace(//, headStartTag => { - if (str.includes('hexo injector head_begin')) return headStartTag; + function injector(data, pattern, flag, isBegin = true) { + return data.replace(pattern, str => { + if (data.includes(`hexo injector ${flag}`)) return str; - let code = ''; - for (const line of Inject.get('head_begin')) { - code += line; - } + const arr = _Injector.get(flag); - return headStartTag - + '' - + code - + ''; - }); + if (arr.length) { + let code = ''; - // Inject head_end - str.replace('', headEndTag => { - if (str.includes('hexo injector head_end')) return headEndTag; + for (const line of arr) { + code += line; + } - let code = ''; - for (const line of Inject.get('head_end')) { - code += line; - } + if (isBegin) { + return str + + '' + + code + + ''; + } - return '' + return '' + code - + '' - + headEndTag; - }); + + '' + + str; + } - return str; - }); + return str; + }); + } + // Inject head_begin + data = injector(data, //, 'head_begin', true); + // Inject head_end + data = injector(data, '', 'head_end', false); // Inject body_begin - data = data.replace(//, bodyStartTag => { - if (data.includes('hexo injector body_begin')) return bodyStartTag; - - let code = ''; - for (const line of Inject.get('body_begin')) { - code += line; - } - - return bodyStartTag - + '' - + code - + ''; - }); - + data = injector(data, //, 'body_begin', true); // Inject body_end - data = data.replace('', bodyEndTag => { - if (data.includes('hexo injector body_end')) return bodyEndTag; - - let code = ''; - for (const line of Inject.get('body_end')) { - code += line; - } - - return '' - + code - + '' - + bodyEndTag; - }); + data = injector(data, '', 'body_end', false); return data; } diff --git a/test/scripts/extend/index.js b/test/scripts/extend/index.js index 0e06ccaa99..dbd1e467ef 100644 --- a/test/scripts/extend/index.js +++ b/test/scripts/extend/index.js @@ -6,6 +6,7 @@ describe('Extend', () => { require('./filter'); require('./generator'); require('./helper'); + require('./injector'); require('./migrator'); require('./processor'); require('./renderer'); diff --git a/test/scripts/extend/injector.js b/test/scripts/extend/injector.js index ab27945693..3d1f5850f3 100644 --- a/test/scripts/extend/injector.js +++ b/test/scripts/extend/injector.js @@ -20,18 +20,18 @@ describe('Injector', () => { const i = new Injector(); const str = ''; - i.register('head_start', str); + i.register('head_begin', str); - i.get('head_start').should.contains(str); + i.get('head_begin').should.contains(str); }); it('register() - function', () => { const i = new Injector(); const fn = () => ''; - i.register('head_start', fn); + i.register('head_begin', fn); - i.get('head_start').should.contains(fn()); + i.get('head_begin').should.contains(fn()); }); it('list()', () => { @@ -39,6 +39,7 @@ describe('Injector', () => { i.register('body_begin', ''); + i.list().body_begin.should.be.instanceOf(Set); [...i.list().body_begin].should.not.be.empty; }); diff --git a/test/scripts/filters/index.js b/test/scripts/filters/index.js index d899acf7b1..19b86b4ad3 100644 --- a/test/scripts/filters/index.js +++ b/test/scripts/filters/index.js @@ -5,6 +5,7 @@ describe('Filters', () => { require('./excerpt'); require('./external_link'); require('./i18n_locals'); + require('./injector'); require('./meta_generator'); require('./new_post_path'); require('./post_permalink'); diff --git a/test/scripts/filters/injector.js b/test/scripts/filters/injector.js new file mode 100644 index 0000000000..a4f95878c0 --- /dev/null +++ b/test/scripts/filters/injector.js @@ -0,0 +1,83 @@ +'use strict'; + +describe('Injector', () => { + const Hexo = require('../../../lib/hexo'); + const hexo = new Hexo(); + const injectorFilter = require('../../../lib/plugins/filter/after_render/injector').bind(hexo); + + const content = [ + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join(''); + + it('default', () => { + const result = injectorFilter(content); + result.should.contain('Test'); + result.should.contain('

'); + }); + + it('insert code', () => { + hexo.extend.injector.register('head_begin', ''); + hexo.extend.injector.register('head_end', ''); + hexo.extend.injector.register('head_end', ''); + hexo.extend.injector.register('body_begin', ''); + hexo.extend.injector.register('body_end', ''); + + const result = injectorFilter(content); + + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + }); + + it('no duplicate insert', () => { + const content = [ + '', + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join(''); + + const result = injectorFilter(content); + + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + }); + + it('multi-line head & body', () => { + const content = [ + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join('\n'); + + const result = injectorFilter(content); + + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + }); +}); From a3c60f9aef6ebddfb264fa9a052e0b9088b0ba7a Mon Sep 17 00:00:00 2001 From: SukkaW Date: Sun, 5 Jan 2020 21:16:00 +0800 Subject: [PATCH 05/12] feat(inject): add support for inject dest --- lib/extend/injector.js | 4 +- lib/plugins/filter/after_render/injector.js | 46 +++++++++++--- test/scripts/extend/injector.js | 6 +- test/scripts/filters/injector.js | 68 ++++++++++++++++++++- 4 files changed, 110 insertions(+), 14 deletions(-) diff --git a/lib/extend/injector.js b/lib/extend/injector.js index f7d5b180db..5c468f4176 100644 --- a/lib/extend/injector.js +++ b/lib/extend/injector.js @@ -18,11 +18,11 @@ class Injector { return Array.from(this.store[entry]); } - register(entry, value) { + register(entry, value, to = '') { if (!entry) throw new TypeError('entry is required'); if (typeof value === 'function') value = value(); - this.store[entry].add(value); + this.store[entry].add({ value, to }); } } diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index df9f500bde..97cc3e844c 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -1,20 +1,52 @@ 'use strict'; -function injectFilter(data) { +function injectFilter(data, locals = { page: {} }) { const { injector: _Injector } = this.extend; + const is = input => { + let result = true; + const { page } = locals; + + switch (input) { + case 'home': + result = Boolean(page.__index); + break; + + case 'post': + result = Boolean(page.__post); + break; + + case 'page': + result = Boolean(page.__page); + break; + + case 'archive': + result = Boolean(page.archive); + break; + + case 'category': + result = Boolean(page.category); + break; + + case 'tag': + result = Boolean(page.tag); + break; + + default: + result = true; + } + + return result; + }; + function injector(data, pattern, flag, isBegin = true) { return data.replace(pattern, str => { if (data.includes(`hexo injector ${flag}`)) return str; - const arr = _Injector.get(flag); + const arr = _Injector.get(flag).filter(i => is(i.to)).map(i => i.value); if (arr.length) { - let code = ''; - - for (const line of arr) { - code += line; - } + const code = arr.reduce((a, c) => a + c, ''); if (isBegin) { return str diff --git a/test/scripts/extend/injector.js b/test/scripts/extend/injector.js index 3d1f5850f3..b42ab407b6 100644 --- a/test/scripts/extend/injector.js +++ b/test/scripts/extend/injector.js @@ -22,7 +22,7 @@ describe('Injector', () => { const str = ''; i.register('head_begin', str); - i.get('head_begin').should.contains(str); + i.get('head_begin')[0].value.should.contains(str); }); it('register() - function', () => { @@ -31,7 +31,7 @@ describe('Injector', () => { const fn = () => ''; i.register('head_begin', fn); - i.get('head_begin').should.contains(fn()); + i.get('head_begin')[0].value.should.contains(fn()); }); it('list()', () => { @@ -50,6 +50,6 @@ describe('Injector', () => { i.register('body_end', str); i.get('body_end').should.be.instanceOf(Array); - i.get('body_end').should.contains(str); + i.get('body_end')[0].value.should.contains(str); }); }); diff --git a/test/scripts/filters/injector.js b/test/scripts/filters/injector.js index a4f95878c0..c8af74b077 100644 --- a/test/scripts/filters/injector.js +++ b/test/scripts/filters/injector.js @@ -2,8 +2,12 @@ describe('Injector', () => { const Hexo = require('../../../lib/hexo'); - const hexo = new Hexo(); - const injectorFilter = require('../../../lib/plugins/filter/after_render/injector').bind(hexo); + let hexo, injectorFilter; + + beforeEach(() => { + hexo = new Hexo(); + injectorFilter = require('../../../lib/plugins/filter/after_render/injector').bind(hexo); + }); const content = [ '', @@ -52,6 +56,12 @@ describe('Injector', () => { '' ].join(''); + hexo.extend.injector.register('head_begin', ''); + hexo.extend.injector.register('head_end', ''); + hexo.extend.injector.register('head_end', ''); + hexo.extend.injector.register('body_begin', ''); + hexo.extend.injector.register('body_end', ''); + const result = injectorFilter(content); result.should.contain(''); @@ -73,6 +83,12 @@ describe('Injector', () => { '' ].join('\n'); + hexo.extend.injector.register('head_begin', ''); + hexo.extend.injector.register('head_end', ''); + hexo.extend.injector.register('head_end', ''); + hexo.extend.injector.register('body_begin', ''); + hexo.extend.injector.register('body_end', ''); + const result = injectorFilter(content); result.should.contain(''); @@ -80,4 +96,52 @@ describe('Injector', () => { result.should.contain(''); result.should.contain(''); }); + + it('inject on specific page', () => { + const content = [ + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join('\n'); + + hexo.extend.injector.register('head_begin', '', 'home'); + hexo.extend.injector.register('head_begin', '', 'post'); + hexo.extend.injector.register('head_begin', '', 'page'); + hexo.extend.injector.register('head_begin', '', 'archive'); + hexo.extend.injector.register('head_begin', '', 'category'); + hexo.extend.injector.register('head_begin', '', 'tag'); + + const result1 = injectorFilter(content, { page: {} }); + const result2 = injectorFilter(content, { page: { __index: true } }); + const result3 = injectorFilter(content, { page: { __post: true } }); + const result4 = injectorFilter(content, { page: { __page: true } }); + const result5 = injectorFilter(content, { page: { archive: true } }); + const result6 = injectorFilter(content, { page: { category: true } }); + const result7 = injectorFilter(content, { page: { tag: true } }); + + // home + result1.should.not.contain(''); + result2.should.contain(''); + // post + result1.should.not.contain(''); + result3.should.contain(''); + // page + result1.should.not.contain(''); + result4.should.contain(''); + // archive + result1.should.not.contain(''); + result5.should.contain(''); + // category + result1.should.not.contain(''); + result6.should.contain(''); + // tag + result1.should.not.contain(''); + result7.should.contain(''); + }); }); From b4a9837373c4f8d46742a19f4c97a1c997d273f2 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Sun, 5 Jan 2020 22:49:05 +0800 Subject: [PATCH 06/12] feat: return before data.replace if no inject --- lib/plugins/filter/after_render/injector.js | 28 ++++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index 97cc3e844c..477f344dad 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -40,28 +40,26 @@ function injectFilter(data, locals = { page: {} }) { }; function injector(data, pattern, flag, isBegin = true) { - return data.replace(pattern, str => { - if (data.includes(`hexo injector ${flag}`)) return str; + if (data.includes(`hexo injector ${flag}`)) return data; - const arr = _Injector.get(flag).filter(i => is(i.to)).map(i => i.value); + const arr = _Injector.get(flag).filter(i => is(i.to)).map(i => i.value); - if (arr.length) { - const code = arr.reduce((a, c) => a + c, ''); + if (!arr.length) return data; - if (isBegin) { - return str - + '' - + code - + ''; - } + return data.replace(pattern, str => { + const code = arr.reduce((a, c) => a + c, ''); - return '' + if (isBegin) { + return str + + '' + code - + '' - + str; + + ''; } - return str; + return '' + + code + + '' + + str; }); } From f5a44296620309b100ef88b40edd7a426a716fd7 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Mon, 6 Jan 2020 03:52:34 +0800 Subject: [PATCH 07/12] feat(injector): utilize cache --- lib/extend/injector.js | 2 +- lib/plugins/filter/after_render/injector.js | 53 ++++++++------------- package.json | 1 + test/scripts/filters/injector.js | 3 ++ 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/lib/extend/injector.js b/lib/extend/injector.js index 5c468f4176..34effb37d2 100644 --- a/lib/extend/injector.js +++ b/lib/extend/injector.js @@ -18,7 +18,7 @@ class Injector { return Array.from(this.store[entry]); } - register(entry, value, to = '') { + register(entry, value, to = 'default') { if (!entry) throw new TypeError('entry is required'); if (typeof value === 'function') value = value(); diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index 477f344dad..014e4f0154 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -1,53 +1,38 @@ 'use strict'; +const { Cache } = require('hexo-util'); +const cache = new Cache(); + function injectFilter(data, locals = { page: {} }) { const { injector: _Injector } = this.extend; - const is = input => { - let result = true; + const current = () => { const { page } = locals; - switch (input) { - case 'home': - result = Boolean(page.__index); - break; - - case 'post': - result = Boolean(page.__post); - break; - - case 'page': - result = Boolean(page.__page); - break; - - case 'archive': - result = Boolean(page.archive); - break; - - case 'category': - result = Boolean(page.category); - break; - - case 'tag': - result = Boolean(page.tag); - break; - - default: - result = true; - } - - return result; + if (page.__index) return 'home'; + if (page.__post) return 'post'; + if (page.__page) return 'page'; + if (page.archive) return 'archive'; + if (page.category) return 'category'; + if (page.tag) return 'tag'; + return 'default'; }; function injector(data, pattern, flag, isBegin = true) { if (data.includes(`hexo injector ${flag}`)) return data; - const arr = _Injector.get(flag).filter(i => is(i.to)).map(i => i.value); + const arr = cache.apply( + `${flag}-${current()}-arr`, + _Injector.get(flag).filter(i => i.to === current()).map(i => i.value) + ); if (!arr.length) return data; return data.replace(pattern, str => { - const code = arr.reduce((a, c) => a + c, ''); + const code = cache.apply( + `${flag}-${current()}-code`, + () => arr.reduce((a, c) => a + c, '') + ); if (isBegin) { return str diff --git a/package.json b/package.json index 6ea886e2a8..d3efe97dc4 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "lint-staged": "^9.1.0", "mocha": "^6.0.0", "nyc": "^15.0.0", + "resnap": "^1.0.1", "rewire": "^4.0.1", "sinon": "^8.0.1" }, diff --git a/test/scripts/filters/injector.js b/test/scripts/filters/injector.js index c8af74b077..590e45b723 100644 --- a/test/scripts/filters/injector.js +++ b/test/scripts/filters/injector.js @@ -1,11 +1,14 @@ 'use strict'; +const resetCache = require('resnap')(); + describe('Injector', () => { const Hexo = require('../../../lib/hexo'); let hexo, injectorFilter; beforeEach(() => { hexo = new Hexo(); + resetCache(); injectorFilter = require('../../../lib/plugins/filter/after_render/injector').bind(hexo); }); From 6695d7888488aa6f4e3c89b31c270b1f21e7924c Mon Sep 17 00:00:00 2001 From: SukkaW Date: Tue, 7 Jan 2020 14:56:39 +0800 Subject: [PATCH 08/12] refactor(injector): use new data structure Apply suggestions from code review by @dailyrandomphoto --- lib/extend/injector.js | 23 +++++++---- lib/plugins/filter/after_render/injector.js | 19 ++++----- test/scripts/extend/injector.js | 43 +++++++++++++++++---- test/scripts/filters/injector.js | 25 ++++++------ 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/lib/extend/injector.js b/lib/extend/injector.js index 34effb37d2..116e39cbff 100644 --- a/lib/extend/injector.js +++ b/lib/extend/injector.js @@ -3,10 +3,10 @@ class Injector { constructor() { this.store = { - head_begin: new Set(), - head_end: new Set(), - body_begin: new Set(), - body_end: new Set() + head_begin: {}, + head_end: {}, + body_begin: {}, + body_end: {} }; } @@ -14,15 +14,24 @@ class Injector { return this.store; } - get(entry) { - return Array.from(this.store[entry]); + get(entry, to = 'default') { + return Array.from(this.store[entry][to] || []); + } + + getText(entry, to = 'default') { + const arr = this.get(entry, to); + if (!arr || !arr.length) return ''; + return arr.join(''); } register(entry, value, to = 'default') { if (!entry) throw new TypeError('entry is required'); if (typeof value === 'function') value = value(); - this.store[entry].add({ value, to }); + const entryMap = this.store[entry] || this.store.head_end; + const valueSet = entryMap[to] || new Set(); + valueSet.add(value); + entryMap[to] = valueSet; } } diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index 014e4f0154..f5a0c1851c 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -4,7 +4,7 @@ const { Cache } = require('hexo-util'); const cache = new Cache(); function injectFilter(data, locals = { page: {} }) { - const { injector: _Injector } = this.extend; + const Injector = this.extend.injector; const current = () => { const { page } = locals; @@ -21,19 +21,16 @@ function injectFilter(data, locals = { page: {} }) { function injector(data, pattern, flag, isBegin = true) { if (data.includes(`hexo injector ${flag}`)) return data; - const arr = cache.apply( - `${flag}-${current()}-arr`, - _Injector.get(flag).filter(i => i.to === current()).map(i => i.value) - ); + const code = cache.apply(`${flag}-${current()}-code`, () => { + const currentType = current(); - if (!arr.length) return data; + if (currentType === 'default') return Injector.getText(flag, 'default'); + return Injector.getText(flag, currentType) + Injector.getText(flag, 'default'); + }); - return data.replace(pattern, str => { - const code = cache.apply( - `${flag}-${current()}-code`, - () => arr.reduce((a, c) => a + c, '') - ); + if (!code.length) return data; + return data.replace(pattern, str => { if (isBegin) { return str + '' diff --git a/test/scripts/extend/injector.js b/test/scripts/extend/injector.js index b42ab407b6..3b471b986f 100644 --- a/test/scripts/extend/injector.js +++ b/test/scripts/extend/injector.js @@ -21,8 +21,11 @@ describe('Injector', () => { const str = ''; i.register('head_begin', str); + i.register('head_end', str, 'home'); - i.get('head_begin')[0].value.should.contains(str); + i.get('head_begin').should.contains(str); + i.get('head_begin', 'default').should.contains(str); + i.get('head_end', 'home').should.contains(str); }); it('register() - function', () => { @@ -31,7 +34,16 @@ describe('Injector', () => { const fn = () => ''; i.register('head_begin', fn); - i.get('head_begin')[0].value.should.contains(fn()); + i.get('head_begin').should.contains(fn()); + }); + + it('register() - fallback when entry not exists', () => { + const i = new Injector(); + + const str = ''; + i.register('foo', str); + + i.get('head_end').should.contains(str); }); it('list()', () => { @@ -39,17 +51,34 @@ describe('Injector', () => { i.register('body_begin', ''); - i.list().body_begin.should.be.instanceOf(Set); - [...i.list().body_begin].should.not.be.empty; + i.list().body_begin.default.should.be.instanceOf(Set); + [...i.list().body_begin.default].should.not.be.empty; }); it('get()', () => { const i = new Injector(); const str = ''; - i.register('body_end', str); + i.register('body_begin', str); + i.register('body_end', str, 'home'); + + i.get('body_begin').should.be.instanceOf(Array); + i.get('body_begin').should.contains(str); + i.get('body_end', 'home').should.be.instanceOf(Array); + i.get('body_end', 'home').should.contains(str); + + i.get('head_end').should.be.instanceOf(Array); + i.get('head_end').should.eql([]); + }); + + it('getText()', () => { + const i = new Injector(); + const str = ''; + + i.register('head_end', str); + i.register('body_end', str, 'home'); - i.get('body_end').should.be.instanceOf(Array); - i.get('body_end')[0].value.should.contains(str); + i.getText('body_end', 'home').should.eql(str); + i.getText('body_end').should.eql(''); }); }); diff --git a/test/scripts/filters/injector.js b/test/scripts/filters/injector.js index 590e45b723..59a9c88bf6 100644 --- a/test/scripts/filters/injector.js +++ b/test/scripts/filters/injector.js @@ -113,6 +113,7 @@ describe('Injector', () => { '' ].join('\n'); + hexo.extend.injector.register('head_begin', ''); hexo.extend.injector.register('head_begin', '', 'home'); hexo.extend.injector.register('head_begin', '', 'post'); hexo.extend.injector.register('head_begin', '', 'page'); @@ -129,22 +130,22 @@ describe('Injector', () => { const result7 = injectorFilter(content, { page: { tag: true } }); // home - result1.should.not.contain(''); - result2.should.contain(''); + result1.should.not.contain(''); + result2.should.contain(''); // post - result1.should.not.contain(''); - result3.should.contain(''); + result1.should.not.contain(''); + result3.should.contain(''); // page - result1.should.not.contain(''); - result4.should.contain(''); + result1.should.not.contain(''); + result4.should.contain(''); // archive - result1.should.not.contain(''); - result5.should.contain(''); + result1.should.not.contain(''); + result5.should.contain(''); // category - result1.should.not.contain(''); - result6.should.contain(''); + result1.should.not.contain(''); + result6.should.contain(''); // tag - result1.should.not.contain(''); - result7.should.contain(''); + result1.should.not.contain(''); + result7.should.contain(''); }); }); From 38ebdc36edc1510b548bfd14fcae0e3ff5dd6ccc Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 8 Jan 2020 00:20:00 +0800 Subject: [PATCH 09/12] feat(injector): support page.layout --- lib/plugins/filter/after_render/injector.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index f5a0c1851c..aa9c4ea7ad 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -15,6 +15,7 @@ function injectFilter(data, locals = { page: {} }) { if (page.archive) return 'archive'; if (page.category) return 'category'; if (page.tag) return 'tag'; + if (page.layout) return page.layout; return 'default'; }; From 789614d488d655f072d655373e188686f4757183 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 8 Jan 2020 00:31:38 +0800 Subject: [PATCH 10/12] refactor(injector): simplify the filter Apply code suggestions from code review by @dailyrandomphoto --- lib/plugins/filter/after_render/injector.js | 25 +++++++-------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/filter/after_render/injector.js index aa9c4ea7ad..7dc8583a92 100644 --- a/lib/plugins/filter/after_render/injector.js +++ b/lib/plugins/filter/after_render/injector.js @@ -22,28 +22,19 @@ function injectFilter(data, locals = { page: {} }) { function injector(data, pattern, flag, isBegin = true) { if (data.includes(`hexo injector ${flag}`)) return data; - const code = cache.apply(`${flag}-${current()}-code`, () => { - const currentType = current(); + const currentType = current(); + const code = cache.apply(`${flag}-${currentType}-code`, () => { + const content = currentType === 'default' ? Injector.getText(flag, 'default') : Injector.getText(flag, currentType) + Injector.getText(flag, 'default'); - if (currentType === 'default') return Injector.getText(flag, 'default'); - return Injector.getText(flag, currentType) + Injector.getText(flag, 'default'); + if (!content.length) return ''; + + return '' + content + ''; }); + // avoid unnesscary replace() for better performance if (!code.length) return data; - return data.replace(pattern, str => { - if (isBegin) { - return str - + '' - + code - + ''; - } - - return '' - + code - + '' - + str; - }); + return data.replace(pattern, str => { return isBegin ? str + code : code + str; }); } // Inject head_begin From 18421ce0c4398f5f0798b920bf0d912502e56ef3 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 8 Jan 2020 04:16:27 +0800 Subject: [PATCH 11/12] refactor(injector): split injector from filter Make sure injector is executed before after_route_render --- lib/hexo/index.js | 5 +++-- lib/plugins/filter/after_render/index.js | 1 - .../after_render/injector.js => injector/index.js} | 0 package.json | 2 +- test/index.js | 1 + test/scripts/filters/index.js | 1 - test/scripts/{filters/injector.js => injector/index.js} | 8 ++++---- 7 files changed, 9 insertions(+), 9 deletions(-) rename lib/plugins/{filter/after_render/injector.js => injector/index.js} (100%) rename test/scripts/{filters/injector.js => injector/index.js} (97%) diff --git a/lib/hexo/index.js b/lib/hexo/index.js index bad37ffa26..7e442f4ad9 100644 --- a/lib/hexo/index.js +++ b/lib/hexo/index.js @@ -25,9 +25,9 @@ const defaultConfig = require('./default_config'); const loadDatabase = require('./load_database'); const multiConfigPath = require('./multi_config_path'); const { sync } = require('resolve'); -const full_url_for = require('../plugins/helper/full_url_for'); +const injectorFilter = require('../plugins/injector'); const { inherits } = require('util'); -const { deepMerge } = require('hexo-util'); +const { deepMerge, full_url_for } = require('hexo-util'); const libDir = dirname(__dirname); const dbVersion = 1; @@ -57,6 +57,7 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) { if (view) { log.debug(`Rendering HTML ${name}: ${magenta(path)}`); return view.render(locals) + .then(result => injectorFilter.call(ctx, result, locals)) .then(result => ctx.execFilter('after_route_render', result, { context: ctx, args: [locals] diff --git a/lib/plugins/filter/after_render/index.js b/lib/plugins/filter/after_render/index.js index 833dc83391..655e4102e4 100644 --- a/lib/plugins/filter/after_render/index.js +++ b/lib/plugins/filter/after_render/index.js @@ -5,5 +5,4 @@ module.exports = ctx => { filter.register('after_route_render', require('./external_link')); filter.register('after_route_render', require('./meta_generator')); - filter.register('after_route_render', require('./injector')); }; diff --git a/lib/plugins/filter/after_render/injector.js b/lib/plugins/injector/index.js similarity index 100% rename from lib/plugins/filter/after_render/injector.js rename to lib/plugins/injector/index.js diff --git a/package.json b/package.json index d3efe97dc4..6efe4fd042 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "cheerio": "0.22.0", + "decache": "^4.5.1", "eslint": "^6.0.1", "eslint-config-hexo": "^4.1.0", "hexo-renderer-marked": "^2.0.0", @@ -78,7 +79,6 @@ "lint-staged": "^9.1.0", "mocha": "^6.0.0", "nyc": "^15.0.0", - "resnap": "^1.0.1", "rewire": "^4.0.1", "sinon": "^8.0.1" }, diff --git a/test/index.js b/test/index.js index 68b8655b91..6210636470 100644 --- a/test/index.js +++ b/test/index.js @@ -10,6 +10,7 @@ describe('Hexo', () => { require('./scripts/generators'); require('./scripts/helpers'); require('./scripts/hexo'); + require('./scripts/injector'); require('./scripts/models'); require('./scripts/processors'); require('./scripts/renderers'); diff --git a/test/scripts/filters/index.js b/test/scripts/filters/index.js index 19b86b4ad3..d899acf7b1 100644 --- a/test/scripts/filters/index.js +++ b/test/scripts/filters/index.js @@ -5,7 +5,6 @@ describe('Filters', () => { require('./excerpt'); require('./external_link'); require('./i18n_locals'); - require('./injector'); require('./meta_generator'); require('./new_post_path'); require('./post_permalink'); diff --git a/test/scripts/filters/injector.js b/test/scripts/injector/index.js similarity index 97% rename from test/scripts/filters/injector.js rename to test/scripts/injector/index.js index 59a9c88bf6..d5e62a4286 100644 --- a/test/scripts/filters/injector.js +++ b/test/scripts/injector/index.js @@ -1,15 +1,15 @@ 'use strict'; -const resetCache = require('resnap')(); +const decache = require('decache'); describe('Injector', () => { const Hexo = require('../../../lib/hexo'); let hexo, injectorFilter; - beforeEach(() => { + beforeEach(async () => { + await decache('../../../lib/plugins/injector'); hexo = new Hexo(); - resetCache(); - injectorFilter = require('../../../lib/plugins/filter/after_render/injector').bind(hexo); + injectorFilter = require('../../../lib/plugins/injector').bind(hexo); }); const content = [ From 8cdaf0b756662ca425fd2bce64ad364ca9e9f55e Mon Sep 17 00:00:00 2001 From: SukkaW Date: Fri, 31 Jan 2020 22:41:07 +0800 Subject: [PATCH 12/12] refactor(injector): add exec() method - Remove injectorFilter from plugin dir - Move cache into Injector Class - Remove decache --- lib/extend/injector.js | 43 +++++++++ lib/hexo/index.js | 4 +- lib/plugins/injector/index.js | 54 +---------- package.json | 1 - test/index.js | 1 - test/scripts/extend/injector.js | 153 ++++++++++++++++++++++++++++++++ test/scripts/injector/index.js | 151 ------------------------------- 7 files changed, 202 insertions(+), 205 deletions(-) delete mode 100644 test/scripts/injector/index.js diff --git a/lib/extend/injector.js b/lib/extend/injector.js index 116e39cbff..ed25e1041c 100644 --- a/lib/extend/injector.js +++ b/lib/extend/injector.js @@ -1,5 +1,7 @@ 'use strict'; +const { Cache } = require('hexo-util'); + class Injector { constructor() { this.store = { @@ -8,6 +10,8 @@ class Injector { body_begin: {}, body_end: {} }; + + this.cache = new Cache(); } list() { @@ -33,6 +37,45 @@ class Injector { valueSet.add(value); entryMap[to] = valueSet; } + + exec(data, locals = { page: {} }) { + let currentType = 'default'; + const { page } = locals; + + if (page.__index) currentType = 'home'; + if (page.__post) currentType = 'post'; + if (page.__page) currentType = 'page'; + if (page.archive) currentType = 'archive'; + if (page.category) currentType = 'category'; + if (page.tag) currentType = 'tag'; + if (page.layout) currentType = page.layout; + + const injector = (data, pattern, flag, isBegin = true) => { + if (data.includes(`hexo injector ${flag}`)) return data; + + const code = this.cache.apply(`${flag}-${currentType}-code`, () => { + const content = currentType === 'default' ? this.getText(flag, 'default') : this.getText(flag, currentType) + this.getText(flag, 'default'); + + if (!content.length) return ''; + return '' + content + ''; + }); + + // avoid unnesscary replace() for better performance + if (!code.length) return data; + return data.replace(pattern, str => { return isBegin ? str + code : code + str; }); + }; + + // Inject head_begin + data = injector(data, //, 'head_begin', true); + // Inject head_end + data = injector(data, '', 'head_end', false); + // Inject body_begin + data = injector(data, //, 'body_begin', true); + // Inject body_end + data = injector(data, '', 'body_end', false); + + return data; + } } module.exports = Injector; diff --git a/lib/hexo/index.js b/lib/hexo/index.js index 7e442f4ad9..05a2098619 100644 --- a/lib/hexo/index.js +++ b/lib/hexo/index.js @@ -25,7 +25,6 @@ const defaultConfig = require('./default_config'); const loadDatabase = require('./load_database'); const multiConfigPath = require('./multi_config_path'); const { sync } = require('resolve'); -const injectorFilter = require('../plugins/injector'); const { inherits } = require('util'); const { deepMerge, full_url_for } = require('hexo-util'); @@ -57,7 +56,7 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) { if (view) { log.debug(`Rendering HTML ${name}: ${magenta(path)}`); return view.render(locals) - .then(result => injectorFilter.call(ctx, result, locals)) + .then(result => ctx.extend.injector.exec(result, locals)) .then(result => ctx.execFilter('after_route_render', result, { context: ctx, args: [locals] @@ -225,6 +224,7 @@ class Hexo { require('../plugins/filter')(this); require('../plugins/generator')(this); require('../plugins/helper')(this); + require('../plugins/injector')(this); require('../plugins/processor')(this); require('../plugins/renderer')(this); require('../plugins/tag')(this); diff --git a/lib/plugins/injector/index.js b/lib/plugins/injector/index.js index 7dc8583a92..be1a9aaca9 100644 --- a/lib/plugins/injector/index.js +++ b/lib/plugins/injector/index.js @@ -1,52 +1,6 @@ 'use strict'; -const { Cache } = require('hexo-util'); -const cache = new Cache(); - -function injectFilter(data, locals = { page: {} }) { - const Injector = this.extend.injector; - - const current = () => { - const { page } = locals; - - if (page.__index) return 'home'; - if (page.__post) return 'post'; - if (page.__page) return 'page'; - if (page.archive) return 'archive'; - if (page.category) return 'category'; - if (page.tag) return 'tag'; - if (page.layout) return page.layout; - return 'default'; - }; - - function injector(data, pattern, flag, isBegin = true) { - if (data.includes(`hexo injector ${flag}`)) return data; - - const currentType = current(); - const code = cache.apply(`${flag}-${currentType}-code`, () => { - const content = currentType === 'default' ? Injector.getText(flag, 'default') : Injector.getText(flag, currentType) + Injector.getText(flag, 'default'); - - if (!content.length) return ''; - - return '' + content + ''; - }); - - // avoid unnesscary replace() for better performance - if (!code.length) return data; - - return data.replace(pattern, str => { return isBegin ? str + code : code + str; }); - } - - // Inject head_begin - data = injector(data, //, 'head_begin', true); - // Inject head_end - data = injector(data, '', 'head_end', false); - // Inject body_begin - data = injector(data, //, 'body_begin', true); - // Inject body_end - data = injector(data, '', 'body_end', false); - - return data; -} - -module.exports = injectFilter; +module.exports = ctx => { + // eslint-disable-next-line no-unused-vars + const { injector } = ctx.extend; +}; diff --git a/package.json b/package.json index 6efe4fd042..6ea886e2a8 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "cheerio": "0.22.0", - "decache": "^4.5.1", "eslint": "^6.0.1", "eslint-config-hexo": "^4.1.0", "hexo-renderer-marked": "^2.0.0", diff --git a/test/index.js b/test/index.js index 6210636470..68b8655b91 100644 --- a/test/index.js +++ b/test/index.js @@ -10,7 +10,6 @@ describe('Hexo', () => { require('./scripts/generators'); require('./scripts/helpers'); require('./scripts/hexo'); - require('./scripts/injector'); require('./scripts/models'); require('./scripts/processors'); require('./scripts/renderers'); diff --git a/test/scripts/extend/injector.js b/test/scripts/extend/injector.js index 3b471b986f..900c331f8f 100644 --- a/test/scripts/extend/injector.js +++ b/test/scripts/extend/injector.js @@ -1,6 +1,18 @@ 'use strict'; describe('Injector', () => { + const content = [ + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join(''); + const Injector = require('../../../lib/extend/injector'); it('register() - entry is required', () => { @@ -81,4 +93,145 @@ describe('Injector', () => { i.getText('body_end', 'home').should.eql(str); i.getText('body_end').should.eql(''); }); + + it('exec() - default', () => { + const i = new Injector(); + const result = i.exec(content); + result.should.contain('Test'); + result.should.contain('

'); + }); + + it('exec() - default', () => { + const i = new Injector(); + const result = i.exec(content); + result.should.contain('Test'); + result.should.contain('

'); + }); + + it('exec() - insert code', () => { + const i = new Injector(); + + i.register('head_begin', ''); + i.register('head_end', ''); + i.register('head_end', ''); + i.register('body_begin', ''); + i.register('body_end', ''); + + const result = i.exec(content); + + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + }); + + it('exec() - no duplicate insert', () => { + const content = [ + '', + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join(''); + + const i = new Injector(); + + i.register('head_begin', ''); + i.register('head_end', ''); + i.register('head_end', ''); + i.register('body_begin', ''); + i.register('body_end', ''); + + const result = i.exec(content); + + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + }); + + it('exec() - multi-line head & body', () => { + const content = [ + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join('\n'); + + const i = new Injector(); + + i.register('head_begin', ''); + i.register('head_end', ''); + i.register('head_end', ''); + i.register('body_begin', ''); + i.register('body_end', ''); + + const result = i.exec(content); + + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + result.should.contain(''); + }); + + it('exec() - inject on specific page', () => { + const content = [ + '', + '', + 'Test', + '', + '', + '
', + '

', + '', + '' + ].join('\n'); + + const i = new Injector(); + + i.register('head_begin', ''); + i.register('head_begin', '', 'home'); + i.register('head_begin', '', 'post'); + i.register('head_begin', '', 'page'); + i.register('head_begin', '', 'archive'); + i.register('head_begin', '', 'category'); + i.register('head_begin', '', 'tag'); + + const result1 = i.exec(content, { page: {} }); + const result2 = i.exec(content, { page: { __index: true } }); + const result3 = i.exec(content, { page: { __post: true } }); + const result4 = i.exec(content, { page: { __page: true } }); + const result5 = i.exec(content, { page: { archive: true } }); + const result6 = i.exec(content, { page: { category: true } }); + const result7 = i.exec(content, { page: { tag: true } }); + + // home + result1.should.not.contain(''); + result2.should.contain(''); + // post + result1.should.not.contain(''); + result3.should.contain(''); + // page + result1.should.not.contain(''); + result4.should.contain(''); + // archive + result1.should.not.contain(''); + result5.should.contain(''); + // category + result1.should.not.contain(''); + result6.should.contain(''); + // tag + result1.should.not.contain(''); + result7.should.contain(''); + }); }); diff --git a/test/scripts/injector/index.js b/test/scripts/injector/index.js deleted file mode 100644 index d5e62a4286..0000000000 --- a/test/scripts/injector/index.js +++ /dev/null @@ -1,151 +0,0 @@ -'use strict'; - -const decache = require('decache'); - -describe('Injector', () => { - const Hexo = require('../../../lib/hexo'); - let hexo, injectorFilter; - - beforeEach(async () => { - await decache('../../../lib/plugins/injector'); - hexo = new Hexo(); - injectorFilter = require('../../../lib/plugins/injector').bind(hexo); - }); - - const content = [ - '', - '', - 'Test', - '', - '', - '
', - '

', - '', - '' - ].join(''); - - it('default', () => { - const result = injectorFilter(content); - result.should.contain('Test'); - result.should.contain('

'); - }); - - it('insert code', () => { - hexo.extend.injector.register('head_begin', ''); - hexo.extend.injector.register('head_end', ''); - hexo.extend.injector.register('head_end', ''); - hexo.extend.injector.register('body_begin', ''); - hexo.extend.injector.register('body_end', ''); - - const result = injectorFilter(content); - - result.should.contain(''); - result.should.contain(''); - result.should.contain(''); - result.should.contain(''); - }); - - it('no duplicate insert', () => { - const content = [ - '', - '', - '', - 'Test', - '', - '', - '
', - '

', - '', - '' - ].join(''); - - hexo.extend.injector.register('head_begin', ''); - hexo.extend.injector.register('head_end', ''); - hexo.extend.injector.register('head_end', ''); - hexo.extend.injector.register('body_begin', ''); - hexo.extend.injector.register('body_end', ''); - - const result = injectorFilter(content); - - result.should.contain(''); - result.should.contain(''); - result.should.contain(''); - result.should.contain(''); - }); - - it('multi-line head & body', () => { - const content = [ - '', - '', - 'Test', - '', - '', - '
', - '

', - '', - '' - ].join('\n'); - - hexo.extend.injector.register('head_begin', ''); - hexo.extend.injector.register('head_end', ''); - hexo.extend.injector.register('head_end', ''); - hexo.extend.injector.register('body_begin', ''); - hexo.extend.injector.register('body_end', ''); - - const result = injectorFilter(content); - - result.should.contain(''); - result.should.contain(''); - result.should.contain(''); - result.should.contain(''); - }); - - it('inject on specific page', () => { - const content = [ - '', - '', - 'Test', - '', - '', - '
', - '

', - '', - '' - ].join('\n'); - - hexo.extend.injector.register('head_begin', ''); - hexo.extend.injector.register('head_begin', '', 'home'); - hexo.extend.injector.register('head_begin', '', 'post'); - hexo.extend.injector.register('head_begin', '', 'page'); - hexo.extend.injector.register('head_begin', '', 'archive'); - hexo.extend.injector.register('head_begin', '', 'category'); - hexo.extend.injector.register('head_begin', '', 'tag'); - - const result1 = injectorFilter(content, { page: {} }); - const result2 = injectorFilter(content, { page: { __index: true } }); - const result3 = injectorFilter(content, { page: { __post: true } }); - const result4 = injectorFilter(content, { page: { __page: true } }); - const result5 = injectorFilter(content, { page: { archive: true } }); - const result6 = injectorFilter(content, { page: { category: true } }); - const result7 = injectorFilter(content, { page: { tag: true } }); - - // home - result1.should.not.contain(''); - result2.should.contain(''); - // post - result1.should.not.contain(''); - result3.should.contain(''); - // page - result1.should.not.contain(''); - result4.should.contain(''); - // archive - result1.should.not.contain(''); - result5.should.contain(''); - // category - result1.should.not.contain(''); - result6.should.contain(''); - // tag - result1.should.not.contain(''); - result7.should.contain(''); - }); -});