asset.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. 'use strict';
  2. const { timezone, toDate, isExcludedFile, isMatch } = require('./common');
  3. const Promise = require('bluebird');
  4. const { parse: yfm } = require('hexo-front-matter');
  5. const { extname, relative } = require('path');
  6. const { Pattern } = require('hexo-util');
  7. module.exports = ctx => {
  8. function processPage(file) {
  9. const Page = ctx.model('Page');
  10. const { path } = file;
  11. const doc = Page.findOne({source: path});
  12. const { config } = ctx;
  13. const { timezone: timezoneCfg } = config;
  14. // Deprecated: use_date_for_updated will be removed in future
  15. const updated_option = config.use_date_for_updated === true ? 'date' : config.updated_option;
  16. if (file.type === 'skip' && doc) {
  17. return;
  18. }
  19. if (file.type === 'delete') {
  20. if (doc) {
  21. return doc.remove();
  22. }
  23. return;
  24. }
  25. return Promise.all([
  26. file.stat(),
  27. file.read()
  28. ]).spread((stats, content) => {
  29. const data = yfm(content);
  30. const output = ctx.render.getOutput(path);
  31. data.source = path;
  32. data.raw = content;
  33. data.date = toDate(data.date);
  34. if (data.date) {
  35. if (timezoneCfg) data.date = timezone(data.date, timezoneCfg);
  36. } else {
  37. data.date = stats.ctime;
  38. }
  39. data.updated = toDate(data.updated);
  40. if (data.updated) {
  41. if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg);
  42. } else if (updated_option === 'date') {
  43. data.updated = data.date;
  44. } else if (updated_option === 'empty') {
  45. delete data.updated;
  46. } else {
  47. data.updated = stats.mtime;
  48. }
  49. if (data.permalink) {
  50. data.path = data.permalink;
  51. delete data.permalink;
  52. if (data.path.endsWith('/')) {
  53. data.path += 'index';
  54. }
  55. if (!extname(data.path)) {
  56. data.path += `.${output}`;
  57. }
  58. } else {
  59. data.path = `${path.substring(0, path.length - extname(path).length)}.${output}`;
  60. }
  61. if (!data.layout && output !== 'html' && output !== 'htm') {
  62. data.layout = false;
  63. }
  64. // FIXME: Data may be inserted when reading files. Load it again to prevent
  65. // race condition. We have to solve this in warehouse.
  66. const doc = Page.findOne({source: path});
  67. if (doc) {
  68. return doc.replace(data);
  69. }
  70. return Page.insert(data);
  71. });
  72. }
  73. function processAsset(file) {
  74. const id = relative(ctx.base_dir, file.source).replace(/\\/g, '/');
  75. const Asset = ctx.model('Asset');
  76. const doc = Asset.findById(id);
  77. if (file.type === 'delete') {
  78. if (doc) {
  79. return doc.remove();
  80. }
  81. return;
  82. }
  83. return Asset.save({
  84. _id: id,
  85. path: file.path,
  86. modified: file.type !== 'skip',
  87. renderable: file.params.renderable
  88. });
  89. }
  90. return {
  91. pattern: new Pattern(path => {
  92. if (isExcludedFile(path, ctx.config)) return;
  93. return {
  94. renderable: ctx.render.isRenderable(path) && !isMatch(path, ctx.config.skip_render)
  95. };
  96. }),
  97. process: function assetProcessor(file) {
  98. if (file.params.renderable) {
  99. return processPage(file);
  100. }
  101. return processAsset(file);
  102. }
  103. };
  104. };