UNPKG

hexo

Version:

A fast, simple & powerful blog framework, powered by Node.js.

144 lines (118 loc) 3.6 kB
var async = require('async'), swig = require('swig'), _ = require('lodash'), isReady = false; var rEscapeContent = /<escape( indent=['"](\d+)['"])?>([\s\S]+?)<\/escape>/g, rLineBreak = /(\n(\t+)){2,}/g, rUnescape = /<notextile>(\d+)<\/notextile>/g; swig.setDefaults({autoescape: false}); /** * Renders post contents. * * Rendering flow: * * - Compiles with Swig * - Runs pre-filter * - Compiles with Markdown (or other render engines, depends on the extension name of source files) * - Runs post-filter * * @method render * @param {String} source The path of source file * @param {Object} data * @param {Function} callback * @for post * @static */ module.exports = function(source, data, callback){ var extend = hexo.extend, filter = extend.filter.list(), render = hexo.render.render; // Loads tag plugins if (!isReady){ extend.tag.list().forEach(function(tag){ swig.setTag(tag.name, tag.parse, tag.compile, tag.ends, true); }); isReady = true; } // Replaces <escape>content</escape> in raw content with `<notextile>cache number</notextile>`, // and adds indent before the content to avoid markdown render error. var escapeContent = function(){ var indent = arguments[2], str = arguments[3], out = '<notextile>' + cache.length + '</notextile>\n'; cache.push(str); // Adds indents after the content if (indent){ for (var i = 0; i < indent; i++){ out += '\t'; } } return out; }; var cache = []; async.series([ // Renders content with Swig function(next){ try { data.content = swig.render(data.content, { locals: data, filename: source }); } catch (err){ return callback(err); } // Replaces contents in `<notextile>` tag and saves them in cache data.content = data.content.replace(rEscapeContent, escapeContent); next(); }, function(next){ // Pre filters async.eachSeries(filter.pre, function(filter, next){ filter(data, function(err, result){ if (err) return callback(err); if (result){ // Replaces contents in `<escape>` tag and saves them in cache result.content = result.content.replace(rEscapeContent, escapeContent); data = result; } next(); }); }, next); }, function(next){ // Deletes continous line breaks data.content = data.content.replace(rLineBreak, function(){ var tabs = arguments[2], out = '\n'; for (var i = 0, len = tabs.length; i < len; i++){ out += '\t'; } return out; }); var options = _.extend({}, hexo.config.markdown, data.markdown); if (!hexo.config.highlight.enable){ options.highlight = null; } // Renders with Markdown or other render engines. render({text: data.content, path: source, engine: data.engine}, options, function(err, result){ if (err) return callback(err); // Replaces cache data with real contents. data.content = result.replace(rUnescape, function(match, number){ return cache[number]; }); // Post filters async.eachSeries(filter.post, function(filter, next){ filter(data, function(err, result){ if (err) return callback(err); if (result){ data = result; } next(); }); }, next); }); } ], function(err){ callback(err, data); }); };