injector.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. 'use strict';
  2. const { Cache } = require('hexo-util');
  3. class Injector {
  4. constructor() {
  5. this.store = {
  6. head_begin: {},
  7. head_end: {},
  8. body_begin: {},
  9. body_end: {}
  10. };
  11. this.cache = new Cache();
  12. }
  13. list() {
  14. return this.store;
  15. }
  16. get(entry, to = 'default') {
  17. return Array.from(this.store[entry][to] || []);
  18. }
  19. getText(entry, to = 'default') {
  20. const arr = this.get(entry, to);
  21. if (!arr || !arr.length) return '';
  22. return arr.join('');
  23. }
  24. getSize(entry) {
  25. return this.cache.apply(`${entry}-size`, Object.keys(this.store[entry]).length);
  26. }
  27. register(entry, value, to = 'default') {
  28. if (!entry) throw new TypeError('entry is required');
  29. if (typeof value === 'function') value = value();
  30. const entryMap = this.store[entry] || this.store.head_end;
  31. const valueSet = entryMap[to] || new Set();
  32. valueSet.add(value);
  33. entryMap[to] = valueSet;
  34. }
  35. _getPageType(pageLocals) {
  36. let currentType = 'default';
  37. if (pageLocals.__index) currentType = 'home';
  38. if (pageLocals.__post) currentType = 'post';
  39. if (pageLocals.__page) currentType = 'page';
  40. if (pageLocals.archive) currentType = 'archive';
  41. if (pageLocals.category) currentType = 'category';
  42. if (pageLocals.tag) currentType = 'tag';
  43. if (pageLocals.layout) currentType = pageLocals.layout;
  44. return currentType;
  45. }
  46. _injector(input, pattern, flag, isBegin = true, currentType) {
  47. if (input.includes(`hexo injector ${flag}`)) return input;
  48. const code = this.cache.apply(`${flag}-${currentType}-code`, () => {
  49. const content = currentType === 'default' ? this.getText(flag, 'default') : this.getText(flag, currentType) + this.getText(flag, 'default');
  50. if (!content.length) return '';
  51. return '<!-- hexo injector ' + flag + ' start -->' + content + '<!-- hexo injector ' + flag + ' end -->';
  52. });
  53. // avoid unnecessary replace() for better performance
  54. if (!code.length) return input;
  55. return input.replace(pattern, str => { return isBegin ? str + code : code + str; });
  56. }
  57. exec(data, locals = { page: {} }) {
  58. const { page } = locals;
  59. const currentType = this._getPageType(page);
  60. if (this.getSize('head_begin') !== 0) {
  61. // Inject head_begin
  62. data = this._injector(data, /<head.*?>/, 'head_begin', true, currentType);
  63. }
  64. if (this.getSize('head_end') !== 0) {
  65. // Inject head_end
  66. data = this._injector(data, '</head>', 'head_end', false, currentType);
  67. }
  68. if (this.getSize('body_begin') !== 0) {
  69. // Inject body_begin
  70. data = this._injector(data, /<body.*?>/, 'body_begin', true, currentType);
  71. }
  72. if (this.getSize('body_end') !== 0) {
  73. // Inject body_end
  74. data = this._injector(data, '</body>', 'body_end', false, currentType);
  75. }
  76. return data;
  77. }
  78. }
  79. module.exports = Injector;